mirror of
https://github.com/breezy-weather/breezy-weather.git
synced 2025-10-18 23:43:40 +00:00
Migrate percent to unit module
This commit is contained in:
parent
8ab3a158cb
commit
9e4b22e714
92 changed files with 1680 additions and 1090 deletions
|
@ -107,6 +107,7 @@ import org.breezyweather.unit.precipitation.Precipitation
|
|||
import org.breezyweather.unit.precipitation.PrecipitationUnit
|
||||
import org.breezyweather.unit.pressure.Pressure
|
||||
import org.breezyweather.unit.pressure.PressureUnit
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.speed.Speed
|
||||
import org.breezyweather.unit.speed.SpeedUnit
|
||||
import org.breezyweather.unit.temperature.Temperature
|
||||
|
@ -480,10 +481,7 @@ class WeatherContentProvider : ContentProvider() {
|
|||
relativeHumidity = getPercentUnit(cur.relativeHumidity),
|
||||
dewPoint = getTemperatureUnit(cur.dewPoint, temperatureUnit),
|
||||
pressure = getPressureUnit(cur.pressure, pressureUnit),
|
||||
cloudCover = getPercentUnit(
|
||||
cur.cloudCover?.toDouble(),
|
||||
getCloudCoverDescription(context!!, cur.cloudCover)
|
||||
),
|
||||
cloudCover = getPercentUnit(cur.cloudCover, cur.cloudCover?.getCloudCoverDescription(context!!)),
|
||||
visibility = getDistanceUnit(cur.visibility, distanceUnit),
|
||||
ceiling = getDistanceUnit(cur.ceiling, distanceUnit)
|
||||
)
|
||||
|
@ -562,16 +560,16 @@ class WeatherContentProvider : ContentProvider() {
|
|||
),
|
||||
cloudCover = BreezyDailyUnit(
|
||||
avg = getPercentUnit(
|
||||
day.cloudCover?.average?.toDouble(),
|
||||
getCloudCoverDescription(context!!, day.cloudCover?.average)
|
||||
day.cloudCover?.average,
|
||||
day.cloudCover?.average?.getCloudCoverDescription(context!!)
|
||||
),
|
||||
max = getPercentUnit(
|
||||
day.cloudCover?.max?.toDouble(),
|
||||
getCloudCoverDescription(context!!, day.cloudCover?.max)
|
||||
day.cloudCover?.max,
|
||||
day.cloudCover?.max?.getCloudCoverDescription(context!!)
|
||||
),
|
||||
min = getPercentUnit(
|
||||
day.cloudCover?.min?.toDouble(),
|
||||
getCloudCoverDescription(context!!, day.cloudCover?.min)
|
||||
day.cloudCover?.min,
|
||||
day.cloudCover?.min?.getCloudCoverDescription(context!!)
|
||||
),
|
||||
summary = null
|
||||
),
|
||||
|
@ -609,10 +607,7 @@ class WeatherContentProvider : ContentProvider() {
|
|||
relativeHumidity = getPercentUnit(hour.relativeHumidity),
|
||||
dewPoint = getTemperatureUnit(hour.dewPoint, temperatureUnit),
|
||||
pressure = getPressureUnit(hour.pressure, pressureUnit),
|
||||
cloudCover = getPercentUnit(
|
||||
hour.cloudCover?.toDouble(),
|
||||
getCloudCoverDescription(context!!, hour.cloudCover)
|
||||
),
|
||||
cloudCover = getPercentUnit(hour.cloudCover, hour.cloudCover?.getCloudCoverDescription(context!!)),
|
||||
visibility = getDistanceUnit(hour.visibility, distanceUnit)
|
||||
)
|
||||
}
|
||||
|
@ -870,12 +865,12 @@ class WeatherContentProvider : ContentProvider() {
|
|||
}
|
||||
|
||||
private fun getPercentUnit(
|
||||
percent: Double?,
|
||||
percent: Ratio?,
|
||||
description: String? = null,
|
||||
): BreezyUnit? {
|
||||
return percent?.let {
|
||||
BreezyUnit(
|
||||
value = it.roundDecimals(1),
|
||||
value = it.inPercent.roundDecimals(1),
|
||||
unit = "percent",
|
||||
description = description
|
||||
)
|
||||
|
|
|
@ -38,6 +38,7 @@ import breezyweather.data.PollenConcentrationColumnAdapter
|
|||
import breezyweather.data.PollutantConcentrationColumnAdapter
|
||||
import breezyweather.data.PrecipitationColumnAdapter
|
||||
import breezyweather.data.PressureColumnAdapter
|
||||
import breezyweather.data.RatioColumnAdapter
|
||||
import breezyweather.data.SpeedColumnAdapter
|
||||
import breezyweather.data.TemperatureColumnAdapter
|
||||
import breezyweather.data.TimeZoneColumnAdapter
|
||||
|
@ -110,9 +111,11 @@ class DbModule {
|
|||
no2Adapter = PollutantConcentrationColumnAdapter,
|
||||
o3Adapter = PollutantConcentrationColumnAdapter,
|
||||
coAdapter = PollutantConcentrationColumnAdapter,
|
||||
relative_humidityAdapter = RatioColumnAdapter,
|
||||
dew_pointAdapter = TemperatureColumnAdapter,
|
||||
pressureAdapter = PressureColumnAdapter,
|
||||
visibilityAdapter = DistanceColumnAdapter,
|
||||
cloud_coverAdapter = RatioColumnAdapter,
|
||||
ceilingAdapter = DistanceColumnAdapter
|
||||
),
|
||||
dailysAdapter = Dailys.Adapter(
|
||||
|
@ -127,6 +130,11 @@ class DbModule {
|
|||
daytime_rain_precipitationAdapter = PrecipitationColumnAdapter,
|
||||
daytime_snow_precipitationAdapter = PrecipitationColumnAdapter,
|
||||
daytime_ice_precipitationAdapter = PrecipitationColumnAdapter,
|
||||
daytime_total_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
daytime_thunderstorm_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
daytime_rain_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
daytime_snow_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
daytime_ice_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
daytime_total_precipitation_durationAdapter = DurationColumnAdapter,
|
||||
daytime_thunderstorm_precipitation_durationAdapter = DurationColumnAdapter,
|
||||
daytime_rain_precipitation_durationAdapter = DurationColumnAdapter,
|
||||
|
@ -145,6 +153,11 @@ class DbModule {
|
|||
nighttime_rain_precipitationAdapter = PrecipitationColumnAdapter,
|
||||
nighttime_snow_precipitationAdapter = PrecipitationColumnAdapter,
|
||||
nighttime_ice_precipitationAdapter = PrecipitationColumnAdapter,
|
||||
nighttime_total_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
nighttime_thunderstorm_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
nighttime_rain_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
nighttime_snow_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
nighttime_ice_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
nighttime_total_precipitation_durationAdapter = DurationColumnAdapter,
|
||||
nighttime_thunderstorm_precipitation_durationAdapter = DurationColumnAdapter,
|
||||
nighttime_rain_precipitation_durationAdapter = DurationColumnAdapter,
|
||||
|
@ -182,12 +195,18 @@ class DbModule {
|
|||
urticaceaeAdapter = PollenConcentrationColumnAdapter,
|
||||
willowAdapter = PollenConcentrationColumnAdapter,
|
||||
sunshine_durationAdapter = DurationColumnAdapter,
|
||||
relative_humidity_averageAdapter = RatioColumnAdapter,
|
||||
relative_humidity_minAdapter = RatioColumnAdapter,
|
||||
relative_humidity_maxAdapter = RatioColumnAdapter,
|
||||
dewpoint_averageAdapter = TemperatureColumnAdapter,
|
||||
dewpoint_minAdapter = TemperatureColumnAdapter,
|
||||
dewpoint_maxAdapter = TemperatureColumnAdapter,
|
||||
pressure_averageAdapter = PressureColumnAdapter,
|
||||
pressure_maxAdapter = PressureColumnAdapter,
|
||||
pressure_minAdapter = PressureColumnAdapter,
|
||||
cloud_cover_averageAdapter = RatioColumnAdapter,
|
||||
cloud_cover_minAdapter = RatioColumnAdapter,
|
||||
cloud_cover_maxAdapter = RatioColumnAdapter,
|
||||
visibility_averageAdapter = DistanceColumnAdapter,
|
||||
visibility_maxAdapter = DistanceColumnAdapter,
|
||||
visibility_minAdapter = DistanceColumnAdapter
|
||||
|
@ -204,6 +223,11 @@ class DbModule {
|
|||
rain_precipitationAdapter = PrecipitationColumnAdapter,
|
||||
snow_precipitationAdapter = PrecipitationColumnAdapter,
|
||||
ice_precipitationAdapter = PrecipitationColumnAdapter,
|
||||
total_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
thunderstorm_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
rain_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
snow_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
ice_precipitation_probabilityAdapter = RatioColumnAdapter,
|
||||
wind_speedAdapter = SpeedColumnAdapter,
|
||||
wind_gustsAdapter = SpeedColumnAdapter,
|
||||
pm25Adapter = PollutantConcentrationColumnAdapter,
|
||||
|
@ -212,8 +236,10 @@ class DbModule {
|
|||
no2Adapter = PollutantConcentrationColumnAdapter,
|
||||
o3Adapter = PollutantConcentrationColumnAdapter,
|
||||
coAdapter = PollutantConcentrationColumnAdapter,
|
||||
relative_humidityAdapter = RatioColumnAdapter,
|
||||
dew_pointAdapter = TemperatureColumnAdapter,
|
||||
pressureAdapter = PressureColumnAdapter,
|
||||
cloud_coverAdapter = RatioColumnAdapter,
|
||||
visibilityAdapter = DistanceColumnAdapter
|
||||
),
|
||||
minutelysAdapter = Minutelys.Adapter(
|
||||
|
|
|
@ -36,9 +36,11 @@ import android.view.animation.DecelerateInterpolator
|
|||
import android.view.animation.Interpolator
|
||||
import android.view.animation.OvershootInterpolator
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorRes
|
||||
import androidx.annotation.Px
|
||||
import androidx.annotation.Size
|
||||
import androidx.annotation.StyleRes
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.graphics.createBitmap
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import com.google.android.material.resources.TextAppearance
|
||||
|
@ -205,6 +207,10 @@ fun Context.getThemeColor(
|
|||
return typedValue.data
|
||||
}
|
||||
|
||||
fun Context.getColorResource(@ColorRes id: Int): androidx.compose.ui.graphics.Color {
|
||||
return androidx.compose.ui.graphics.Color(ResourcesCompat.getColor(resources, id, theme))
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun Window.setSystemBarStyle(
|
||||
lightStatus: Boolean,
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.breezyweather.common.extensions
|
|||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.breezyweather.R
|
||||
import org.breezyweather.domain.settings.SettingsManager
|
||||
import org.breezyweather.unit.distance.Distance
|
||||
|
@ -30,9 +31,10 @@ import org.breezyweather.unit.pollutant.PollutantConcentrationUnit
|
|||
import org.breezyweather.unit.precipitation.Precipitation
|
||||
import org.breezyweather.unit.precipitation.PrecipitationUnit
|
||||
import org.breezyweather.unit.pressure.Pressure
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.ratio.RatioUnit
|
||||
import org.breezyweather.unit.speed.Speed
|
||||
import org.breezyweather.unit.temperature.Temperature
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.DurationUnit
|
||||
|
||||
|
@ -357,6 +359,41 @@ fun Duration.formatTime(
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient format function with parameters filled for our app
|
||||
*/
|
||||
fun Ratio.formatPercent(
|
||||
context: Context,
|
||||
valueWidth: UnitWidth = UnitWidth.SHORT,
|
||||
): String {
|
||||
val settings = SettingsManager.getInstance(context)
|
||||
return format(
|
||||
context = context,
|
||||
unit = RatioUnit.PERCENT,
|
||||
valueWidth = valueWidth,
|
||||
locale = context.currentLocale,
|
||||
useNumberFormatter = settings.useNumberFormatter,
|
||||
useMeasureFormat = settings.useMeasureFormat
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient format function with parameters filled for our app
|
||||
*/
|
||||
fun Ratio.formatValue(
|
||||
context: Context,
|
||||
width: UnitWidth = UnitWidth.SHORT,
|
||||
): String {
|
||||
val settings = SettingsManager.getInstance(context)
|
||||
return formatValue(
|
||||
unit = RatioUnit.PERCENT,
|
||||
width = width,
|
||||
locale = context.currentLocale,
|
||||
useNumberFormatter = settings.useNumberFormatter,
|
||||
useMeasureFormat = settings.useMeasureFormat
|
||||
)
|
||||
}
|
||||
|
||||
// We don't need any cloud cover unit, it's just a percent, but we need some helpers
|
||||
|
||||
/**
|
||||
|
@ -368,35 +405,25 @@ const val CLOUD_COVER_SCT = 67.5 // 5 okta
|
|||
const val CLOUD_COVER_BKN = 87.5 // 7 okta
|
||||
const val CLOUD_COVER_OVC = 100.0 // 8 okta
|
||||
|
||||
val cloudCoverScaleThresholds = listOf(
|
||||
0.0,
|
||||
CLOUD_COVER_SKC,
|
||||
CLOUD_COVER_FEW,
|
||||
CLOUD_COVER_SCT,
|
||||
CLOUD_COVER_BKN,
|
||||
CLOUD_COVER_OVC
|
||||
)
|
||||
fun Ratio.getCloudCoverColor(context: Context): Int {
|
||||
return when (inPercent) {
|
||||
in 0.0..<CLOUD_COVER_FEW -> ContextCompat.getColor(context, R.color.colorLevel_1)
|
||||
in CLOUD_COVER_FEW..CLOUD_COVER_SCT -> ContextCompat.getColor(context, R.color.colorLevel_2)
|
||||
in CLOUD_COVER_SCT..100.0 -> ContextCompat.getColor(context, R.color.colorLevel_3)
|
||||
else -> Color.TRANSPARENT
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param cloudCover in % (0-100)
|
||||
*/
|
||||
fun getCloudCoverDescription(context: Context, cloudCover: Int?): String? {
|
||||
if (cloudCover == null) return null
|
||||
return when (cloudCover) {
|
||||
in 0..<CLOUD_COVER_SKC.roundToInt() -> context.getString(R.string.common_weather_text_clear_sky)
|
||||
in CLOUD_COVER_SKC.roundToInt()..<CLOUD_COVER_FEW.roundToInt() -> {
|
||||
context.getString(R.string.common_weather_text_mostly_clear)
|
||||
}
|
||||
in CLOUD_COVER_FEW.roundToInt()..<CLOUD_COVER_SCT.roundToInt() -> {
|
||||
context.getString(R.string.common_weather_text_partly_cloudy)
|
||||
}
|
||||
in CLOUD_COVER_SCT.roundToInt()..<CLOUD_COVER_BKN.roundToInt() -> {
|
||||
context.getString(R.string.common_weather_text_mostly_cloudy)
|
||||
}
|
||||
in CLOUD_COVER_BKN.roundToInt()..CLOUD_COVER_OVC.roundToInt() -> {
|
||||
context.getString(R.string.common_weather_text_cloudy)
|
||||
}
|
||||
fun Ratio.getCloudCoverDescription(context: Context): String? {
|
||||
return when (inPercent) {
|
||||
in 0.0..<CLOUD_COVER_SKC -> context.getString(R.string.common_weather_text_clear_sky)
|
||||
in CLOUD_COVER_SKC..<CLOUD_COVER_FEW -> context.getString(R.string.common_weather_text_mostly_clear)
|
||||
in CLOUD_COVER_FEW..<CLOUD_COVER_SCT -> context.getString(R.string.common_weather_text_partly_cloudy)
|
||||
in CLOUD_COVER_SCT..<CLOUD_COVER_BKN -> context.getString(R.string.common_weather_text_mostly_cloudy)
|
||||
in CLOUD_COVER_BKN..CLOUD_COVER_OVC -> context.getString(R.string.common_weather_text_cloudy)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,19 +71,17 @@ enum class DetailScreen(
|
|||
(it.uV?.index ?: 0.0) > 0.0
|
||||
} == true
|
||||
TAG_HUMIDITY -> location.weather?.dailyForecast?.any {
|
||||
(it.relativeHumidity?.min ?: 0.0) > 0.0 || (it.relativeHumidity?.max ?: 0.0) > 0.0
|
||||
it.relativeHumidity?.min != null || it.relativeHumidity?.max != null
|
||||
} == true ||
|
||||
location.weather?.hourlyForecast?.any {
|
||||
(it.relativeHumidity ?: 0.0) > 0.0 || (it.dewPoint ?: 0.0) != 0.0
|
||||
it.relativeHumidity != null || it.dewPoint != null
|
||||
} == true
|
||||
TAG_PRESSURE -> location.weather?.dailyForecast?.any { it.pressure?.average != null } == true ||
|
||||
location.weather?.hourlyForecast?.any { it.pressure != null } == true
|
||||
TAG_CLOUD_COVER -> location.weather?.dailyForecast?.any {
|
||||
(it.cloudCover?.min ?: 0) > 0 || (it.cloudCover?.max ?: 0) > 0
|
||||
it.cloudCover?.min != null || it.cloudCover?.max != null
|
||||
} == true ||
|
||||
location.weather?.hourlyForecast?.any {
|
||||
(it.cloudCover ?: 0) > 0
|
||||
} == true
|
||||
location.weather?.hourlyForecast?.any { it.cloudCover != null } == true
|
||||
TAG_VISIBILITY -> location.weather?.dailyForecast?.any {
|
||||
it.visibility?.min != null || it.visibility?.max != null
|
||||
} == true ||
|
||||
|
|
|
@ -18,12 +18,6 @@ package org.breezyweather.common.utils
|
|||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.icu.number.LocalizedNumberFormatter
|
||||
import android.icu.number.NumberFormatter
|
||||
import android.icu.number.Precision
|
||||
import android.icu.text.NumberFormat
|
||||
import android.icu.util.MeasureUnit
|
||||
import android.os.Build
|
||||
import android.text.SpannableString
|
||||
import android.text.Spanned
|
||||
import android.text.style.RelativeSizeSpan
|
||||
|
@ -116,62 +110,6 @@ object UnitUtils {
|
|||
)
|
||||
}
|
||||
|
||||
@Deprecated("Use Number.format() extension")
|
||||
fun formatNumber(
|
||||
context: Context,
|
||||
valueWithoutUnit: Number,
|
||||
precision: Int,
|
||||
showSign: Boolean = false,
|
||||
): String {
|
||||
return valueWithoutUnit.format(
|
||||
decimals = precision,
|
||||
locale = context.currentLocale,
|
||||
showSign = showSign,
|
||||
useNumberFormatter = SettingsManager.Companion.getInstance(context).useNumberFormatter,
|
||||
useMeasureFormat = SettingsManager.Companion.getInstance(context).useMeasureFormat
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses LocalizedNumberFormatter on Android SDK >= 30 (which is the recommended way)
|
||||
* Uses NumberFormat on Android SDK >= 24
|
||||
* Uses java.text.NumberFormat on Android SDK < 24
|
||||
*
|
||||
* @param context
|
||||
* @param value between 0.0 and 100.0
|
||||
* @param precision
|
||||
*/
|
||||
fun formatPercent(
|
||||
context: Context,
|
||||
value: Double,
|
||||
precision: Int = 0,
|
||||
): String {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
|
||||
SettingsManager.Companion.getInstance(context).useNumberFormatter
|
||||
) {
|
||||
(NumberFormatter.withLocale(context.currentLocale) as LocalizedNumberFormatter)
|
||||
.precision(if (precision == 0) Precision.integer() else Precision.maxFraction(precision))
|
||||
.unit(MeasureUnit.PERCENT)
|
||||
.format(value)
|
||||
.toString()
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
NumberFormat.getPercentInstance(context.currentLocale)
|
||||
.apply { maximumFractionDigits = precision }
|
||||
.format(if (value > 0) value.div(100.0) else 0)
|
||||
} else {
|
||||
java.text.NumberFormat.getPercentInstance(context.currentLocale)
|
||||
.apply { maximumFractionDigits = precision }
|
||||
.format(if (value > 0) value.div(100.0) else 0)
|
||||
}
|
||||
}
|
||||
|
||||
fun formatPercent(
|
||||
context: Context,
|
||||
value: Int,
|
||||
): String {
|
||||
return formatPercent(context, value.toDouble(), 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Units will stay at the same size if it somehow fails to parse
|
||||
*/
|
||||
|
@ -263,14 +201,6 @@ object UnitUtils {
|
|||
}
|
||||
}
|
||||
|
||||
fun validatePercent(percent: Double?): Double? {
|
||||
return percent?.let { if (it in 0.0..100.0) it else null }
|
||||
}
|
||||
|
||||
fun validatePercent(percent: Int?): Int? {
|
||||
return percent?.let { if (it in 0..100) it else null }
|
||||
}
|
||||
|
||||
private val ARABIC_DIGITS = charArrayOf('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')
|
||||
private val ARABIC_INDIC_DIGITS = charArrayOf('٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩')
|
||||
private val BENGALI_DIGITS = charArrayOf('০', '১', '২', '৩', '৪', '৫', '৬', '৭', '৮', '৯')
|
||||
|
|
|
@ -19,19 +19,20 @@ package org.breezyweather.domain.weather.model
|
|||
import android.content.Context
|
||||
import breezyweather.domain.weather.model.DailyCloudCover
|
||||
import org.breezyweather.R
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.formatValue
|
||||
import org.breezyweather.common.extensions.getCloudCoverDescription
|
||||
import org.breezyweather.common.utils.UnitUtils
|
||||
|
||||
fun DailyCloudCover.getRangeSummary(context: Context): String? {
|
||||
return if (min == null || max == null) {
|
||||
null
|
||||
} else if (min == max) {
|
||||
UnitUtils.formatPercent(context, max!!)
|
||||
max!!.formatPercent(context)
|
||||
} else {
|
||||
context.getString(
|
||||
R.string.cloud_cover_from_to_number,
|
||||
UnitUtils.formatInt(context, min!!),
|
||||
UnitUtils.formatPercent(context, max!!)
|
||||
min!!.formatValue(context),
|
||||
max!!.formatPercent(context)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +41,8 @@ fun DailyCloudCover.getRangeDescriptionSummary(context: Context): String? {
|
|||
return if (min == null || max == null) {
|
||||
null
|
||||
} else {
|
||||
val minDescription = getCloudCoverDescription(context, min)
|
||||
val maxDescription = getCloudCoverDescription(context, max)
|
||||
val minDescription = min!!.getCloudCoverDescription(context)
|
||||
val maxDescription = max!!.getCloudCoverDescription(context)
|
||||
|
||||
if (minDescription == maxDescription) {
|
||||
maxDescription
|
||||
|
|
|
@ -19,18 +19,19 @@ package org.breezyweather.domain.weather.model
|
|||
import android.content.Context
|
||||
import breezyweather.domain.weather.model.DailyRelativeHumidity
|
||||
import org.breezyweather.R
|
||||
import org.breezyweather.common.utils.UnitUtils
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.formatValue
|
||||
|
||||
fun DailyRelativeHumidity.getRangeSummary(context: Context): String? {
|
||||
return if (min == null || max == null) {
|
||||
null
|
||||
} else if (min == max) {
|
||||
UnitUtils.formatPercent(context, max!!)
|
||||
max!!.formatPercent(context)
|
||||
} else {
|
||||
context.getString(
|
||||
R.string.humidity_from_to_number,
|
||||
UnitUtils.formatDouble(context, min!!),
|
||||
UnitUtils.formatPercent(context, max!!)
|
||||
min!!.formatValue(context),
|
||||
max!!.formatPercent(context)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* 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 org.breezyweather.domain.weather.model
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.core.content.ContextCompat
|
||||
import breezyweather.domain.weather.model.Hourly
|
||||
import org.breezyweather.R
|
||||
|
||||
@ColorInt
|
||||
fun Hourly.getCloudCoverColor(context: Context): Int {
|
||||
if (cloudCover == null) return Color.TRANSPARENT
|
||||
return when (cloudCover!!.toDouble()) {
|
||||
in 0.0..CLOUD_COVER_CLEAR -> ContextCompat.getColor(context, R.color.colorLevel_1)
|
||||
in CLOUD_COVER_CLEAR..CLOUD_COVER_PARTLY -> ContextCompat.getColor(context, R.color.colorLevel_2)
|
||||
in CLOUD_COVER_PARTLY..100.0 -> ContextCompat.getColor(context, R.color.colorLevel_3)
|
||||
else -> Color.TRANSPARENT
|
||||
}
|
||||
}
|
||||
|
||||
const val CLOUD_COVER_CLEAR = 37.5
|
||||
const val CLOUD_COVER_PARTLY = 75.0
|
|
@ -59,6 +59,7 @@ import com.google.android.material.textfield.TextInputLayout
|
|||
import org.breezyweather.R
|
||||
import org.breezyweather.common.activities.BreezyActivity
|
||||
import org.breezyweather.common.extensions.doOnApplyWindowInsets
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.getTabletListAdaptiveWidth
|
||||
import org.breezyweather.common.extensions.hasPermission
|
||||
import org.breezyweather.common.extensions.launchUI
|
||||
|
@ -68,6 +69,8 @@ import org.breezyweather.common.snackbar.SnackbarManager
|
|||
import org.breezyweather.common.utils.UnitUtils
|
||||
import org.breezyweather.common.utils.helpers.SnackbarHelper
|
||||
import org.breezyweather.domain.settings.ConfigStore
|
||||
import org.breezyweather.unit.formatting.UnitWidth
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
@ -355,7 +358,7 @@ abstract class AbstractWidgetConfigActivity : BreezyActivity() {
|
|||
valueTo = 100f
|
||||
value = ((cardAlpha.toDouble() / 10.0).roundToInt() * 10.0).toFloat()
|
||||
setLabelFormatter { value: Float ->
|
||||
UnitUtils.formatPercent(context, value.toDouble())
|
||||
value.toDouble().percent.formatPercent(context, UnitWidth.NARROW)
|
||||
}
|
||||
addOnChangeListener { _, value, _ ->
|
||||
if (cardAlpha != value.roundToInt()) {
|
||||
|
@ -418,7 +421,7 @@ abstract class AbstractWidgetConfigActivity : BreezyActivity() {
|
|||
}
|
||||
}
|
||||
setLabelFormatter { value: Float ->
|
||||
UnitUtils.formatPercent(context, value.toDouble())
|
||||
value.toDouble().percent.formatPercent(context, UnitWidth.NARROW)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -480,6 +483,14 @@ abstract class AbstractWidgetConfigActivity : BreezyActivity() {
|
|||
}
|
||||
mBottomSheetScrollView = findViewById(R.id.activity_widget_config_custom_scrollView)
|
||||
mSubtitleInputLayout = findViewById(R.id.activity_widget_config_subtitle_inputLayout)
|
||||
mSubtitleInputLayout?.setEndIconOnClickListener {
|
||||
val message = getString(R.string.widget_custom_subtitle_explanation) + "\n\n" + subtitleCustomKeywords
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.widget_custom_subtitle_alert_box_title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.action_done, null)
|
||||
.show()
|
||||
}
|
||||
mSubtitleEditText = findViewById<TextInputEditText>(R.id.activity_widget_config_subtitle_inputter).apply {
|
||||
addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
|
||||
|
@ -509,15 +520,6 @@ abstract class AbstractWidgetConfigActivity : BreezyActivity() {
|
|||
mBottomSheetBehavior!!.peekHeight = mSubtitleInputLayout!!.measuredHeight
|
||||
setBottomSheetState(isCustomSubtitle)
|
||||
}
|
||||
val subtitleInputLayout = findViewById<TextInputLayout>(R.id.activity_widget_config_subtitle_inputLayout)
|
||||
subtitleInputLayout.setEndIconOnClickListener {
|
||||
val message = getString(R.string.widget_custom_subtitle_explanation) + "\n\n" + subtitleCustomKeywords
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.widget_custom_subtitle_alert_box_title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.action_done, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun updateWidgetView()
|
||||
|
|
|
@ -33,6 +33,7 @@ import breezyweather.domain.location.model.Location
|
|||
import breezyweather.domain.weather.model.Weather
|
||||
import org.breezyweather.R
|
||||
import org.breezyweather.common.extensions.formatMeasure
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.getFormattedDate
|
||||
import org.breezyweather.common.extensions.getFormattedMediumDayAndMonth
|
||||
import org.breezyweather.common.extensions.getFormattedMediumDayAndMonthInAdditionalCalendar
|
||||
|
@ -317,9 +318,8 @@ abstract class AbstractRemoteViewsPresenter {
|
|||
?: context.getString(R.string.null_data_text)
|
||||
).replace(
|
||||
"\$ch$",
|
||||
weather.current?.relativeHumidity?.let {
|
||||
UnitUtils.formatPercent(context, it)
|
||||
} ?: context.getString(R.string.null_data_text)
|
||||
weather.current?.relativeHumidity?.formatPercent(context, UnitWidth.NARROW)
|
||||
?: context.getString(R.string.null_data_text)
|
||||
).replace(
|
||||
"\$cps$",
|
||||
weather.current?.pressure?.formatMeasure(context)
|
||||
|
@ -466,14 +466,14 @@ abstract class AbstractRemoteViewsPresenter {
|
|||
) ?: context.getString(R.string.null_data_text)
|
||||
).replace(
|
||||
"$" + i + "dp$",
|
||||
weather.dailyForecastStartingToday.getOrNull(i)?.day?.precipitationProbability?.total?.let {
|
||||
UnitUtils.formatPercent(context, it)
|
||||
} ?: context.getString(R.string.null_data_text)
|
||||
weather.dailyForecastStartingToday.getOrNull(i)?.day?.precipitationProbability?.total
|
||||
?.formatPercent(context, UnitWidth.NARROW)
|
||||
?: context.getString(R.string.null_data_text)
|
||||
).replace(
|
||||
"$" + i + "np$",
|
||||
weather.dailyForecastStartingToday.getOrNull(i)?.night?.precipitationProbability?.total?.let {
|
||||
UnitUtils.formatPercent(context, it)
|
||||
} ?: context.getString(R.string.null_data_text)
|
||||
weather.dailyForecastStartingToday.getOrNull(i)?.night?.precipitationProbability?.total
|
||||
?.formatPercent(context, UnitWidth.NARROW)
|
||||
?: context.getString(R.string.null_data_text)
|
||||
).replace(
|
||||
"$" + i + "dwd$",
|
||||
weather.dailyForecastStartingToday.getOrNull(i)?.day?.wind?.getShortDescription(context)
|
||||
|
|
|
@ -29,6 +29,7 @@ import breezyweather.domain.weather.model.Weather
|
|||
import org.breezyweather.R
|
||||
import org.breezyweather.background.receiver.widget.WidgetClockDayDetailsProvider
|
||||
import org.breezyweather.common.extensions.formatMeasure
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.getFormattedMediumDayAndMonthInAdditionalCalendar
|
||||
import org.breezyweather.common.extensions.getShortWeekdayDayMonth
|
||||
import org.breezyweather.common.options.appearance.CalendarHelper
|
||||
|
@ -288,7 +289,7 @@ object ClockDayDetailsWidgetIMP : AbstractRemoteViewsPresenter() {
|
|||
weather.current?.relativeHumidity?.let {
|
||||
context.getString(R.string.humidity) +
|
||||
context.getString(R.string.colon_separator) +
|
||||
UnitUtils.formatPercent(context, it)
|
||||
it.formatPercent(context, UnitWidth.NARROW)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import breezyweather.domain.location.model.Location
|
|||
import org.breezyweather.R
|
||||
import org.breezyweather.background.receiver.widget.WidgetTrendDailyProvider
|
||||
import org.breezyweather.common.extensions.formatMeasure
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.getCalendarMonth
|
||||
import org.breezyweather.common.extensions.getFormattedShortDayAndMonth
|
||||
import org.breezyweather.common.extensions.getTabletListAdaptiveWidth
|
||||
|
@ -217,12 +218,10 @@ object DailyTrendWidgetIMP : AbstractRemoteViewsPresenter() {
|
|||
ResourceHelper.getWidgetNotificationIcon(provider, it, true, minimalIcon, lightTheme)
|
||||
)
|
||||
}
|
||||
val daytimePrecipitationProbability = daily.day?.precipitationProbability?.total?.toFloat()
|
||||
val nighttimePrecipitationProbability = daily.night?.precipitationProbability?.total?.toFloat()
|
||||
val p = max(
|
||||
daytimePrecipitationProbability ?: 0f,
|
||||
nighttimePrecipitationProbability ?: 0f
|
||||
)
|
||||
val daytimePrecipitationProbability = daily.day?.precipitationProbability?.total
|
||||
val nighttimePrecipitationProbability = daily.night?.precipitationProbability?.total
|
||||
val p = listOfNotNull(daytimePrecipitationProbability, nighttimePrecipitationProbability)
|
||||
.takeIf { it.isNotEmpty() }?.maxBy { it.value }
|
||||
widgetItemView.trendItemView.setData(
|
||||
buildTemperatureArrayForItem(daytimeTemperatures, i),
|
||||
buildTemperatureArrayForItem(nighttimeTemperatures, i),
|
||||
|
@ -238,12 +237,8 @@ object DailyTrendWidgetIMP : AbstractRemoteViewsPresenter() {
|
|||
),
|
||||
highestTemperature,
|
||||
lowestTemperature,
|
||||
if (p > 0) p else null,
|
||||
if (p > 0) {
|
||||
UnitUtils.formatPercent(context, p.toDouble())
|
||||
} else {
|
||||
null
|
||||
},
|
||||
p?.takeIf { it.value > 0 }?.inPercent?.toFloat(),
|
||||
p?.takeIf { it.value > 0 }?.formatPercent(context, UnitWidth.NARROW),
|
||||
100f,
|
||||
0f
|
||||
)
|
||||
|
|
|
@ -45,7 +45,6 @@ import org.breezyweather.common.extensions.CLOUD_COVER_FEW
|
|||
import org.breezyweather.common.extensions.ensurePositive
|
||||
import org.breezyweather.common.extensions.getIsoFormattedDate
|
||||
import org.breezyweather.common.extensions.toCalendarWithTimeZone
|
||||
import org.breezyweather.common.utils.UnitUtils
|
||||
import org.breezyweather.domain.weather.index.PollutantIndex
|
||||
import org.breezyweather.domain.weather.model.validate
|
||||
import org.breezyweather.ui.theme.weatherView.WeatherViewController
|
||||
|
@ -58,6 +57,10 @@ import org.breezyweather.unit.precipitation.Precipitation.Companion.micrometers
|
|||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.pascals
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.fraction
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.permille
|
||||
import org.breezyweather.unit.speed.Speed
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
|
@ -224,13 +227,13 @@ internal fun computeMissingHourlyData(
|
|||
ice = hourly.precipitation!!.ice?.toValidHourlyOrNull()
|
||||
)
|
||||
val precipitationProbability = hourly.precipitationProbability?.copy(
|
||||
total = UnitUtils.validatePercent(hourly.precipitationProbability!!.total),
|
||||
thunderstorm = UnitUtils.validatePercent(hourly.precipitationProbability!!.thunderstorm),
|
||||
rain = UnitUtils.validatePercent(hourly.precipitationProbability!!.rain),
|
||||
snow = UnitUtils.validatePercent(hourly.precipitationProbability!!.snow),
|
||||
ice = UnitUtils.validatePercent(hourly.precipitationProbability!!.ice)
|
||||
total = hourly.precipitationProbability!!.total?.toValidRangeOrNull(),
|
||||
thunderstorm = hourly.precipitationProbability!!.thunderstorm?.toValidRangeOrNull(),
|
||||
rain = hourly.precipitationProbability!!.rain?.toValidRangeOrNull(),
|
||||
snow = hourly.precipitationProbability!!.snow?.toValidRangeOrNull(),
|
||||
ice = hourly.precipitationProbability!!.ice?.toValidRangeOrNull()
|
||||
)
|
||||
val cloudCover = UnitUtils.validatePercent(hourly.cloudCover)
|
||||
val cloudCover = hourly.cloudCover?.toValidRangeOrNull()
|
||||
val visibility = hourly.visibility?.toValidOrNull()
|
||||
val weatherCode = hourly.weatherCode ?: getHalfDayWeatherCodeFromHourlyList(
|
||||
listOf(hourly.toHourly()),
|
||||
|
@ -240,7 +243,7 @@ internal fun computeMissingHourlyData(
|
|||
cloudCover,
|
||||
visibility
|
||||
)
|
||||
val relativeHumidity = UnitUtils.validatePercent(hourly.relativeHumidity)
|
||||
val relativeHumidity = hourly.relativeHumidity?.toValidRangeOrNull()
|
||||
?: computeRelativeHumidity(temp, hourly.dewPoint?.toValidOrNull())
|
||||
val dewPoint = hourly.dewPoint?.toValidOrNull()
|
||||
?: computeDewPoint(temp, relativeHumidity)
|
||||
|
@ -279,16 +282,16 @@ internal fun computeMissingHourlyData(
|
|||
private fun computeRelativeHumidity(
|
||||
temperature: Temperature?,
|
||||
dewPoint: Temperature?,
|
||||
): Double? {
|
||||
): Ratio? {
|
||||
if (temperature == null || dewPoint == null) return null
|
||||
|
||||
val b = if (temperature < 0.celsius) 17.966 else 17.368
|
||||
val c = if (temperature < 0.celsius) 227.15 else 238.88 // °C
|
||||
|
||||
return 100 * (
|
||||
return (
|
||||
exp((b * dewPoint.inCelsius).div(c + dewPoint.inCelsius)) /
|
||||
exp((b * temperature.inCelsius).div(c + temperature.inCelsius))
|
||||
)
|
||||
).fraction
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -297,18 +300,18 @@ private fun computeRelativeHumidity(
|
|||
* TODO: Unit test
|
||||
*
|
||||
* @param temperature
|
||||
* @param relativeHumidity in %
|
||||
* @param relativeHumidity
|
||||
*/
|
||||
private fun computeDewPoint(
|
||||
temperature: Temperature?,
|
||||
relativeHumidity: Double?,
|
||||
relativeHumidity: Ratio?,
|
||||
): Temperature? {
|
||||
if (temperature == null || relativeHumidity == null) return null
|
||||
|
||||
val b = if (temperature < 0.celsius) 17.966 else 17.368
|
||||
val c = if (temperature < 0.celsius) 227.15 else 238.88 // °C
|
||||
|
||||
val magnus = ln(relativeHumidity / 100) + (b * temperature.inCelsius) / (c + temperature.inCelsius)
|
||||
val magnus = ln(relativeHumidity.inFraction) + (b * temperature.inCelsius) / (c + temperature.inCelsius)
|
||||
return ((c * magnus) / (b - magnus)).celsius
|
||||
}
|
||||
|
||||
|
@ -319,16 +322,17 @@ private fun computeDewPoint(
|
|||
* TODO: Unit test
|
||||
*
|
||||
* @param temperature
|
||||
* @param relativeHumidity in %
|
||||
* @param relativeHumidity
|
||||
* @param windSpeed
|
||||
*/
|
||||
internal fun computeApparentTemperature(
|
||||
temperature: Temperature?,
|
||||
relativeHumidity: Double?,
|
||||
relativeHumidity: Ratio?,
|
||||
windSpeed: Speed?,
|
||||
): Temperature? {
|
||||
if (temperature == null || relativeHumidity == null || windSpeed == null) return null
|
||||
|
||||
val e = relativeHumidity.div(100) * 6.105 * exp(17.27 * temperature.inCelsius / (237.7 + temperature.inCelsius))
|
||||
val e = relativeHumidity.inFraction * 6.105 * exp(17.27 * temperature.inCelsius / (237.7 + temperature.inCelsius))
|
||||
return (temperature.inCelsius + 0.33 * e - 0.7 * windSpeed.inMetersPerSecond - 4.0).celsius
|
||||
}
|
||||
|
||||
|
@ -878,11 +882,11 @@ private fun completeHalfDayFromHourlyList(
|
|||
}
|
||||
|
||||
val initialPrecipitationProbability = newHalfDay.precipitationProbability?.copy(
|
||||
total = UnitUtils.validatePercent(newHalfDay.precipitationProbability!!.total),
|
||||
thunderstorm = UnitUtils.validatePercent(newHalfDay.precipitationProbability!!.thunderstorm),
|
||||
rain = UnitUtils.validatePercent(newHalfDay.precipitationProbability!!.rain),
|
||||
snow = UnitUtils.validatePercent(newHalfDay.precipitationProbability!!.snow),
|
||||
ice = UnitUtils.validatePercent(newHalfDay.precipitationProbability!!.ice)
|
||||
total = newHalfDay.precipitationProbability!!.total?.toValidRangeOrNull(),
|
||||
thunderstorm = newHalfDay.precipitationProbability!!.thunderstorm?.toValidRangeOrNull(),
|
||||
rain = newHalfDay.precipitationProbability!!.rain?.toValidRangeOrNull(),
|
||||
snow = newHalfDay.precipitationProbability!!.snow?.toValidRangeOrNull(),
|
||||
ice = newHalfDay.precipitationProbability!!.ice?.toValidRangeOrNull()
|
||||
)
|
||||
val maxPrecipitationProbability = if (initialPrecipitationProbability?.total == null) {
|
||||
getHalfDayPrecipitationProbabilityFromHourlyList(halfDayHourlyList)
|
||||
|
@ -963,11 +967,11 @@ private fun getHalfDayWeatherCodeFromHourlyList(
|
|||
totPrecipitation: Precipitation?,
|
||||
maxPrecipitationProbability: PrecipitationProbability?,
|
||||
maxWind: Wind?,
|
||||
avgCloudCover: Int?,
|
||||
avgCloudCover: Ratio?,
|
||||
avgVisibility: Distance?,
|
||||
): WeatherCode? {
|
||||
val minPrecipIntensity = 1.0.millimeters // in mm
|
||||
val minPrecipProbability = 30.0 // in %
|
||||
val minPrecipIntensity = 1.0.millimeters
|
||||
val minPrecipProbability = 30.percent
|
||||
val maxVisibilityHaze = 5000.meters
|
||||
val maxVisibilityFog = 1000.meters
|
||||
val maxWindSpeedWindy = 10.metersPerSecond
|
||||
|
@ -975,7 +979,7 @@ private fun getHalfDayWeatherCodeFromHourlyList(
|
|||
// If total precipitation is greater than 1 mm
|
||||
// and max probability is greater than 30 % (assume 100 % if not reported)
|
||||
if ((totPrecipitation?.total ?: 0.0.millimeters) > minPrecipIntensity &&
|
||||
(maxPrecipitationProbability?.total ?: 100.0) > minPrecipProbability
|
||||
(maxPrecipitationProbability?.total ?: 100.percent) > minPrecipProbability
|
||||
) {
|
||||
val isRain = maxPrecipitationProbability?.rain?.let { it > minPrecipProbability }
|
||||
?: totPrecipitation!!.rain?.let { it.value > 0 }
|
||||
|
@ -1047,8 +1051,8 @@ private fun getHalfDayWeatherCodeFromHourlyList(
|
|||
|
||||
// It’s not raining, it’s not windy, and it’s not mysterious. Just cloudy
|
||||
if (avgCloudCover != null) {
|
||||
if (avgCloudCover > CLOUD_COVER_BKN) return WeatherCode.CLOUDY
|
||||
if (avgCloudCover > CLOUD_COVER_FEW) return WeatherCode.PARTLY_CLOUDY
|
||||
if (avgCloudCover > CLOUD_COVER_BKN.percent) return WeatherCode.CLOUDY
|
||||
if (avgCloudCover > CLOUD_COVER_FEW.percent) return WeatherCode.PARTLY_CLOUDY
|
||||
return WeatherCode.CLEAR
|
||||
}
|
||||
|
||||
|
@ -1230,10 +1234,9 @@ private fun getHalfDayWindFromHourlyList(
|
|||
|
||||
private fun getHalfDayCloudCoverFromHourlyList(
|
||||
halfDayHourlyList: List<Hourly>,
|
||||
): Int? {
|
||||
): Ratio? {
|
||||
// average() would return NaN when called for an empty list
|
||||
return halfDayHourlyList.mapNotNull { it.cloudCover }
|
||||
.takeIf { it.isNotEmpty() }?.average()?.roundToInt()
|
||||
return halfDayHourlyList.mapNotNull { it.cloudCover?.value }.takeIf { it.isNotEmpty() }?.average()?.permille
|
||||
}
|
||||
|
||||
private fun getHalfDayAvgVisibilityFromHourlyList(
|
||||
|
@ -1340,16 +1343,16 @@ private fun getSunshineDuration(
|
|||
|
||||
fun getDailyRelativeHumidity(
|
||||
initialDailyRelativeHumidity: DailyRelativeHumidity?,
|
||||
values: List<Double>?,
|
||||
values: List<Ratio>?,
|
||||
): DailyRelativeHumidity? {
|
||||
if (values.isNullOrEmpty()) return initialDailyRelativeHumidity
|
||||
|
||||
return DailyRelativeHumidity(
|
||||
average = UnitUtils.validatePercent(initialDailyRelativeHumidity?.average)
|
||||
?: values.average(),
|
||||
min = UnitUtils.validatePercent(initialDailyRelativeHumidity?.min)
|
||||
average = initialDailyRelativeHumidity?.average?.toValidRangeOrNull()
|
||||
?: values.map { it.value }.average().permille,
|
||||
min = initialDailyRelativeHumidity?.min?.toValidRangeOrNull()
|
||||
?: values.min(),
|
||||
max = UnitUtils.validatePercent(initialDailyRelativeHumidity?.max)
|
||||
max = initialDailyRelativeHumidity?.max?.toValidRangeOrNull()
|
||||
?: values.max()
|
||||
)
|
||||
}
|
||||
|
@ -1388,16 +1391,16 @@ fun getDailyPressure(
|
|||
|
||||
fun getDailyCloudCover(
|
||||
initialDailyCloudCover: DailyCloudCover?,
|
||||
values: List<Int>?,
|
||||
values: List<Ratio>?,
|
||||
): DailyCloudCover? {
|
||||
if (values.isNullOrEmpty()) return initialDailyCloudCover
|
||||
|
||||
return DailyCloudCover(
|
||||
average = UnitUtils.validatePercent(initialDailyCloudCover?.average)
|
||||
?: values.average().roundToInt(),
|
||||
min = UnitUtils.validatePercent(initialDailyCloudCover?.min)
|
||||
average = initialDailyCloudCover?.average?.toValidRangeOrNull()
|
||||
?: values.map { it.value }.average().permille,
|
||||
min = initialDailyCloudCover?.min?.toValidRangeOrNull()
|
||||
?: values.min(),
|
||||
max = UnitUtils.validatePercent(initialDailyCloudCover?.max)
|
||||
max = initialDailyCloudCover?.max?.toValidRangeOrNull()
|
||||
?: values.max()
|
||||
)
|
||||
}
|
||||
|
@ -1576,7 +1579,7 @@ internal fun completeCurrentFromHourlyData(
|
|||
val initialFeelsLike = newCurrent.temperature?.feelsLike?.toValidOrNull()
|
||||
val initialWind = newCurrent.wind?.validate()
|
||||
val newWind = if (initialWind?.speed != null || hourly.wind?.speed == null) initialWind else hourly.wind
|
||||
val newRelativeHumidity = UnitUtils.validatePercent(newCurrent.relativeHumidity)
|
||||
val newRelativeHumidity = newCurrent.relativeHumidity?.toValidRangeOrNull()
|
||||
?: hourly.relativeHumidity
|
||||
val newDewPoint = newCurrent.dewPoint?.toValidOrNull()
|
||||
?: if (newRelativeHumidity != null || initialTemp != null) {
|
||||
|
@ -1623,7 +1626,7 @@ internal fun completeCurrentFromHourlyData(
|
|||
relativeHumidity = newRelativeHumidity,
|
||||
dewPoint = newDewPoint,
|
||||
pressure = newCurrent.pressure?.toValidOrNull() ?: hourly.pressure,
|
||||
cloudCover = UnitUtils.validatePercent(newCurrent.cloudCover) ?: hourly.cloudCover,
|
||||
cloudCover = newCurrent.cloudCover?.toValidRangeOrNull() ?: hourly.cloudCover,
|
||||
visibility = newCurrent.visibility?.toValidOrNull() ?: hourly.visibility,
|
||||
ceiling = newCurrent.ceiling?.toValidOrNull()
|
||||
)
|
||||
|
@ -1634,7 +1637,7 @@ private fun completeCurrentTemperatureFromHourly(
|
|||
initialFeelsLike: Temperature?,
|
||||
hourlyTemperature: breezyweather.domain.weather.model.Temperature?,
|
||||
windSpeed: Speed?,
|
||||
relativeHumidity: Double?,
|
||||
relativeHumidity: Ratio?,
|
||||
dewPoint: Temperature?,
|
||||
): breezyweather.domain.weather.model.Temperature? {
|
||||
if (initialTemp == null) return hourlyTemperature
|
||||
|
|
|
@ -61,6 +61,7 @@ import org.breezyweather.sources.brightsky.json.BrightSkyWeatherResult
|
|||
import org.breezyweather.unit.distance.Distance.Companion.meters
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -215,10 +216,10 @@ class BrightSkyService @Inject constructor(
|
|||
speed = result.windSpeed?.kilometersPerHour,
|
||||
gusts = result.windGustSpeed?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = result.relativeHumidity?.toDouble(),
|
||||
relativeHumidity = result.relativeHumidity?.percent,
|
||||
dewPoint = result.dewPoint?.celsius,
|
||||
pressure = result.pressure?.hectopascals,
|
||||
cloudCover = result.cloudCover,
|
||||
cloudCover = result.cloudCover?.percent,
|
||||
visibility = result.visibility?.meters
|
||||
)
|
||||
}
|
||||
|
@ -268,17 +269,17 @@ class BrightSkyService @Inject constructor(
|
|||
total = result.precipitation?.millimeters
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = result.precipitationProbability?.toDouble()
|
||||
total = result.precipitationProbability?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = result.windDirection?.toDouble(),
|
||||
speed = result.windSpeed?.kilometersPerHour,
|
||||
gusts = result.windGustSpeed?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = result.relativeHumidity?.toDouble(),
|
||||
relativeHumidity = result.relativeHumidity?.percent,
|
||||
dewPoint = result.dewPoint?.celsius,
|
||||
pressure = result.pressure?.hectopascals,
|
||||
cloudCover = result.cloudCover,
|
||||
cloudCover = result.cloudCover?.percent,
|
||||
visibility = result.visibility?.toDouble()?.meters,
|
||||
sunshineDuration = result.sunshine?.minutes
|
||||
)
|
||||
|
|
|
@ -36,13 +36,13 @@ import org.breezyweather.common.source.WeatherSource
|
|||
import org.breezyweather.unit.distance.Distance.Companion.meters
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.fraction
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.TimeZone
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.random.Random
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
|
@ -146,7 +146,7 @@ class DebugService @Inject constructor() : WeatherSource {
|
|||
dewPoint = Math.random().times(10).plus(5).celsius,
|
||||
pressure = Math.random().times(100).plus(963).hectopascals,
|
||||
visibility = Math.random().times(50000).meters,
|
||||
cloudCover = Math.random().times(100).roundToInt()
|
||||
cloudCover = Math.random().fraction
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ class GadgetbridgeService @Inject constructor() : BroadcastSource {
|
|||
currentTemp = current?.temperature?.temperature?.inKelvins?.roundToInt(),
|
||||
currentConditionCode = getWeatherCode(current?.weatherCode),
|
||||
currentCondition = current?.weatherText,
|
||||
currentHumidity = current?.relativeHumidity?.roundToInt(),
|
||||
currentHumidity = current?.relativeHumidity?.inPercent?.roundToInt(),
|
||||
windSpeed = current?.wind?.speed?.inKilometersPerHour?.toFloat(),
|
||||
windDirection = current?.wind?.degree?.roundToInt(),
|
||||
uvIndex = current?.uV?.index?.toFloat(),
|
||||
|
@ -94,11 +94,11 @@ class GadgetbridgeService @Inject constructor() : BroadcastSource {
|
|||
precipProbability = maxOfNullable(
|
||||
today?.day?.precipitationProbability?.total,
|
||||
today?.night?.precipitationProbability?.total
|
||||
)?.roundToInt(),
|
||||
)?.inPercent?.roundToInt(),
|
||||
|
||||
dewPoint = current?.dewPoint?.inKelvins?.roundToInt(),
|
||||
pressure = current?.pressure?.inHectopascals?.toFloat(),
|
||||
cloudCover = current?.cloudCover,
|
||||
cloudCover = current?.cloudCover?.inPercent?.roundToInt(),
|
||||
visibility = current?.visibility?.inMeters?.toFloat(),
|
||||
|
||||
sunRise = today?.sun?.riseDate?.time?.div(1000)?.toInt(),
|
||||
|
@ -125,14 +125,14 @@ class GadgetbridgeService @Inject constructor() : BroadcastSource {
|
|||
conditionCode = getWeatherCode(day.day?.weatherCode),
|
||||
maxTemp = day.day?.temperature?.temperature?.inKelvins?.roundToInt(),
|
||||
minTemp = day.night?.temperature?.temperature?.inKelvins?.roundToInt(),
|
||||
humidity = day.relativeHumidity?.average?.roundToInt(),
|
||||
humidity = day.relativeHumidity?.average?.inPercent?.roundToInt(),
|
||||
windSpeed = maxWind?.speed?.inKilometersPerHour?.toFloat(),
|
||||
windDirection = maxWind?.degree?.roundToInt(),
|
||||
uvIndex = day.uV?.index?.toFloat(),
|
||||
precipProbability = maxOfNullable(
|
||||
day.day?.precipitationProbability?.total,
|
||||
day.night?.precipitationProbability?.total
|
||||
)?.roundToInt(),
|
||||
)?.inPercent?.roundToInt(),
|
||||
|
||||
sunRise = day.sun?.riseDate?.time?.div(1000)?.toInt(),
|
||||
sunSet = day.sun?.setDate?.time?.div(1000)?.toInt(),
|
||||
|
@ -174,11 +174,11 @@ class GadgetbridgeService @Inject constructor() : BroadcastSource {
|
|||
timestamp = hour.date.time.div(1000).toInt(),
|
||||
temp = hour.temperature?.temperature?.inKelvins?.roundToInt(),
|
||||
conditionCode = getWeatherCode(hour.weatherCode),
|
||||
humidity = hour.relativeHumidity?.roundToInt(),
|
||||
humidity = hour.relativeHumidity?.inPercent?.roundToInt(),
|
||||
windSpeed = hour.wind?.speed?.inKilometersPerHour?.toFloat(),
|
||||
windDirection = hour.wind?.degree?.roundToInt(),
|
||||
uvIndex = hour.uV?.index?.toFloat(),
|
||||
precipProbability = hour.precipitationProbability?.total?.roundToInt()
|
||||
precipProbability = hour.precipitationProbability?.total?.inPercent?.roundToInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@ import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.microgr
|
|||
import org.breezyweather.unit.precipitation.Precipitation.Companion.centimeters
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.HttpException
|
||||
|
@ -395,10 +396,10 @@ class OpenMeteoService @Inject constructor(
|
|||
gusts = current.windGusts?.metersPerSecond
|
||||
),
|
||||
uV = UV(index = current.uvIndex),
|
||||
relativeHumidity = current.relativeHumidity?.toDouble(),
|
||||
relativeHumidity = current.relativeHumidity?.percent,
|
||||
dewPoint = current.dewPoint?.celsius,
|
||||
pressure = current.pressureMsl?.hectopascals,
|
||||
cloudCover = current.cloudCover,
|
||||
cloudCover = current.cloudCover?.percent,
|
||||
visibility = current.visibility?.meters
|
||||
)
|
||||
}
|
||||
|
@ -435,9 +436,9 @@ class OpenMeteoService @Inject constructor(
|
|||
uV = UV(index = dailyResult.uvIndexMax?.getOrNull(i)),
|
||||
sunshineDuration = dailyResult.sunshineDuration?.getOrNull(i)?.seconds,
|
||||
relativeHumidity = DailyRelativeHumidity(
|
||||
average = dailyResult.relativeHumidityMean?.getOrNull(i)?.toDouble(),
|
||||
max = dailyResult.relativeHumidityMax?.getOrNull(i)?.toDouble(),
|
||||
min = dailyResult.relativeHumidityMin?.getOrNull(i)?.toDouble()
|
||||
average = dailyResult.relativeHumidityMean?.getOrNull(i)?.percent,
|
||||
max = dailyResult.relativeHumidityMax?.getOrNull(i)?.percent,
|
||||
min = dailyResult.relativeHumidityMin?.getOrNull(i)?.percent
|
||||
),
|
||||
dewPoint = DailyDewPoint(
|
||||
average = dailyResult.dewPointMean?.getOrNull(i)?.celsius,
|
||||
|
@ -450,9 +451,9 @@ class OpenMeteoService @Inject constructor(
|
|||
min = dailyResult.pressureMslMin?.getOrNull(i)?.hectopascals
|
||||
),
|
||||
cloudCover = DailyCloudCover(
|
||||
average = dailyResult.cloudCoverMean?.getOrNull(i),
|
||||
max = dailyResult.cloudCoverMax?.getOrNull(i),
|
||||
min = dailyResult.cloudCoverMin?.getOrNull(i)
|
||||
average = dailyResult.cloudCoverMean?.getOrNull(i)?.percent,
|
||||
max = dailyResult.cloudCoverMax?.getOrNull(i)?.percent,
|
||||
min = dailyResult.cloudCoverMin?.getOrNull(i)?.percent
|
||||
),
|
||||
visibility = DailyVisibility(
|
||||
average = dailyResult.visibilityMean?.getOrNull(i)?.meters,
|
||||
|
@ -489,7 +490,7 @@ class OpenMeteoService @Inject constructor(
|
|||
snow = hourlyResult.snowfall?.getOrNull(i)?.centimeters
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = hourlyResult.precipitationProbability?.getOrNull(i)?.toDouble()
|
||||
total = hourlyResult.precipitationProbability?.getOrNull(i)?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = hourlyResult.windDirection?.getOrNull(i)?.toDouble(),
|
||||
|
@ -497,10 +498,10 @@ class OpenMeteoService @Inject constructor(
|
|||
gusts = hourlyResult.windGusts?.getOrNull(i)?.metersPerSecond
|
||||
),
|
||||
uV = UV(index = hourlyResult.uvIndex?.getOrNull(i)),
|
||||
relativeHumidity = hourlyResult.relativeHumidity?.getOrNull(i)?.toDouble(),
|
||||
relativeHumidity = hourlyResult.relativeHumidity?.getOrNull(i)?.percent,
|
||||
dewPoint = hourlyResult.dewPoint?.getOrNull(i)?.celsius,
|
||||
pressure = hourlyResult.pressureMsl?.getOrNull(i)?.hectopascals,
|
||||
cloudCover = hourlyResult.cloudCover?.getOrNull(i),
|
||||
cloudCover = hourlyResult.cloudCover?.getOrNull(i)?.percent,
|
||||
visibility = hourlyResult.visibility?.getOrNull(i)?.meters
|
||||
)
|
||||
)
|
||||
|
|
|
@ -63,6 +63,7 @@ import org.breezyweather.unit.distance.Distance.Companion.kilometers
|
|||
import org.breezyweather.unit.precipitation.Precipitation.Companion.centimeters
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.fraction
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -170,10 +171,10 @@ class PirateWeatherService @Inject constructor(
|
|||
gusts = result.windGust?.metersPerSecond
|
||||
),
|
||||
uV = UV(index = result.uvIndex),
|
||||
relativeHumidity = result.humidity?.times(100),
|
||||
relativeHumidity = result.humidity?.fraction,
|
||||
dewPoint = result.dewPoint?.celsius,
|
||||
pressure = result.pressure?.hectopascals,
|
||||
cloudCover = result.cloudCover?.times(100)?.roundToInt(),
|
||||
cloudCover = result.cloudCover?.fraction,
|
||||
visibility = result.visibility?.kilometers,
|
||||
dailyForecast = dailySummary,
|
||||
hourlyForecast = hourlySummary
|
||||
|
@ -205,10 +206,10 @@ class PirateWeatherService @Inject constructor(
|
|||
)
|
||||
),
|
||||
uV = UV(index = result.uvIndex),
|
||||
relativeHumidity = DailyRelativeHumidity(average = result.humidity?.times(100)),
|
||||
relativeHumidity = DailyRelativeHumidity(average = result.humidity?.fraction),
|
||||
dewPoint = DailyDewPoint(average = result.dewPoint?.celsius),
|
||||
pressure = DailyPressure(average = result.pressure?.hectopascals),
|
||||
cloudCover = DailyCloudCover(average = result.cloudCover?.times(100)?.roundToInt()),
|
||||
cloudCover = DailyCloudCover(average = result.cloudCover?.fraction),
|
||||
visibility = DailyVisibility(average = result.visibility?.kilometers)
|
||||
)
|
||||
}
|
||||
|
@ -237,7 +238,7 @@ class PirateWeatherService @Inject constructor(
|
|||
ice = result.iceAccumulation?.centimeters
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = result.precipProbability?.times(100)
|
||||
total = result.precipProbability?.fraction
|
||||
),
|
||||
wind = Wind(
|
||||
degree = result.windBearing,
|
||||
|
@ -247,10 +248,10 @@ class PirateWeatherService @Inject constructor(
|
|||
uV = UV(
|
||||
index = result.uvIndex
|
||||
),
|
||||
relativeHumidity = result.humidity?.times(100),
|
||||
relativeHumidity = result.humidity?.fraction,
|
||||
dewPoint = result.dewPoint?.celsius,
|
||||
pressure = result.pressure?.hectopascals,
|
||||
cloudCover = result.cloudCover?.times(100)?.roundToInt(),
|
||||
cloudCover = result.cloudCover?.fraction,
|
||||
visibility = result.visibility?.kilometers
|
||||
)
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalResources
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -441,6 +442,7 @@ private fun AirQualityChart(
|
|||
markerVisibilityListener: CartesianMarkerVisibilityListener,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val resources = LocalResources.current
|
||||
|
||||
val maxY = remember(mappedValues, selectedPollutant) {
|
||||
max(
|
||||
|
@ -475,38 +477,46 @@ private fun AirQualityChart(
|
|||
}
|
||||
|
||||
BreezyLineChart(
|
||||
location,
|
||||
modelProducer,
|
||||
daily.date,
|
||||
maxY.toDouble(),
|
||||
{ _, value, _ ->
|
||||
if (selectedPollutant == null) {
|
||||
UnitUtils.formatInt(context, value.roundToInt())
|
||||
} else {
|
||||
PollutantIndex.getUnit(selectedPollutant).formatMeasure(context, value)
|
||||
location = location,
|
||||
modelProducer = modelProducer,
|
||||
theDay = daily.date,
|
||||
maxY = maxY.toDouble(),
|
||||
endAxisValueFormatter = remember(selectedPollutant) {
|
||||
{ _, value, _ ->
|
||||
if (selectedPollutant == null) {
|
||||
UnitUtils.formatInt(context, value.roundToInt())
|
||||
} else {
|
||||
PollutantIndex.getUnit(selectedPollutant).formatMeasure(context, value)
|
||||
}
|
||||
}
|
||||
},
|
||||
persistentListOf(
|
||||
((selectedPollutant?.thresholds ?: PollutantIndex.aqiThresholds).reversed().map { it.toFloat() }).zip(
|
||||
context.resources.getIntArray(PollutantIndex.colorsArrayId).reversed().map { Color(it) }
|
||||
).toMap().toImmutableMap()
|
||||
),
|
||||
trendHorizontalLines = persistentMapOf(
|
||||
(selectedPollutant?.let { it.thresholds[3] } ?: PollutantIndex.aqiThresholds[3]).toDouble() to
|
||||
context.resources.getStringArray(R.array.air_quality_levels)[3]
|
||||
),
|
||||
topAxisValueFormatter = { _, value, _ ->
|
||||
mappedValues.getOrElse(value.toLong()) { null }
|
||||
?.let {
|
||||
UnitUtils.formatInt(
|
||||
context,
|
||||
if (selectedPollutant == null) {
|
||||
it.getIndex()!!
|
||||
} else {
|
||||
it.getConcentration(selectedPollutant)!!.roundToInt()
|
||||
}
|
||||
)
|
||||
} ?: "-"
|
||||
colors = remember(selectedPollutant) {
|
||||
persistentListOf(
|
||||
((selectedPollutant?.thresholds ?: PollutantIndex.aqiThresholds).reversed().map { it.toFloat() }).zip(
|
||||
resources.getIntArray(PollutantIndex.colorsArrayId).reversed().map { Color(it) }
|
||||
).toMap().toImmutableMap()
|
||||
)
|
||||
},
|
||||
trendHorizontalLines = remember(selectedPollutant) {
|
||||
persistentMapOf(
|
||||
(selectedPollutant?.let { it.thresholds[3] } ?: PollutantIndex.aqiThresholds[3]).toDouble() to
|
||||
resources.getStringArray(R.array.air_quality_levels)[3]
|
||||
)
|
||||
},
|
||||
topAxisValueFormatter = remember(mappedValues) {
|
||||
{ _, value, _ ->
|
||||
mappedValues.getOrElse(value.toLong()) { null }
|
||||
?.let {
|
||||
UnitUtils.formatInt(
|
||||
context,
|
||||
if (selectedPollutant == null) {
|
||||
it.getIndex()!!
|
||||
} else {
|
||||
it.getConcentration(selectedPollutant)!!.roundToInt()
|
||||
}
|
||||
)
|
||||
} ?: "-"
|
||||
}
|
||||
},
|
||||
endAxisItemPlacer = remember(selectedPollutant) {
|
||||
SpecificVerticalAxisItemPlacer(
|
||||
|
|
|
@ -50,7 +50,6 @@ import breezyweather.domain.weather.model.Daily
|
|||
import breezyweather.domain.weather.model.Hourly
|
||||
import com.patrykandpatrick.vico.core.cartesian.axis.VerticalAxis
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.lineSeries
|
||||
import com.patrykandpatrick.vico.core.cartesian.marker.CartesianMarker
|
||||
import com.patrykandpatrick.vico.core.cartesian.marker.CartesianMarkerVisibilityListener
|
||||
|
@ -60,14 +59,19 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import kotlinx.collections.immutable.toImmutableMap
|
||||
import org.breezyweather.R
|
||||
import org.breezyweather.common.extensions.cloudCoverScaleThresholds
|
||||
import org.breezyweather.common.extensions.CLOUD_COVER_BKN
|
||||
import org.breezyweather.common.extensions.CLOUD_COVER_FEW
|
||||
import org.breezyweather.common.extensions.CLOUD_COVER_OVC
|
||||
import org.breezyweather.common.extensions.CLOUD_COVER_SCT
|
||||
import org.breezyweather.common.extensions.CLOUD_COVER_SKC
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.formatTime
|
||||
import org.breezyweather.common.extensions.formatValue
|
||||
import org.breezyweather.common.extensions.getCloudCoverDescription
|
||||
import org.breezyweather.common.extensions.getFormattedTime
|
||||
import org.breezyweather.common.extensions.is12Hour
|
||||
import org.breezyweather.common.extensions.toDate
|
||||
import org.breezyweather.common.options.appearance.DetailScreen
|
||||
import org.breezyweather.common.utils.UnitUtils
|
||||
import org.breezyweather.domain.weather.model.getFullLabel
|
||||
import org.breezyweather.domain.weather.model.getRangeDescriptionSummary
|
||||
import org.breezyweather.domain.weather.model.getRangeSummary
|
||||
|
@ -75,8 +79,9 @@ import org.breezyweather.ui.common.charts.BreezyLineChart
|
|||
import org.breezyweather.ui.common.widgets.Material3ExpressiveCardListItem
|
||||
import org.breezyweather.ui.settings.preference.bottomInsetItem
|
||||
import org.breezyweather.unit.formatting.UnitWidth
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import java.util.Date
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.DurationUnit
|
||||
|
||||
|
@ -85,7 +90,7 @@ fun DetailsCloudCover(
|
|||
location: Location,
|
||||
hourlyList: ImmutableList<Hourly>,
|
||||
daily: Daily,
|
||||
defaultValue: Pair<Date, Int>?,
|
||||
defaultValue: Pair<Date, Ratio>?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val mappedValues = remember(hourlyList) {
|
||||
|
@ -94,7 +99,7 @@ fun DetailsCloudCover(
|
|||
.associate { it.date.time to it.cloudCover!! }
|
||||
.toImmutableMap()
|
||||
}
|
||||
var activeItem: Pair<Date, Int>? by remember { mutableStateOf(null) }
|
||||
var activeItem: Pair<Date, Ratio>? by remember { mutableStateOf(null) }
|
||||
val markerVisibilityListener = remember {
|
||||
object : CartesianMarkerVisibilityListener {
|
||||
override fun onShown(marker: CartesianMarker, targets: List<CartesianMarker.Target>) {
|
||||
|
@ -181,8 +186,8 @@ fun DetailsCloudCover(
|
|||
private fun CloudCoverHeader(
|
||||
location: Location,
|
||||
daily: Daily,
|
||||
activeItem: Pair<Date, Int>?,
|
||||
defaultValue: Pair<Date, Int>?,
|
||||
activeItem: Pair<Date, Ratio>?,
|
||||
defaultValue: Pair<Date, Ratio>?,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
|
@ -204,7 +209,7 @@ private fun CloudCoverHeader(
|
|||
@Composable
|
||||
private fun CloudCoverItem(
|
||||
header: String?,
|
||||
cloudCover: Int?,
|
||||
cloudCover: Ratio?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
@ -217,13 +222,11 @@ private fun CloudCoverItem(
|
|||
style = MaterialTheme.typography.labelMedium
|
||||
)
|
||||
TextFixedHeight(
|
||||
text = cloudCover?.let {
|
||||
UnitUtils.formatPercent(context, it.toDouble())
|
||||
} ?: "",
|
||||
text = cloudCover?.formatPercent(context) ?: "",
|
||||
style = MaterialTheme.typography.displaySmall
|
||||
)
|
||||
TextFixedHeight(
|
||||
text = getCloudCoverDescription(context, cloudCover) ?: "",
|
||||
text = cloudCover?.getCloudCoverDescription(context) ?: "",
|
||||
style = MaterialTheme.typography.labelMedium
|
||||
)
|
||||
}
|
||||
|
@ -257,7 +260,7 @@ private fun CloudCoverSummary(
|
|||
@Composable
|
||||
private fun CloudCoverChart(
|
||||
location: Location,
|
||||
mappedValues: ImmutableMap<Long, Int>,
|
||||
mappedValues: ImmutableMap<Long, Ratio>,
|
||||
daily: Daily,
|
||||
markerVisibilityListener: CartesianMarkerVisibilityListener,
|
||||
) {
|
||||
|
@ -269,35 +272,31 @@ private fun CloudCoverChart(
|
|||
lineSeries {
|
||||
series(
|
||||
x = mappedValues.keys,
|
||||
y = mappedValues.values
|
||||
y = mappedValues.values.map { it.inPercent }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BreezyLineChart(
|
||||
location,
|
||||
modelProducer,
|
||||
daily.date,
|
||||
location = location,
|
||||
modelProducer = modelProducer,
|
||||
theDay = daily.date,
|
||||
maxY = 100.0,
|
||||
endAxisValueFormatter = remember {
|
||||
CartesianValueFormatter { _, value, _ ->
|
||||
UnitUtils.formatPercent(context, value)
|
||||
}
|
||||
},
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
100f to Color(213, 213, 205),
|
||||
98f to Color(198, 201, 201),
|
||||
95f to Color(171, 180, 179),
|
||||
50f to Color(116, 116, 116),
|
||||
10f to Color(132, 119, 70),
|
||||
0f to Color(146, 130, 70)
|
||||
endAxisValueFormatter = remember { { _, value, _ -> value.percent.formatPercent(context) } },
|
||||
colors = remember {
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
100f to Color(213, 213, 205),
|
||||
98f to Color(198, 201, 201),
|
||||
95f to Color(171, 180, 179),
|
||||
50f to Color(116, 116, 116),
|
||||
10f to Color(132, 119, 70),
|
||||
0f to Color(146, 130, 70)
|
||||
)
|
||||
)
|
||||
),
|
||||
endAxisItemPlacer = remember {
|
||||
VerticalAxis.ItemPlacer.step({ 20.0 }) // Every 20 %
|
||||
},
|
||||
endAxisItemPlacer = remember { VerticalAxis.ItemPlacer.step({ 20.0 }) }, // Every 20 %
|
||||
markerVisibilityListener = markerVisibilityListener
|
||||
)
|
||||
}
|
||||
|
@ -333,6 +332,14 @@ fun CloudCoverScale(
|
|||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val cloudCoverScaleThresholds = listOf(
|
||||
0.0.percent,
|
||||
CLOUD_COVER_SKC.percent,
|
||||
CLOUD_COVER_FEW.percent,
|
||||
CLOUD_COVER_SCT.percent,
|
||||
CLOUD_COVER_BKN.percent,
|
||||
CLOUD_COVER_OVC.percent
|
||||
)
|
||||
|
||||
Material3ExpressiveCardListItem(
|
||||
modifier = modifier,
|
||||
|
@ -363,11 +370,9 @@ fun CloudCoverScale(
|
|||
)
|
||||
}
|
||||
cloudCoverScaleThresholds.dropLast(1).forEachIndexed { index, startingValue ->
|
||||
val startingValueFormatted = UnitUtils.formatNumber(context, startingValue, precision = 1)
|
||||
val startingValueFormatted = startingValue.formatValue(context)
|
||||
val endingValueFormatted = cloudCoverScaleThresholds.getOrElse(index + 1) { null }
|
||||
?.let {
|
||||
" – ${UnitUtils.formatNumber(context, it, precision = 1)}"
|
||||
}
|
||||
?.let { " – ${it.formatValue(context)}" }
|
||||
?: "+"
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
|
@ -377,7 +382,7 @@ fun CloudCoverScale(
|
|||
.padding(top = dimensionResource(R.dimen.small_margin))
|
||||
) {
|
||||
Text(
|
||||
text = getCloudCoverDescription(context, (startingValue + 0.1).roundToInt())!!,
|
||||
text = startingValue.getCloudCoverDescription(context)!!,
|
||||
modifier = Modifier.weight(1.5f)
|
||||
)
|
||||
Text(
|
||||
|
|
|
@ -104,6 +104,7 @@ import org.breezyweather.ui.settings.preference.bottomInsetItem
|
|||
import org.breezyweather.ui.theme.resource.ResourceHelper
|
||||
import org.breezyweather.ui.theme.resource.ResourcesProviderFactory
|
||||
import org.breezyweather.unit.formatting.UnitWidth
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.temperature.Temperature
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.deciCelsius
|
||||
|
@ -163,7 +164,7 @@ fun DetailsConditions(
|
|||
.associate { it.date.time to it.precipitationProbability!!.total!! }
|
||||
.toImmutableMap()
|
||||
}
|
||||
var activeProbabilityItem: Pair<Date, Double>? by remember { mutableStateOf(null) }
|
||||
var activeProbabilityItem: Pair<Date, Ratio>? by remember { mutableStateOf(null) }
|
||||
val probabilityMarkerVisibilityListener = remember {
|
||||
object : CartesianMarkerVisibilityListener {
|
||||
override fun onShown(marker: CartesianMarker, targets: List<CartesianMarker.Target>) {
|
||||
|
@ -801,67 +802,73 @@ private fun TemperatureChart(
|
|||
}
|
||||
|
||||
BreezyLineChart(
|
||||
location,
|
||||
modelProducer,
|
||||
daily.date,
|
||||
maxY,
|
||||
{ _, value, _ ->
|
||||
value.toTemperature(temperatureUnit)
|
||||
.formatMeasure(context, valueWidth = UnitWidth.NARROW, unitWidth = UnitWidth.NARROW)
|
||||
},
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
47.celsius.toDouble(temperatureUnit).toFloat() to Color(71, 14, 0),
|
||||
30.celsius.toDouble(temperatureUnit).toFloat() to Color(232, 83, 25),
|
||||
21.celsius.toDouble(temperatureUnit).toFloat() to Color(243, 183, 4),
|
||||
10.celsius.toDouble(temperatureUnit).toFloat() to Color(128, 147, 24),
|
||||
1.celsius.toDouble(temperatureUnit).toFloat() to Color(68, 125, 99),
|
||||
0.celsius.toDouble(temperatureUnit).toFloat() to Color(93, 133, 198),
|
||||
-4.celsius.toDouble(temperatureUnit).toFloat() to Color(100, 166, 189),
|
||||
-8.celsius.toDouble(temperatureUnit).toFloat() to Color(106, 191, 181),
|
||||
-15.celsius.toDouble(temperatureUnit).toFloat() to Color(157, 219, 217),
|
||||
-25.celsius.toDouble(temperatureUnit).toFloat() to Color(143, 89, 169),
|
||||
-40.celsius.toDouble(temperatureUnit).toFloat() to Color(162, 70, 145),
|
||||
-55.celsius.toDouble(temperatureUnit).toFloat() to Color(202, 172, 195),
|
||||
-70.celsius.toDouble(temperatureUnit).toFloat() to Color(115, 70, 105)
|
||||
),
|
||||
persistentMapOf(
|
||||
50f to Color(128, 128, 128, 160),
|
||||
0f to Color(128, 128, 128, 160)
|
||||
)
|
||||
),
|
||||
topAxisValueFormatter = { _, value, _ ->
|
||||
mappedValues.getOrElse(value.toLong()) { null }?.let { hourly ->
|
||||
hourly.weatherCode?.let {
|
||||
val ss = SpannableString("abc")
|
||||
val d = ResourceHelper.getWeatherIcon(provider, it, hourly.isDaylight)
|
||||
d.setBounds(0, 0, 64, 64)
|
||||
val span = ImageSpan(d, ImageSpan.ALIGN_BASELINE)
|
||||
ss.setSpan(span, 0, 3, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
|
||||
ss
|
||||
}
|
||||
} ?: "-"
|
||||
},
|
||||
trendHorizontalLines = buildMap {
|
||||
normals?.let {
|
||||
it.daytimeTemperature?.let { normal ->
|
||||
put(
|
||||
normal.toDouble(temperatureUnit),
|
||||
context.getString(R.string.temperature_normal_short)
|
||||
)
|
||||
}
|
||||
it.nighttimeTemperature?.let { normal ->
|
||||
put(
|
||||
normal.toDouble(temperatureUnit),
|
||||
context.getString(R.string.temperature_normal_short)
|
||||
)
|
||||
}
|
||||
location = location,
|
||||
modelProducer = modelProducer,
|
||||
theDay = daily.date,
|
||||
maxY = maxY,
|
||||
endAxisValueFormatter = remember {
|
||||
{ _, value, _ ->
|
||||
value.toTemperature(temperatureUnit)
|
||||
.formatMeasure(context, valueWidth = UnitWidth.NARROW, unitWidth = UnitWidth.NARROW)
|
||||
}
|
||||
}.toImmutableMap(),
|
||||
minY = minY,
|
||||
endAxisItemPlacer = remember {
|
||||
VerticalAxis.ItemPlacer.step({ step })
|
||||
},
|
||||
colors = remember {
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
47.celsius.toDouble(temperatureUnit).toFloat() to Color(71, 14, 0),
|
||||
30.celsius.toDouble(temperatureUnit).toFloat() to Color(232, 83, 25),
|
||||
21.celsius.toDouble(temperatureUnit).toFloat() to Color(243, 183, 4),
|
||||
10.celsius.toDouble(temperatureUnit).toFloat() to Color(128, 147, 24),
|
||||
1.celsius.toDouble(temperatureUnit).toFloat() to Color(68, 125, 99),
|
||||
0.celsius.toDouble(temperatureUnit).toFloat() to Color(93, 133, 198),
|
||||
-4.celsius.toDouble(temperatureUnit).toFloat() to Color(100, 166, 189),
|
||||
-8.celsius.toDouble(temperatureUnit).toFloat() to Color(106, 191, 181),
|
||||
-15.celsius.toDouble(temperatureUnit).toFloat() to Color(157, 219, 217),
|
||||
-25.celsius.toDouble(temperatureUnit).toFloat() to Color(143, 89, 169),
|
||||
-40.celsius.toDouble(temperatureUnit).toFloat() to Color(162, 70, 145),
|
||||
-55.celsius.toDouble(temperatureUnit).toFloat() to Color(202, 172, 195),
|
||||
-70.celsius.toDouble(temperatureUnit).toFloat() to Color(115, 70, 105)
|
||||
),
|
||||
persistentMapOf(
|
||||
50f to Color(128, 128, 128, 160),
|
||||
0f to Color(128, 128, 128, 160)
|
||||
)
|
||||
)
|
||||
},
|
||||
topAxisValueFormatter = remember(mappedValues) {
|
||||
{ _, value, _ ->
|
||||
mappedValues.getOrElse(value.toLong()) { null }?.let { hourly ->
|
||||
hourly.weatherCode?.let {
|
||||
val ss = SpannableString("abc")
|
||||
val d = ResourceHelper.getWeatherIcon(provider, it, hourly.isDaylight)
|
||||
d.setBounds(0, 0, 64, 64)
|
||||
val span = ImageSpan(d, ImageSpan.ALIGN_BASELINE)
|
||||
ss.setSpan(span, 0, 3, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
|
||||
ss
|
||||
}
|
||||
} ?: "-"
|
||||
}
|
||||
},
|
||||
trendHorizontalLines = remember {
|
||||
buildMap {
|
||||
normals?.let {
|
||||
it.daytimeTemperature?.let { normal ->
|
||||
put(
|
||||
normal.toDouble(temperatureUnit),
|
||||
context.getString(R.string.temperature_normal_short)
|
||||
)
|
||||
}
|
||||
it.nighttimeTemperature?.let { normal ->
|
||||
put(
|
||||
normal.toDouble(temperatureUnit),
|
||||
context.getString(R.string.temperature_normal_short)
|
||||
)
|
||||
}
|
||||
}
|
||||
}.toImmutableMap()
|
||||
},
|
||||
minY = minY,
|
||||
endAxisItemPlacer = remember { VerticalAxis.ItemPlacer.step({ step }) },
|
||||
markerVisibilityListener = markerVisibilityListener
|
||||
)
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ import breezyweather.domain.weather.model.Daily
|
|||
import breezyweather.domain.weather.model.Hourly
|
||||
import com.patrykandpatrick.vico.core.cartesian.axis.VerticalAxis
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.lineSeries
|
||||
import com.patrykandpatrick.vico.core.cartesian.marker.CartesianMarker
|
||||
import com.patrykandpatrick.vico.core.cartesian.marker.CartesianMarkerVisibilityListener
|
||||
|
@ -54,13 +53,13 @@ import kotlinx.collections.immutable.persistentMapOf
|
|||
import kotlinx.collections.immutable.toImmutableMap
|
||||
import org.breezyweather.R
|
||||
import org.breezyweather.common.extensions.formatMeasure
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.getFormattedTime
|
||||
import org.breezyweather.common.extensions.is12Hour
|
||||
import org.breezyweather.common.extensions.roundDownToNearestMultiplier
|
||||
import org.breezyweather.common.extensions.roundUpToNearestMultiplier
|
||||
import org.breezyweather.common.extensions.toDate
|
||||
import org.breezyweather.common.options.appearance.DetailScreen
|
||||
import org.breezyweather.common.utils.UnitUtils
|
||||
import org.breezyweather.domain.settings.SettingsManager
|
||||
import org.breezyweather.domain.weather.model.getFullLabel
|
||||
import org.breezyweather.domain.weather.model.getRangeContentDescriptionSummary
|
||||
|
@ -68,6 +67,8 @@ import org.breezyweather.domain.weather.model.getRangeSummary
|
|||
import org.breezyweather.ui.common.charts.BreezyLineChart
|
||||
import org.breezyweather.ui.settings.preference.bottomInsetItem
|
||||
import org.breezyweather.unit.formatting.UnitWidth
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.temperature.Temperature
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import org.breezyweather.unit.temperature.toTemperature
|
||||
|
@ -78,7 +79,7 @@ fun DetailsHumidity(
|
|||
location: Location,
|
||||
hourlyList: ImmutableList<Hourly>,
|
||||
daily: Daily,
|
||||
defaultHumidityValue: Pair<Date, Double>?,
|
||||
defaultHumidityValue: Pair<Date, Ratio>?,
|
||||
defaultDewPointValue: Pair<Date, Temperature>?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
@ -89,7 +90,7 @@ fun DetailsHumidity(
|
|||
.associate { it.date.time to it.relativeHumidity!! }
|
||||
.toImmutableMap()
|
||||
}
|
||||
var activeHumidityItem: Pair<Date, Double>? by remember { mutableStateOf(null) }
|
||||
var activeHumidityItem: Pair<Date, Ratio>? by remember { mutableStateOf(null) }
|
||||
val humidityMarkerVisibilityListener = remember {
|
||||
object : CartesianMarkerVisibilityListener {
|
||||
override fun onShown(marker: CartesianMarker, targets: List<CartesianMarker.Target>) {
|
||||
|
@ -204,7 +205,10 @@ fun DetailsHumidity(
|
|||
}
|
||||
item {
|
||||
DetailsCardText(
|
||||
stringResource(R.string.dew_point_about_description, UnitUtils.formatPercent(context, 100.0))
|
||||
stringResource(
|
||||
R.string.dew_point_about_description,
|
||||
100.percent.formatPercent(context, UnitWidth.NARROW)
|
||||
)
|
||||
)
|
||||
}
|
||||
bottomInsetItem()
|
||||
|
@ -215,8 +219,8 @@ fun DetailsHumidity(
|
|||
fun HumidityHeader(
|
||||
location: Location,
|
||||
daily: Daily,
|
||||
activeItem: Pair<Date, Double>?,
|
||||
defaultValue: Pair<Date, Double>?,
|
||||
activeItem: Pair<Date, Ratio>?,
|
||||
defaultValue: Pair<Date, Ratio>?,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
|
@ -270,7 +274,7 @@ private fun HumiditySummary(
|
|||
@Composable
|
||||
private fun HumidityItem(
|
||||
header: @Composable () -> Unit,
|
||||
relativeHumidity: Double?,
|
||||
relativeHumidity: Ratio?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
@ -280,9 +284,7 @@ private fun HumidityItem(
|
|||
) {
|
||||
header()
|
||||
TextFixedHeight(
|
||||
text = relativeHumidity?.let {
|
||||
UnitUtils.formatPercent(context, it)
|
||||
} ?: "",
|
||||
text = relativeHumidity?.formatPercent(context) ?: "",
|
||||
style = MaterialTheme.typography.displaySmall
|
||||
)
|
||||
}
|
||||
|
@ -291,7 +293,7 @@ private fun HumidityItem(
|
|||
@Composable
|
||||
private fun HumidityChart(
|
||||
location: Location,
|
||||
mappedValues: ImmutableMap<Long, Double>,
|
||||
mappedValues: ImmutableMap<Long, Ratio>,
|
||||
daily: Daily,
|
||||
markerVisibilityListener: CartesianMarkerVisibilityListener,
|
||||
) {
|
||||
|
@ -299,10 +301,6 @@ private fun HumidityChart(
|
|||
|
||||
val maxY = 100.0
|
||||
|
||||
val endAxisValueFormatter = CartesianValueFormatter { _, value, _ ->
|
||||
UnitUtils.formatPercent(context, value)
|
||||
}
|
||||
|
||||
val modelProducer = remember { CartesianChartModelProducer() }
|
||||
|
||||
LaunchedEffect(location) {
|
||||
|
@ -310,44 +308,44 @@ private fun HumidityChart(
|
|||
lineSeries {
|
||||
series(
|
||||
x = mappedValues.keys,
|
||||
y = mappedValues.values
|
||||
y = mappedValues.values.map { it.inPercent }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BreezyLineChart(
|
||||
location,
|
||||
modelProducer,
|
||||
daily.date,
|
||||
maxY,
|
||||
endAxisValueFormatter,
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
100f to Color(56, 70, 114),
|
||||
97f to Color(56, 98, 157),
|
||||
93f to Color(56, 123, 173),
|
||||
90f to Color(56, 132, 173),
|
||||
87f to Color(56, 135, 173),
|
||||
83f to Color(56, 148, 173),
|
||||
80f to Color(56, 157, 173),
|
||||
75f to Color(56, 160, 173),
|
||||
70f to Color(56, 174, 173),
|
||||
60f to Color(56, 173, 121),
|
||||
50f to Color(105, 173, 56),
|
||||
40f to Color(173, 146, 56),
|
||||
30f to Color(173, 110, 56),
|
||||
0f to Color(173, 85, 56)
|
||||
location = location,
|
||||
modelProducer = modelProducer,
|
||||
theDay = daily.date,
|
||||
maxY = maxY,
|
||||
endAxisValueFormatter = remember { { _, value, _ -> value.percent.formatPercent(context) } },
|
||||
colors = remember {
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
100f to Color(56, 70, 114),
|
||||
97f to Color(56, 98, 157),
|
||||
93f to Color(56, 123, 173),
|
||||
90f to Color(56, 132, 173),
|
||||
87f to Color(56, 135, 173),
|
||||
83f to Color(56, 148, 173),
|
||||
80f to Color(56, 157, 173),
|
||||
75f to Color(56, 160, 173),
|
||||
70f to Color(56, 174, 173),
|
||||
60f to Color(56, 173, 121),
|
||||
50f to Color(105, 173, 56),
|
||||
40f to Color(173, 146, 56),
|
||||
30f to Color(173, 110, 56),
|
||||
0f to Color(173, 85, 56)
|
||||
)
|
||||
)
|
||||
),
|
||||
topAxisValueFormatter = { _, value, _ ->
|
||||
mappedValues.getOrElse(value.toLong()) { null }?.let {
|
||||
UnitUtils.formatPercent(context, it)
|
||||
} ?: "-"
|
||||
},
|
||||
endAxisItemPlacer = remember {
|
||||
VerticalAxis.ItemPlacer.step({ 20.0 }) // Every 20 %
|
||||
topAxisValueFormatter = remember(mappedValues) {
|
||||
{ _, value, _ ->
|
||||
mappedValues.getOrElse(value.toLong()) { null }?.formatPercent(context, UnitWidth.NARROW) ?: "-"
|
||||
}
|
||||
},
|
||||
endAxisItemPlacer = remember { VerticalAxis.ItemPlacer.step({ 20.0 }) }, // Every 20 %
|
||||
markerVisibilityListener = markerVisibilityListener
|
||||
)
|
||||
}
|
||||
|
@ -471,43 +469,47 @@ private fun DewPointChart(
|
|||
}
|
||||
|
||||
BreezyLineChart(
|
||||
location,
|
||||
modelProducer,
|
||||
daily.date,
|
||||
maxY,
|
||||
{ _, value, _ ->
|
||||
value.toTemperature(temperatureUnit)
|
||||
.formatMeasure(context, valueWidth = UnitWidth.NARROW, unitWidth = UnitWidth.NARROW)
|
||||
location = location,
|
||||
modelProducer = modelProducer,
|
||||
theDay = daily.date,
|
||||
maxY = maxY,
|
||||
endAxisValueFormatter = remember {
|
||||
{ _, value, _ ->
|
||||
value.toTemperature(temperatureUnit)
|
||||
.formatMeasure(context, valueWidth = UnitWidth.NARROW, unitWidth = UnitWidth.NARROW)
|
||||
}
|
||||
},
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
// TODO: Duplicate of temperature colors
|
||||
47.celsius.toDouble(temperatureUnit).toFloat() to Color(71, 14, 0),
|
||||
30.celsius.toDouble(temperatureUnit).toFloat() to Color(232, 83, 25),
|
||||
21.celsius.toDouble(temperatureUnit).toFloat() to Color(243, 183, 4),
|
||||
10.celsius.toDouble(temperatureUnit).toFloat() to Color(128, 147, 24),
|
||||
1.celsius.toDouble(temperatureUnit).toFloat() to Color(68, 125, 99),
|
||||
0.celsius.toDouble(temperatureUnit).toFloat() to Color(93, 133, 198),
|
||||
-4.celsius.toDouble(temperatureUnit).toFloat() to Color(100, 166, 189),
|
||||
-8.celsius.toDouble(temperatureUnit).toFloat() to Color(106, 191, 181),
|
||||
-15.celsius.toDouble(temperatureUnit).toFloat() to Color(157, 219, 217),
|
||||
-25.celsius.toDouble(temperatureUnit).toFloat() to Color(143, 89, 169),
|
||||
-40.celsius.toDouble(temperatureUnit).toFloat() to Color(162, 70, 145),
|
||||
-55.celsius.toDouble(temperatureUnit).toFloat() to Color(202, 172, 195),
|
||||
-70.celsius.toDouble(temperatureUnit).toFloat() to Color(115, 70, 105)
|
||||
colors = remember {
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
// TODO: Duplicate of temperature colors
|
||||
47.celsius.toDouble(temperatureUnit).toFloat() to Color(71, 14, 0),
|
||||
30.celsius.toDouble(temperatureUnit).toFloat() to Color(232, 83, 25),
|
||||
21.celsius.toDouble(temperatureUnit).toFloat() to Color(243, 183, 4),
|
||||
10.celsius.toDouble(temperatureUnit).toFloat() to Color(128, 147, 24),
|
||||
1.celsius.toDouble(temperatureUnit).toFloat() to Color(68, 125, 99),
|
||||
0.celsius.toDouble(temperatureUnit).toFloat() to Color(93, 133, 198),
|
||||
-4.celsius.toDouble(temperatureUnit).toFloat() to Color(100, 166, 189),
|
||||
-8.celsius.toDouble(temperatureUnit).toFloat() to Color(106, 191, 181),
|
||||
-15.celsius.toDouble(temperatureUnit).toFloat() to Color(157, 219, 217),
|
||||
-25.celsius.toDouble(temperatureUnit).toFloat() to Color(143, 89, 169),
|
||||
-40.celsius.toDouble(temperatureUnit).toFloat() to Color(162, 70, 145),
|
||||
-55.celsius.toDouble(temperatureUnit).toFloat() to Color(202, 172, 195),
|
||||
-70.celsius.toDouble(temperatureUnit).toFloat() to Color(115, 70, 105)
|
||||
)
|
||||
)
|
||||
),
|
||||
topAxisValueFormatter = { _, value, _ ->
|
||||
mappedValues.getOrElse(value.toLong()) { null }?.formatMeasure(
|
||||
context,
|
||||
valueWidth = UnitWidth.NARROW,
|
||||
unitWidth = UnitWidth.NARROW
|
||||
) ?: "-"
|
||||
},
|
||||
topAxisValueFormatter = remember(mappedValues) {
|
||||
{ _, value, _ ->
|
||||
mappedValues.getOrElse(value.toLong()) { null }?.formatMeasure(
|
||||
context,
|
||||
valueWidth = UnitWidth.NARROW,
|
||||
unitWidth = UnitWidth.NARROW
|
||||
) ?: "-"
|
||||
}
|
||||
},
|
||||
minY = minY,
|
||||
endAxisItemPlacer = remember {
|
||||
VerticalAxis.ItemPlacer.step({ step })
|
||||
},
|
||||
endAxisItemPlacer = remember { VerticalAxis.ItemPlacer.step({ step }) },
|
||||
markerVisibilityListener = markerVisibilityListener
|
||||
)
|
||||
}
|
||||
|
|
|
@ -53,7 +53,6 @@ import breezyweather.domain.weather.model.PrecipitationDuration
|
|||
import breezyweather.domain.weather.model.PrecipitationProbability
|
||||
import com.patrykandpatrick.vico.core.cartesian.axis.VerticalAxis
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.lineSeries
|
||||
import com.patrykandpatrick.vico.core.cartesian.marker.CartesianMarker
|
||||
|
@ -66,6 +65,7 @@ import kotlinx.collections.immutable.persistentMapOf
|
|||
import kotlinx.collections.immutable.toImmutableMap
|
||||
import org.breezyweather.R
|
||||
import org.breezyweather.common.extensions.formatMeasure
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.formatTime
|
||||
import org.breezyweather.common.extensions.getFormattedTime
|
||||
import org.breezyweather.common.extensions.is12Hour
|
||||
|
@ -81,6 +81,8 @@ import org.breezyweather.unit.formatting.UnitWidth
|
|||
import org.breezyweather.unit.precipitation.Precipitation
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.precipitation.toPrecipitation
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import java.util.Date
|
||||
import kotlin.math.max
|
||||
import kotlin.time.Duration
|
||||
|
@ -128,7 +130,7 @@ fun DetailsPrecipitation(
|
|||
.associate { it.date.time to it.precipitationProbability!!.total!! }
|
||||
.toImmutableMap()
|
||||
}
|
||||
var activeProbabilityItem: Pair<Date, Double>? by remember { mutableStateOf(null) }
|
||||
var activeProbabilityItem: Pair<Date, Ratio>? by remember { mutableStateOf(null) }
|
||||
val probabilityMarkerVisibilityListener = remember {
|
||||
object : CartesianMarkerVisibilityListener {
|
||||
override fun onShown(marker: CartesianMarker, targets: List<CartesianMarker.Target>) {
|
||||
|
@ -366,47 +368,51 @@ internal fun PrecipitationChart(
|
|||
}
|
||||
|
||||
BreezyBarChart(
|
||||
location,
|
||||
modelProducer,
|
||||
daily.date,
|
||||
maxY,
|
||||
{ _, value, _ -> value.toPrecipitation(precipitationUnit).formatMeasure(context, precipitationUnit) },
|
||||
Fill(Color(60, 116, 160).toArgb()),
|
||||
/*persistentMapOf(
|
||||
50 to Fill(Color(168, 168, 168).toArgb()),
|
||||
31 to Fill(Color(161, 59, 161).toArgb()),
|
||||
20 to Fill(Color(161, 59, 59).toArgb()),
|
||||
15 to Fill(Color(161, 161, 59).toArgb()),
|
||||
10 to Fill(Color(130, 161, 59).toArgb()),
|
||||
8 to Fill(Color(59, 161, 61).toArgb()),
|
||||
6 to Fill(Color(59, 161, 161).toArgb()),
|
||||
0.6 to Fill(Color(60, 116, 160).toArgb()),
|
||||
0.0 to Fill(Color(111, 111, 111).toArgb())
|
||||
)*/
|
||||
trendHorizontalLines = buildMap {
|
||||
put(
|
||||
breezyweather.domain.weather.model.Precipitation.PRECIPITATION_HOURLY_HEAVY
|
||||
.millimeters.toDouble(precipitationUnit),
|
||||
context.getString(R.string.precipitation_intensity_heavy)
|
||||
)
|
||||
if (maxY < breezyweather.domain.weather.model.Precipitation.PRECIPITATION_HOURLY_HEAVY.times(2.0)
|
||||
.millimeters.toDouble(precipitationUnit)
|
||||
) {
|
||||
put(
|
||||
breezyweather.domain.weather.model.Precipitation.PRECIPITATION_HOURLY_MEDIUM
|
||||
.millimeters.toDouble(precipitationUnit),
|
||||
context.getString(R.string.precipitation_intensity_medium)
|
||||
)
|
||||
put(
|
||||
breezyweather.domain.weather.model.Precipitation.PRECIPITATION_HOURLY_LIGHT
|
||||
.millimeters.toDouble(precipitationUnit),
|
||||
context.getString(R.string.precipitation_intensity_light)
|
||||
)
|
||||
}
|
||||
}.toImmutableMap(),
|
||||
endAxisItemPlacer = remember {
|
||||
VerticalAxis.ItemPlacer.step({ step })
|
||||
location = location,
|
||||
modelProducer = modelProducer,
|
||||
theDay = daily.date,
|
||||
maxY = maxY,
|
||||
endAxisValueFormatter = remember {
|
||||
{ _, value, _ -> value.toPrecipitation(precipitationUnit).formatMeasure(context, precipitationUnit) }
|
||||
},
|
||||
barColorFill = remember { Fill(Color(60, 116, 160).toArgb()) },
|
||||
/*colors = remember {
|
||||
persistentMapOf(
|
||||
50 to Fill(Color(168, 168, 168).toArgb()),
|
||||
31 to Fill(Color(161, 59, 161).toArgb()),
|
||||
20 to Fill(Color(161, 59, 59).toArgb()),
|
||||
15 to Fill(Color(161, 161, 59).toArgb()),
|
||||
10 to Fill(Color(130, 161, 59).toArgb()),
|
||||
8 to Fill(Color(59, 161, 61).toArgb()),
|
||||
6 to Fill(Color(59, 161, 161).toArgb()),
|
||||
0.6 to Fill(Color(60, 116, 160).toArgb()),
|
||||
0.0 to Fill(Color(111, 111, 111).toArgb())
|
||||
)
|
||||
}*/
|
||||
trendHorizontalLines = remember {
|
||||
buildMap {
|
||||
put(
|
||||
breezyweather.domain.weather.model.Precipitation.PRECIPITATION_HOURLY_HEAVY
|
||||
.millimeters.toDouble(precipitationUnit),
|
||||
context.getString(R.string.precipitation_intensity_heavy)
|
||||
)
|
||||
if (maxY < breezyweather.domain.weather.model.Precipitation.PRECIPITATION_HOURLY_HEAVY.times(2.0)
|
||||
.millimeters.toDouble(precipitationUnit)
|
||||
) {
|
||||
put(
|
||||
breezyweather.domain.weather.model.Precipitation.PRECIPITATION_HOURLY_MEDIUM
|
||||
.millimeters.toDouble(precipitationUnit),
|
||||
context.getString(R.string.precipitation_intensity_medium)
|
||||
)
|
||||
put(
|
||||
breezyweather.domain.weather.model.Precipitation.PRECIPITATION_HOURLY_LIGHT
|
||||
.millimeters.toDouble(precipitationUnit),
|
||||
context.getString(R.string.precipitation_intensity_light)
|
||||
)
|
||||
}
|
||||
}.toImmutableMap()
|
||||
},
|
||||
endAxisItemPlacer = remember { VerticalAxis.ItemPlacer.step({ step }) },
|
||||
markerVisibilityListener = markerVisibilityListener
|
||||
)
|
||||
}
|
||||
|
@ -503,7 +509,7 @@ fun DailyPrecipitationDetail(
|
|||
fun PrecipitationProbabilityHeader(
|
||||
location: Location,
|
||||
daily: Daily,
|
||||
activeItem: Pair<Date, Double>?,
|
||||
activeItem: Pair<Date, Ratio>?,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
|
@ -523,7 +529,7 @@ fun PrecipitationProbabilityHeader(
|
|||
@Composable
|
||||
private fun PrecipitationProbabilityItem(
|
||||
header: @Composable () -> Unit,
|
||||
precipitationProbability: Double?,
|
||||
precipitationProbability: Ratio?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
@ -536,11 +542,11 @@ private fun PrecipitationProbabilityItem(
|
|||
} else {
|
||||
TextFixedHeight(
|
||||
text = "",
|
||||
style = MaterialTheme.typography.displaySmall
|
||||
style = MaterialTheme.typography.labelMedium
|
||||
)
|
||||
}
|
||||
TextFixedHeight(
|
||||
text = precipitationProbability?.let { pp -> UnitUtils.formatPercent(context, pp) } ?: "",
|
||||
text = precipitationProbability?.formatPercent(context) ?: "",
|
||||
style = MaterialTheme.typography.displaySmall
|
||||
)
|
||||
}
|
||||
|
@ -584,7 +590,7 @@ private fun PrecipitationProbabilitySummary(
|
|||
@Composable
|
||||
internal fun PrecipitationProbabilityChart(
|
||||
location: Location,
|
||||
mappedValues: ImmutableMap<Long, Double>,
|
||||
mappedValues: ImmutableMap<Long, Ratio>,
|
||||
daily: Daily,
|
||||
markerVisibilityListener: CartesianMarkerVisibilityListener,
|
||||
) {
|
||||
|
@ -592,10 +598,6 @@ internal fun PrecipitationProbabilityChart(
|
|||
|
||||
val maxY = 100.0
|
||||
|
||||
val endAxisValueFormatter = CartesianValueFormatter { _, value, _ ->
|
||||
UnitUtils.formatPercent(context, value)
|
||||
}
|
||||
|
||||
val modelProducer = remember { CartesianChartModelProducer() }
|
||||
|
||||
LaunchedEffect(location) {
|
||||
|
@ -603,28 +605,28 @@ internal fun PrecipitationProbabilityChart(
|
|||
lineSeries {
|
||||
series(
|
||||
x = mappedValues.keys,
|
||||
y = mappedValues.values
|
||||
y = mappedValues.values.map { it.inPercent }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BreezyLineChart(
|
||||
location,
|
||||
modelProducer,
|
||||
daily.date,
|
||||
maxY,
|
||||
endAxisValueFormatter,
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
// TODO
|
||||
100f to Color(60, 116, 160),
|
||||
0f to Color(60, 116, 160)
|
||||
location = location,
|
||||
modelProducer = modelProducer,
|
||||
theDay = daily.date,
|
||||
maxY = maxY,
|
||||
endAxisValueFormatter = remember { { _, value, _ -> value.percent.formatPercent(context) } },
|
||||
colors = remember {
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
// TODO
|
||||
100f to Color(60, 116, 160),
|
||||
0f to Color(60, 116, 160)
|
||||
)
|
||||
)
|
||||
),
|
||||
endAxisItemPlacer = remember {
|
||||
VerticalAxis.ItemPlacer.step({ 20.0 }) // Every 20 %
|
||||
},
|
||||
endAxisItemPlacer = remember { VerticalAxis.ItemPlacer.step({ 20.0 }) }, // Every 20 %
|
||||
markerVisibilityListener = markerVisibilityListener
|
||||
)
|
||||
}
|
||||
|
@ -634,22 +636,22 @@ internal fun PrecipitationProbabilityDetails(
|
|||
daytimePrecProb: PrecipitationProbability?,
|
||||
nighttimePrecProb: PrecipitationProbability?,
|
||||
) {
|
||||
val daytimePrecProbItems = mutableListOf<Pair<Int, Double?>>()
|
||||
val nighttimePrecProbItems = mutableListOf<Pair<Int, Double?>>()
|
||||
val daytimePrecProbItems = mutableListOf<Pair<Int, Ratio?>>()
|
||||
val nighttimePrecProbItems = mutableListOf<Pair<Int, Ratio?>>()
|
||||
|
||||
if ((daytimePrecProb?.rain ?: 0.0) > 0 || (nighttimePrecProb?.rain ?: 0.0) > 0) {
|
||||
if ((daytimePrecProb?.rain?.value ?: 0) > 0 || (nighttimePrecProb?.rain?.value ?: 0) > 0) {
|
||||
daytimePrecProbItems.add(Pair(R.string.precipitation_rain, daytimePrecProb?.rain))
|
||||
nighttimePrecProbItems.add(Pair(R.string.precipitation_rain, nighttimePrecProb?.rain))
|
||||
}
|
||||
if ((daytimePrecProb?.snow ?: 0.0) > 0 || (nighttimePrecProb?.snow ?: 0.0) > 0) {
|
||||
if ((daytimePrecProb?.snow?.value ?: 0) > 0 || (nighttimePrecProb?.snow?.value ?: 0) > 0) {
|
||||
daytimePrecProbItems.add(Pair(R.string.precipitation_snow, daytimePrecProb?.snow))
|
||||
nighttimePrecProbItems.add(Pair(R.string.precipitation_snow, nighttimePrecProb?.snow))
|
||||
}
|
||||
if ((daytimePrecProb?.ice ?: 0.0) > 0 || (nighttimePrecProb?.ice ?: 0.0) > 0) {
|
||||
if ((daytimePrecProb?.ice?.value ?: 0) > 0 || (nighttimePrecProb?.ice?.value ?: 0) > 0) {
|
||||
daytimePrecProbItems.add(Pair(R.string.precipitation_ice, daytimePrecProb?.ice))
|
||||
nighttimePrecProbItems.add(Pair(R.string.precipitation_ice, nighttimePrecProb?.ice))
|
||||
}
|
||||
if ((daytimePrecProb?.thunderstorm ?: 0.0) > 0 || (nighttimePrecProb?.thunderstorm ?: 0.0) > 0) {
|
||||
if ((daytimePrecProb?.thunderstorm?.value ?: 0) > 0 || (nighttimePrecProb?.thunderstorm?.value ?: 0) > 0) {
|
||||
daytimePrecProbItems.add(Pair(R.string.precipitation_thunderstorm, daytimePrecProb?.thunderstorm))
|
||||
nighttimePrecProbItems.add(Pair(R.string.precipitation_thunderstorm, nighttimePrecProb?.thunderstorm))
|
||||
}
|
||||
|
@ -689,15 +691,14 @@ internal fun PrecipitationProbabilityDetails(
|
|||
|
||||
@Composable
|
||||
internal fun DailyPrecipitationProbabilityDetail(
|
||||
item: Pair<Int, Double?>,
|
||||
item: Pair<Int, Ratio?>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
DetailsItem(
|
||||
headlineText = stringResource(item.first),
|
||||
supportingText = item.second?.let { pp -> UnitUtils.formatPercent(context, pp) }
|
||||
?: stringResource(R.string.null_data_text),
|
||||
supportingText = item.second?.formatPercent(context) ?: stringResource(R.string.null_data_text),
|
||||
modifier = modifier
|
||||
.padding(top = dimensionResource(R.dimen.normal_margin))
|
||||
.semantics(mergeDescendants = true) {}
|
||||
|
@ -705,7 +706,7 @@ internal fun DailyPrecipitationProbabilityDetail(
|
|||
item.second?.let { pp ->
|
||||
contentDescription = context.getString(item.first) +
|
||||
context.getString(R.string.colon_separator) +
|
||||
UnitUtils.formatPercent(context, pp)
|
||||
pp.formatPercent(context)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -247,60 +247,65 @@ private fun PressureChart(
|
|||
}
|
||||
|
||||
BreezyLineChart(
|
||||
location,
|
||||
modelProducer,
|
||||
daily.date,
|
||||
maxY,
|
||||
{ _, value, _ -> value.toPressure(pressureUnit).formatMeasure(context) },
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
1080.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(48, 8, 24),
|
||||
1046.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(111, 24, 64),
|
||||
1038.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(142, 47, 57),
|
||||
1030.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(159, 81, 44),
|
||||
1024.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(163, 116, 67),
|
||||
1019.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(167, 147, 107),
|
||||
1015.25.hectopascals.toDouble(pressureUnit).toFloat() to Color(176, 174, 152),
|
||||
1013.25.hectopascals.toDouble(pressureUnit).toFloat() to Color(182, 182, 182),
|
||||
1011.25.hectopascals.toDouble(pressureUnit).toFloat() to Color(155, 183, 172),
|
||||
1007.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(103, 162, 155),
|
||||
1002.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(26, 140, 147),
|
||||
995.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(0, 117, 146),
|
||||
986.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(0, 90, 148),
|
||||
976.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(0, 52, 146),
|
||||
950.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(0, 32, 96),
|
||||
900.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(8, 16, 48)
|
||||
location = location,
|
||||
modelProducer = modelProducer,
|
||||
theDay = daily.date,
|
||||
maxY = maxY,
|
||||
endAxisValueFormatter = remember { { _, value, _ -> value.toPressure(pressureUnit).formatMeasure(context) } },
|
||||
colors = remember {
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
1080.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(48, 8, 24),
|
||||
1046.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(111, 24, 64),
|
||||
1038.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(142, 47, 57),
|
||||
1030.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(159, 81, 44),
|
||||
1024.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(163, 116, 67),
|
||||
1019.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(167, 147, 107),
|
||||
1015.25.hectopascals.toDouble(pressureUnit).toFloat() to Color(176, 174, 152),
|
||||
1013.25.hectopascals.toDouble(pressureUnit).toFloat() to Color(182, 182, 182),
|
||||
1011.25.hectopascals.toDouble(pressureUnit).toFloat() to Color(155, 183, 172),
|
||||
1007.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(103, 162, 155),
|
||||
1002.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(26, 140, 147),
|
||||
995.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(0, 117, 146),
|
||||
986.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(0, 90, 148),
|
||||
976.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(0, 52, 146),
|
||||
950.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(0, 32, 96),
|
||||
900.0.hectopascals.toDouble(pressureUnit).toFloat() to Color(8, 16, 48)
|
||||
)
|
||||
)
|
||||
),
|
||||
trendHorizontalLines = persistentMapOf(
|
||||
PressureUnit.NORMAL.pascals.toDouble(pressureUnit) to stringResource(R.string.temperature_normal_short)
|
||||
),
|
||||
},
|
||||
trendHorizontalLines = remember {
|
||||
persistentMapOf(
|
||||
PressureUnit.NORMAL.pascals.toDouble(pressureUnit) to
|
||||
context.getString(R.string.temperature_normal_short)
|
||||
)
|
||||
},
|
||||
minY = minY,
|
||||
topAxisValueFormatter = { _, value, _ ->
|
||||
val currentIndex = mappedValues.keys.indexOfFirst { it == value.toLong() }.let {
|
||||
if (it == 0) 1 else it
|
||||
}
|
||||
val previousValue = if (currentIndex > 0) {
|
||||
mappedValues.values.elementAt(currentIndex - 1)
|
||||
} else {
|
||||
return@BreezyLineChart "-"
|
||||
}
|
||||
val currentValue = mappedValues.values.elementAt(currentIndex)
|
||||
val trend = with(currentValue.value - previousValue.value) {
|
||||
when {
|
||||
// Take into account the trend if the difference is of at least 0.5
|
||||
this >= 0.5 -> "↑"
|
||||
this <= -0.5 -> "↓"
|
||||
else -> "="
|
||||
topAxisValueFormatter = remember(mappedValues) {
|
||||
{ _, value, _ ->
|
||||
val currentIndex = mappedValues.keys.indexOfFirst { it == value.toLong() }.let {
|
||||
if (it == 0) 1 else it
|
||||
}
|
||||
if (currentIndex > 0) {
|
||||
val previousValue = mappedValues.values.elementAt(currentIndex - 1)
|
||||
val currentValue = mappedValues.values.elementAt(currentIndex)
|
||||
val trend = with(currentValue.value - previousValue.value) {
|
||||
when {
|
||||
// Take into account the trend if the difference is of at least 0.5
|
||||
this >= 0.5 -> "↑"
|
||||
this <= -0.5 -> "↓"
|
||||
else -> "="
|
||||
}
|
||||
}
|
||||
SpannableString(trend).apply {
|
||||
setSpan(RelativeSizeSpan(2f), 0, trend.length, 0)
|
||||
}
|
||||
} else {
|
||||
"-"
|
||||
}
|
||||
}
|
||||
SpannableString(trend).apply {
|
||||
setSpan(RelativeSizeSpan(2f), 0, trend.length, 0)
|
||||
}
|
||||
},
|
||||
endAxisItemPlacer = remember {
|
||||
VerticalAxis.ItemPlacer.step({ chartStep })
|
||||
},
|
||||
endAxisItemPlacer = remember { VerticalAxis.ItemPlacer.step({ chartStep }) },
|
||||
markerVisibilityListener = markerVisibilityListener
|
||||
)
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -64,6 +63,7 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import kotlinx.collections.immutable.toImmutableMap
|
||||
import org.breezyweather.R
|
||||
import org.breezyweather.common.extensions.getColorResource
|
||||
import org.breezyweather.common.extensions.getFormattedTime
|
||||
import org.breezyweather.common.extensions.is12Hour
|
||||
import org.breezyweather.common.extensions.toDate
|
||||
|
@ -267,33 +267,37 @@ private fun UVChart(
|
|||
}
|
||||
|
||||
BreezyLineChart(
|
||||
location,
|
||||
modelProducer,
|
||||
daily.date,
|
||||
maxY,
|
||||
{ _, value, _ -> UnitUtils.formatInt(context, value.roundToInt()) },
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
19f to Color(255, 255, 255),
|
||||
11f to colorResource(R.color.colorLevel_5),
|
||||
10f to colorResource(R.color.colorLevel_4),
|
||||
7f to colorResource(R.color.colorLevel_3),
|
||||
5f to colorResource(R.color.colorLevel_2),
|
||||
2f to colorResource(R.color.colorLevel_1),
|
||||
0f to Color(110, 110, 110)
|
||||
location = location,
|
||||
modelProducer = modelProducer,
|
||||
theDay = daily.date,
|
||||
maxY = maxY,
|
||||
endAxisValueFormatter = remember { { _, value, _ -> UnitUtils.formatInt(context, value.roundToInt()) } },
|
||||
colors = remember {
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
19f to Color(255, 255, 255),
|
||||
11f to context.getColorResource(R.color.colorLevel_5),
|
||||
10f to context.getColorResource(R.color.colorLevel_4),
|
||||
7f to context.getColorResource(R.color.colorLevel_3),
|
||||
5f to context.getColorResource(R.color.colorLevel_2),
|
||||
2f to context.getColorResource(R.color.colorLevel_1),
|
||||
0f to Color(110, 110, 110)
|
||||
)
|
||||
)
|
||||
),
|
||||
topAxisValueFormatter = { _, value, _ ->
|
||||
mappedValues.getOrElse(value.toLong()) { null }?.index?.roundToInt()
|
||||
?.let { UnitUtils.formatInt(context, it) }
|
||||
?: "-"
|
||||
},
|
||||
trendHorizontalLines = persistentMapOf(
|
||||
UV.UV_INDEX_MIDDLE to context.getString(R.string.uv_alert_level)
|
||||
),
|
||||
endAxisItemPlacer = remember {
|
||||
VerticalAxis.ItemPlacer.step({ 1.0 }) // Every rounded UVI
|
||||
topAxisValueFormatter = remember(mappedValues) {
|
||||
{ _, value, _ ->
|
||||
mappedValues.getOrElse(value.toLong()) { null }?.index?.roundToInt()
|
||||
?.let { UnitUtils.formatInt(context, it) }
|
||||
?: "-"
|
||||
}
|
||||
},
|
||||
trendHorizontalLines = remember {
|
||||
persistentMapOf(
|
||||
UV.UV_INDEX_MIDDLE to context.getString(R.string.uv_alert_level)
|
||||
)
|
||||
},
|
||||
endAxisItemPlacer = remember { VerticalAxis.ItemPlacer.step({ 1.0 }) }, // Every rounded UVI
|
||||
markerVisibilityListener = markerVisibilityListener
|
||||
)
|
||||
}
|
||||
|
|
|
@ -312,30 +312,32 @@ private fun VisibilityChart(
|
|||
}
|
||||
|
||||
BreezyLineChart(
|
||||
location,
|
||||
modelProducer,
|
||||
daily.date,
|
||||
maxYRounded,
|
||||
{ _, value, _ -> value.toDistance(distanceUnit).formatMeasure(context) },
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
20000.meters.toDouble(distanceUnit).toFloat() to Color(119, 141, 120),
|
||||
15000.meters.toDouble(distanceUnit).toFloat() to Color(91, 167, 99),
|
||||
9000.meters.toDouble(distanceUnit).toFloat() to Color(90, 169, 90),
|
||||
8000.meters.toDouble(distanceUnit).toFloat() to Color(98, 122, 160),
|
||||
6000.meters.toDouble(distanceUnit).toFloat() to Color(98, 122, 160),
|
||||
5000.meters.toDouble(distanceUnit).toFloat() to Color(167, 91, 91),
|
||||
2200.meters.toDouble(distanceUnit).toFloat() to Color(167, 91, 91),
|
||||
1600.meters.toDouble(distanceUnit).toFloat() to Color(162, 97, 160),
|
||||
0.meters.toDouble(distanceUnit).toFloat() to Color(166, 93, 165)
|
||||
location = location,
|
||||
modelProducer = modelProducer,
|
||||
theDay = daily.date,
|
||||
maxY = maxYRounded,
|
||||
endAxisValueFormatter = remember { { _, value, _ -> value.toDistance(distanceUnit).formatMeasure(context) } },
|
||||
colors = remember {
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
20000.meters.toDouble(distanceUnit).toFloat() to Color(119, 141, 120),
|
||||
15000.meters.toDouble(distanceUnit).toFloat() to Color(91, 167, 99),
|
||||
9000.meters.toDouble(distanceUnit).toFloat() to Color(90, 169, 90),
|
||||
8000.meters.toDouble(distanceUnit).toFloat() to Color(98, 122, 160),
|
||||
6000.meters.toDouble(distanceUnit).toFloat() to Color(98, 122, 160),
|
||||
5000.meters.toDouble(distanceUnit).toFloat() to Color(167, 91, 91),
|
||||
2200.meters.toDouble(distanceUnit).toFloat() to Color(167, 91, 91),
|
||||
1600.meters.toDouble(distanceUnit).toFloat() to Color(162, 97, 160),
|
||||
0.meters.toDouble(distanceUnit).toFloat() to Color(166, 93, 165)
|
||||
)
|
||||
)
|
||||
),
|
||||
topAxisValueFormatter = { _, value, _ ->
|
||||
mappedValues.getOrElse(value.toLong()) { null }?.formatValue(context) ?: "-"
|
||||
},
|
||||
endAxisItemPlacer = remember {
|
||||
VerticalAxis.ItemPlacer.step({ step })
|
||||
topAxisValueFormatter = remember(mappedValues) {
|
||||
{ _, value, _ ->
|
||||
mappedValues.getOrElse(value.toLong()) { null }?.formatValue(context) ?: "-"
|
||||
}
|
||||
},
|
||||
endAxisItemPlacer = remember { VerticalAxis.ItemPlacer.step({ step }) },
|
||||
markerVisibilityListener = markerVisibilityListener
|
||||
)
|
||||
}
|
||||
|
|
|
@ -42,7 +42,6 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -73,6 +72,7 @@ import org.breezyweather.common.extensions.currentLocale
|
|||
import org.breezyweather.common.extensions.formatMeasure
|
||||
import org.breezyweather.common.extensions.getBeaufortScaleColor
|
||||
import org.breezyweather.common.extensions.getBeaufortScaleStrength
|
||||
import org.breezyweather.common.extensions.getColorResource
|
||||
import org.breezyweather.common.extensions.getFormattedTime
|
||||
import org.breezyweather.common.extensions.is12Hour
|
||||
import org.breezyweather.common.extensions.roundUpToNearestMultiplier
|
||||
|
@ -354,88 +354,105 @@ private fun WindChart(
|
|||
}
|
||||
|
||||
BreezyLineChart(
|
||||
location,
|
||||
modelProducer,
|
||||
daily.date,
|
||||
maxY,
|
||||
{ _, value, _ -> value.toSpeed(speedUnit).formatMeasure(context) },
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
104.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(128, 128, 128),
|
||||
77.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(205, 202, 112),
|
||||
51.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(219, 212, 135),
|
||||
46.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(231, 215, 215),
|
||||
36.0.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf12),
|
||||
30.5.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf11),
|
||||
26.4.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf10),
|
||||
24.475.metersPerSecond.toDouble(speedUnit).toFloat() to Color(109, 97, 163),
|
||||
22.55.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf9),
|
||||
18.9.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf8),
|
||||
17.175.metersPerSecond.toDouble(speedUnit).toFloat() to Color(129, 58, 78),
|
||||
15.45.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf7),
|
||||
13.85.metersPerSecond.toDouble(speedUnit).toFloat() to Color(159, 127, 58),
|
||||
12.25.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf6),
|
||||
9.3.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf5),
|
||||
6.7.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf4),
|
||||
4.4.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf3),
|
||||
2.4.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf2),
|
||||
1.0.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf1),
|
||||
0.0.metersPerSecond.toDouble(speedUnit).toFloat() to colorResource(R.color.windStrength_bf0)
|
||||
),
|
||||
persistentMapOf(
|
||||
104.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(128, 128, 128, 160),
|
||||
77.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(205, 202, 112, 160),
|
||||
51.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(219, 212, 135, 160),
|
||||
46.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(231, 215, 215, 160),
|
||||
36.0.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf12).copy(alpha = 160f.div(255f)),
|
||||
30.5.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf11).copy(alpha = 160f.div(255f)),
|
||||
26.4.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf10).copy(alpha = 160f.div(255f)),
|
||||
24.475.metersPerSecond.toDouble(speedUnit).toFloat() to Color(109, 97, 163, 160),
|
||||
22.55.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf9).copy(alpha = 160f.div(255f)),
|
||||
18.9.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf8).copy(alpha = 160f.div(255f)),
|
||||
17.175.metersPerSecond.toDouble(speedUnit).toFloat() to Color(129, 58, 78, 160),
|
||||
15.45.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf7).copy(alpha = 160f.div(255f)),
|
||||
13.85.metersPerSecond.toDouble(speedUnit).toFloat() to Color(159, 127, 58, 160),
|
||||
12.25.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf6).copy(alpha = 160f.div(255f)),
|
||||
9.3.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf5).copy(alpha = 160f.div(255f)),
|
||||
6.7.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf4).copy(alpha = 160f.div(255f)),
|
||||
4.4.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf3).copy(alpha = 160f.div(255f)),
|
||||
2.4.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf2).copy(alpha = 160f.div(255f)),
|
||||
1.0.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf1).copy(alpha = 160f.div(255f)),
|
||||
0.0.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
colorResource(R.color.windStrength_bf0).copy(alpha = 160f.div(255f))
|
||||
location = location,
|
||||
modelProducer = modelProducer,
|
||||
theDay = daily.date,
|
||||
maxY = maxY,
|
||||
endAxisValueFormatter = remember { { _, value, _ -> value.toSpeed(speedUnit).formatMeasure(context) } },
|
||||
colors = remember {
|
||||
persistentListOf(
|
||||
persistentMapOf(
|
||||
104.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(128, 128, 128),
|
||||
77.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(205, 202, 112),
|
||||
51.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(219, 212, 135),
|
||||
46.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(231, 215, 215),
|
||||
36.0.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf12),
|
||||
30.5.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf11),
|
||||
26.4.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf10),
|
||||
24.475.metersPerSecond.toDouble(speedUnit).toFloat() to Color(109, 97, 163),
|
||||
22.55.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf9),
|
||||
18.9.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf8),
|
||||
17.175.metersPerSecond.toDouble(speedUnit).toFloat() to Color(129, 58, 78),
|
||||
15.45.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf7),
|
||||
13.85.metersPerSecond.toDouble(speedUnit).toFloat() to Color(159, 127, 58),
|
||||
12.25.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf6),
|
||||
9.3.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf5),
|
||||
6.7.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf4),
|
||||
4.4.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf3),
|
||||
2.4.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf2),
|
||||
1.0.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf1),
|
||||
0.0.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf0)
|
||||
),
|
||||
persistentMapOf(
|
||||
104.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(128, 128, 128, 160),
|
||||
77.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(205, 202, 112, 160),
|
||||
51.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(219, 212, 135, 160),
|
||||
46.0.metersPerSecond.toDouble(speedUnit).toFloat() to Color(231, 215, 215, 160),
|
||||
36.0.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf12).copy(alpha = 160f.div(255f)),
|
||||
30.5.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf11).copy(alpha = 160f.div(255f)),
|
||||
26.4.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf10).copy(alpha = 160f.div(255f)),
|
||||
24.475.metersPerSecond.toDouble(speedUnit).toFloat() to Color(109, 97, 163, 160),
|
||||
22.55.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf9).copy(alpha = 160f.div(255f)),
|
||||
18.9.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf8).copy(alpha = 160f.div(255f)),
|
||||
17.175.metersPerSecond.toDouble(speedUnit).toFloat() to Color(129, 58, 78, 160),
|
||||
15.45.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf7).copy(alpha = 160f.div(255f)),
|
||||
13.85.metersPerSecond.toDouble(speedUnit).toFloat() to Color(159, 127, 58, 160),
|
||||
12.25.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf6).copy(alpha = 160f.div(255f)),
|
||||
9.3.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf5).copy(alpha = 160f.div(255f)),
|
||||
6.7.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf4).copy(alpha = 160f.div(255f)),
|
||||
4.4.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf3).copy(alpha = 160f.div(255f)),
|
||||
2.4.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf2).copy(alpha = 160f.div(255f)),
|
||||
1.0.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf1).copy(alpha = 160f.div(255f)),
|
||||
0.0.metersPerSecond.toDouble(speedUnit).toFloat() to
|
||||
context.getColorResource(R.color.windStrength_bf0).copy(alpha = 160f.div(255f))
|
||||
)
|
||||
)
|
||||
),
|
||||
topAxisValueFormatter = { _, value, _ ->
|
||||
val arrow = mappedValues.getOrElse(value.toLong()) { null }?.arrow ?: "-"
|
||||
SpannableString(arrow).apply {
|
||||
setSpan(RelativeSizeSpan(2f), 0, arrow.length, 0)
|
||||
},
|
||||
topAxisValueFormatter = remember(mappedValues) {
|
||||
{ _, value, _ ->
|
||||
val arrow = mappedValues.getOrElse(value.toLong()) { null }?.arrow ?: "-"
|
||||
SpannableString(arrow).apply {
|
||||
setSpan(RelativeSizeSpan(2f), 0, arrow.length, 0)
|
||||
}
|
||||
}
|
||||
},
|
||||
trendHorizontalLines = buildMap {
|
||||
if (maxY > 7.beaufort.toDouble(speedUnit)) {
|
||||
put(7.beaufort.toDouble(speedUnit), 7.beaufort.getBeaufortScaleStrength(context)!!)
|
||||
}
|
||||
// TODO: Make this a const:
|
||||
if (maxY < (7.beaufort.inMetersPerSecond + 5.0).metersPerSecond.toDouble(speedUnit)) {
|
||||
put(3.beaufort.toDouble(speedUnit), 3.beaufort.getBeaufortScaleStrength(context)!!)
|
||||
}
|
||||
}.toImmutableMap(),
|
||||
endAxisItemPlacer = remember {
|
||||
VerticalAxis.ItemPlacer.step({ step })
|
||||
trendHorizontalLines = remember {
|
||||
buildMap {
|
||||
if (maxY > 7.beaufort.toDouble(speedUnit)) {
|
||||
put(7.beaufort.toDouble(speedUnit), 7.beaufort.getBeaufortScaleStrength(context)!!)
|
||||
}
|
||||
// TODO: Make this a const:
|
||||
if (maxY < (7.beaufort.inMetersPerSecond + 5.0).metersPerSecond.toDouble(speedUnit)) {
|
||||
put(3.beaufort.toDouble(speedUnit), 3.beaufort.getBeaufortScaleStrength(context)!!)
|
||||
}
|
||||
}.toImmutableMap()
|
||||
},
|
||||
endAxisItemPlacer = remember { VerticalAxis.ItemPlacer.step({ step }) },
|
||||
markerVisibilityListener = markerVisibilityListener
|
||||
)
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ import breezyweather.domain.location.model.Location
|
|||
import org.breezyweather.R
|
||||
import org.breezyweather.common.activities.BreezyActivity
|
||||
import org.breezyweather.common.extensions.formatMeasure
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.options.appearance.DetailScreen
|
||||
import org.breezyweather.common.utils.UnitUtils
|
||||
import org.breezyweather.common.utils.helpers.IntentHelper
|
||||
import org.breezyweather.ui.theme.resource.providers.ResourceProvider
|
||||
import org.breezyweather.unit.formatting.UnitWidth
|
||||
|
@ -50,13 +50,13 @@ class HumidityViewHolder(parent: ViewGroup) : AbstractMainCardViewHolder(
|
|||
val talkBackBuilder = StringBuilder(context.getString(R.string.humidity))
|
||||
location.weather!!.current?.let { current ->
|
||||
current.relativeHumidity?.let { relativeHumidity ->
|
||||
humidityValueView.text = UnitUtils.formatPercent(context, relativeHumidity)
|
||||
humidityValueView.text = relativeHumidity.formatPercent(context, UnitWidth.NARROW)
|
||||
|
||||
if (relativeHumidity in 0.0..100.0) {
|
||||
if (relativeHumidity.inPercent in 0.0..100.0) {
|
||||
wavesBackgroundView.setImageDrawable(
|
||||
AppCompatResources.getDrawable(
|
||||
context,
|
||||
when (relativeHumidity) {
|
||||
when (relativeHumidity.inPercent) {
|
||||
in 0.0..20.0 -> R.drawable.humidity_percent_7
|
||||
in 20.0..40.0 -> R.drawable.humidity_percent_30
|
||||
in 60.0..80.0 -> R.drawable.humidity_percent_75
|
||||
|
|
|
@ -158,7 +158,7 @@ class DailyPrecipitationAdapter(
|
|||
val keyLineList = mutableListOf<TrendRecyclerView.KeyLine>()
|
||||
keyLineList.add(
|
||||
TrendRecyclerView.KeyLine(
|
||||
Precipitation.PRECIPITATION_HALF_DAY_LIGHT.toFloat(),
|
||||
Precipitation.PRECIPITATION_HALF_DAY_LIGHT.millimeters.inMicrometers.toFloat(),
|
||||
Precipitation.PRECIPITATION_HALF_DAY_LIGHT.millimeters.formatValue(activity),
|
||||
activity.getString(R.string.precipitation_intensity_light),
|
||||
TrendRecyclerView.KeyLine.ContentPosition.ABOVE_LINE
|
||||
|
@ -166,7 +166,7 @@ class DailyPrecipitationAdapter(
|
|||
)
|
||||
keyLineList.add(
|
||||
TrendRecyclerView.KeyLine(
|
||||
Precipitation.PRECIPITATION_HALF_DAY_HEAVY.toFloat(),
|
||||
Precipitation.PRECIPITATION_HALF_DAY_HEAVY.millimeters.inMicrometers.toFloat(),
|
||||
Precipitation.PRECIPITATION_HALF_DAY_HEAVY.millimeters.formatValue(activity),
|
||||
activity.getString(R.string.precipitation_intensity_heavy),
|
||||
TrendRecyclerView.KeyLine.ContentPosition.ABOVE_LINE
|
||||
|
@ -174,7 +174,7 @@ class DailyPrecipitationAdapter(
|
|||
)
|
||||
keyLineList.add(
|
||||
TrendRecyclerView.KeyLine(
|
||||
-Precipitation.PRECIPITATION_HALF_DAY_LIGHT.toFloat(),
|
||||
-Precipitation.PRECIPITATION_HALF_DAY_LIGHT.millimeters.inMicrometers.toFloat(),
|
||||
Precipitation.PRECIPITATION_HALF_DAY_LIGHT.millimeters.formatValue(activity),
|
||||
activity.getString(R.string.precipitation_intensity_light),
|
||||
TrendRecyclerView.KeyLine.ContentPosition.BELOW_LINE
|
||||
|
@ -182,7 +182,7 @@ class DailyPrecipitationAdapter(
|
|||
)
|
||||
keyLineList.add(
|
||||
TrendRecyclerView.KeyLine(
|
||||
-Precipitation.PRECIPITATION_HALF_DAY_HEAVY.toFloat(),
|
||||
-Precipitation.PRECIPITATION_HALF_DAY_HEAVY.millimeters.inMicrometers.toFloat(),
|
||||
Precipitation.PRECIPITATION_HALF_DAY_HEAVY.millimeters.formatValue(activity),
|
||||
activity.getString(R.string.precipitation_intensity_heavy),
|
||||
TrendRecyclerView.KeyLine.ContentPosition.BELOW_LINE
|
||||
|
|
|
@ -26,6 +26,7 @@ import breezyweather.domain.location.model.Location
|
|||
import org.breezyweather.R
|
||||
import org.breezyweather.common.activities.BreezyActivity
|
||||
import org.breezyweather.common.extensions.formatMeasure
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.getCalendarMonth
|
||||
import org.breezyweather.common.extensions.getThemeColor
|
||||
import org.breezyweather.common.options.appearance.DetailScreen
|
||||
|
@ -84,7 +85,7 @@ class DailyTemperatureAdapter(
|
|||
talkBackBuilder.append(activity.getString(org.breezyweather.unit.R.string.locale_separator))
|
||||
.append(activity.getString(R.string.precipitation_probability))
|
||||
.append(activity.getString(R.string.colon_separator))
|
||||
.append(UnitUtils.formatPercent(activity, p))
|
||||
.append(p.formatPercent(activity))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +105,7 @@ class DailyTemperatureAdapter(
|
|||
talkBackBuilder.append(activity.getString(org.breezyweather.unit.R.string.locale_separator))
|
||||
.append(activity.getString(R.string.precipitation_probability))
|
||||
.append(activity.getString(R.string.colon_separator))
|
||||
.append(UnitUtils.formatPercent(activity, p))
|
||||
.append(p.formatPercent(activity))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,15 +113,10 @@ class DailyTemperatureAdapter(
|
|||
daily.day?.weatherCode?.let { ResourceHelper.getWeatherIcon(mResourceProvider, it, true) },
|
||||
missingIconVisibility = View.INVISIBLE
|
||||
)
|
||||
val daytimePrecipitationProbability = daily.day?.precipitationProbability?.total?.toFloat()
|
||||
val nighttimePrecipitationProbability = daily.night?.precipitationProbability?.total?.toFloat()
|
||||
var p: Float = max(
|
||||
daytimePrecipitationProbability ?: 0f,
|
||||
nighttimePrecipitationProbability ?: 0f
|
||||
)
|
||||
if (!mShowPrecipitationProbability) {
|
||||
p = 0f
|
||||
}
|
||||
val daytimePrecipitationProbability = daily.day?.precipitationProbability?.total
|
||||
val nighttimePrecipitationProbability = daily.night?.precipitationProbability?.total
|
||||
val p = listOfNotNull(daytimePrecipitationProbability, nighttimePrecipitationProbability)
|
||||
.takeIf { it.isNotEmpty() }?.maxBy { it.value }
|
||||
mPolylineAndHistogramView.setData(
|
||||
buildTemperatureArrayForItem(mDaytimeTemperatures, position),
|
||||
buildTemperatureArrayForItem(mNighttimeTemperatures, position),
|
||||
|
@ -136,12 +132,8 @@ class DailyTemperatureAdapter(
|
|||
),
|
||||
mHighestTemperature,
|
||||
mLowestTemperature,
|
||||
if (p > 0) p else null,
|
||||
if (p > 0) {
|
||||
UnitUtils.formatPercent(activity, p.toDouble())
|
||||
} else {
|
||||
null
|
||||
},
|
||||
p?.takeIf { it.value > 0 && mShowPrecipitationProbability }?.inPercent?.toFloat(),
|
||||
p?.takeIf { it.value > 0 && mShowPrecipitationProbability }?.formatPercent(activity, UnitWidth.NARROW),
|
||||
100f,
|
||||
0f
|
||||
)
|
||||
|
|
|
@ -18,22 +18,26 @@ package org.breezyweather.ui.main.adapters.trend.hourly
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import breezyweather.domain.location.model.Location
|
||||
import org.breezyweather.R
|
||||
import org.breezyweather.common.activities.BreezyActivity
|
||||
import org.breezyweather.common.extensions.CLOUD_COVER_FEW
|
||||
import org.breezyweather.common.extensions.CLOUD_COVER_SCT
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.getCloudCoverColor
|
||||
import org.breezyweather.common.extensions.getCloudCoverDescription
|
||||
import org.breezyweather.common.extensions.getThemeColor
|
||||
import org.breezyweather.common.options.appearance.DetailScreen
|
||||
import org.breezyweather.common.utils.UnitUtils
|
||||
import org.breezyweather.domain.weather.model.CLOUD_COVER_CLEAR
|
||||
import org.breezyweather.domain.weather.model.CLOUD_COVER_PARTLY
|
||||
import org.breezyweather.domain.weather.model.getCloudCoverColor
|
||||
import org.breezyweather.ui.common.widgets.trend.TrendRecyclerView
|
||||
import org.breezyweather.ui.common.widgets.trend.chart.PolylineAndHistogramView
|
||||
import org.breezyweather.ui.theme.ThemeManager
|
||||
import org.breezyweather.ui.theme.weatherView.WeatherViewController
|
||||
import org.breezyweather.unit.formatting.UnitWidth
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
|
||||
/**
|
||||
* Hourly Cloud Cover adapter.
|
||||
|
@ -60,7 +64,7 @@ class HourlyCloudCoverAdapter(
|
|||
hourly.cloudCover?.let { cloudCover ->
|
||||
talkBackBuilder
|
||||
.append(activity.getString(org.breezyweather.unit.R.string.locale_separator))
|
||||
.append(UnitUtils.formatPercent(activity, cloudCover.toDouble()))
|
||||
.append(cloudCover.formatPercent(activity, UnitWidth.NARROW))
|
||||
}
|
||||
mPolylineAndHistogramView.setData(
|
||||
null,
|
||||
|
@ -69,14 +73,14 @@ class HourlyCloudCoverAdapter(
|
|||
null,
|
||||
null,
|
||||
null,
|
||||
hourly.cloudCover?.toFloat() ?: 0f,
|
||||
hourly.cloudCover?.let { UnitUtils.formatPercent(activity, it.toDouble()) },
|
||||
hourly.cloudCover?.inPercent?.toFloat() ?: 0f,
|
||||
hourly.cloudCover?.formatPercent(activity, UnitWidth.NARROW),
|
||||
100f,
|
||||
0f
|
||||
)
|
||||
mPolylineAndHistogramView.setLineColors(
|
||||
hourly.getCloudCoverColor(activity),
|
||||
hourly.getCloudCoverColor(activity),
|
||||
hourly.cloudCover?.getCloudCoverColor(activity) ?: Color.TRANSPARENT,
|
||||
hourly.cloudCover?.getCloudCoverColor(activity) ?: Color.TRANSPARENT,
|
||||
activity.getThemeColor(com.google.android.material.R.attr.colorOutline)
|
||||
)
|
||||
|
||||
|
@ -108,7 +112,7 @@ class HourlyCloudCoverAdapter(
|
|||
|
||||
init {
|
||||
mHighestCloudCover = location.weather!!.nextHourlyForecast
|
||||
.mapNotNull { it.cloudCover }
|
||||
.mapNotNull { it.cloudCover?.inPercent }
|
||||
.maxOrNull()
|
||||
?.toFloat() ?: 0f
|
||||
}
|
||||
|
@ -132,18 +136,18 @@ class HourlyCloudCoverAdapter(
|
|||
val keyLineList = mutableListOf<TrendRecyclerView.KeyLine>()
|
||||
keyLineList.add(
|
||||
TrendRecyclerView.KeyLine(
|
||||
CLOUD_COVER_PARTLY.toFloat(),
|
||||
UnitUtils.formatPercent(activity, CLOUD_COVER_PARTLY),
|
||||
activity.getString(R.string.weather_kind_partly_cloudy),
|
||||
CLOUD_COVER_FEW.toFloat(),
|
||||
CLOUD_COVER_FEW.percent.formatPercent(activity),
|
||||
CLOUD_COVER_FEW.percent.getCloudCoverDescription(activity),
|
||||
TrendRecyclerView.KeyLine.ContentPosition.ABOVE_LINE
|
||||
)
|
||||
)
|
||||
keyLineList.add(
|
||||
TrendRecyclerView.KeyLine(
|
||||
CLOUD_COVER_CLEAR.toFloat(),
|
||||
UnitUtils.formatPercent(activity, CLOUD_COVER_CLEAR),
|
||||
activity.getString(R.string.weather_kind_clear),
|
||||
TrendRecyclerView.KeyLine.ContentPosition.BELOW_LINE
|
||||
CLOUD_COVER_SCT.toFloat(),
|
||||
CLOUD_COVER_SCT.percent.formatPercent(activity),
|
||||
CLOUD_COVER_SCT.percent.getCloudCoverDescription(activity),
|
||||
TrendRecyclerView.KeyLine.ContentPosition.ABOVE_LINE
|
||||
)
|
||||
)
|
||||
host.setData(keyLineList, 100f, 0f)
|
||||
|
|
|
@ -25,6 +25,7 @@ import breezyweather.domain.location.model.Location
|
|||
import org.breezyweather.R
|
||||
import org.breezyweather.common.activities.BreezyActivity
|
||||
import org.breezyweather.common.extensions.formatMeasure
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.getThemeColor
|
||||
import org.breezyweather.common.options.appearance.DetailScreen
|
||||
import org.breezyweather.common.utils.UnitUtils
|
||||
|
@ -66,7 +67,7 @@ class HourlyHumidityAdapter(
|
|||
talkBackBuilder.append(activity.getString(org.breezyweather.unit.R.string.locale_separator))
|
||||
.append(activity.getString(R.string.humidity))
|
||||
.append(activity.getString(R.string.colon_separator))
|
||||
.append(UnitUtils.formatPercent(activity, it))
|
||||
.append(it.formatPercent(activity))
|
||||
}
|
||||
hourly.dewPoint?.let {
|
||||
talkBackBuilder.append(activity.getString(org.breezyweather.unit.R.string.locale_separator))
|
||||
|
@ -91,8 +92,8 @@ class HourlyHumidityAdapter(
|
|||
null,
|
||||
mHighestDewPoint,
|
||||
mLowestDewPoint,
|
||||
hourly.relativeHumidity?.toFloat(),
|
||||
hourly.relativeHumidity?.let { UnitUtils.formatPercent(activity, it) },
|
||||
hourly.relativeHumidity?.inPercent?.toFloat(),
|
||||
hourly.relativeHumidity?.formatPercent(activity, UnitWidth.NARROW),
|
||||
100f,
|
||||
0f
|
||||
)
|
||||
|
|
|
@ -155,7 +155,7 @@ class HourlyPrecipitationAdapter(
|
|||
val keyLineList = mutableListOf<TrendRecyclerView.KeyLine>()
|
||||
keyLineList.add(
|
||||
TrendRecyclerView.KeyLine(
|
||||
Precipitation.PRECIPITATION_HOURLY_LIGHT.toFloat(),
|
||||
Precipitation.PRECIPITATION_HOURLY_LIGHT.millimeters.inMicrometers.toFloat(),
|
||||
activity.getString(R.string.precipitation_intensity_light),
|
||||
Precipitation.PRECIPITATION_HALF_DAY_LIGHT.millimeters.formatValue(activity),
|
||||
TrendRecyclerView.KeyLine.ContentPosition.ABOVE_LINE
|
||||
|
@ -163,7 +163,7 @@ class HourlyPrecipitationAdapter(
|
|||
)
|
||||
keyLineList.add(
|
||||
TrendRecyclerView.KeyLine(
|
||||
Precipitation.PRECIPITATION_HOURLY_HEAVY.toFloat(),
|
||||
Precipitation.PRECIPITATION_HOURLY_HEAVY.millimeters.inMicrometers.toFloat(),
|
||||
activity.getString(R.string.precipitation_intensity_heavy),
|
||||
Precipitation.PRECIPITATION_HALF_DAY_HEAVY.millimeters.formatValue(activity),
|
||||
TrendRecyclerView.KeyLine.ContentPosition.ABOVE_LINE
|
||||
|
|
|
@ -25,10 +25,10 @@ import breezyweather.domain.location.model.Location
|
|||
import org.breezyweather.R
|
||||
import org.breezyweather.common.activities.BreezyActivity
|
||||
import org.breezyweather.common.extensions.formatMeasure
|
||||
import org.breezyweather.common.extensions.formatPercent
|
||||
import org.breezyweather.common.extensions.getCalendarMonth
|
||||
import org.breezyweather.common.extensions.getThemeColor
|
||||
import org.breezyweather.common.options.appearance.DetailScreen
|
||||
import org.breezyweather.common.utils.UnitUtils
|
||||
import org.breezyweather.ui.common.widgets.trend.TrendRecyclerView
|
||||
import org.breezyweather.ui.common.widgets.trend.chart.PolylineAndHistogramView
|
||||
import org.breezyweather.ui.theme.ThemeManager
|
||||
|
@ -80,15 +80,12 @@ class HourlyTemperatureAdapter(
|
|||
},
|
||||
missingIconVisibility = View.INVISIBLE
|
||||
)
|
||||
val precipitationProbability = hourly.precipitationProbability?.total
|
||||
var p: Float = precipitationProbability?.toFloat() ?: 0f
|
||||
if (!mShowPrecipitationProbability) {
|
||||
p = 0f
|
||||
} else if (hourly.precipitationProbability?.total != null) {
|
||||
val p = hourly.precipitationProbability?.total
|
||||
if (mShowPrecipitationProbability && hourly.precipitationProbability?.total != null) {
|
||||
talkBackBuilder.append(activity.getString(org.breezyweather.unit.R.string.locale_separator))
|
||||
.append(activity.getString(R.string.precipitation_probability))
|
||||
.append(activity.getString(R.string.colon_separator))
|
||||
.append(UnitUtils.formatPercent(activity, p.toDouble()))
|
||||
.append(hourly.precipitationProbability!!.total!!.formatPercent(activity, UnitWidth.NARROW))
|
||||
}
|
||||
mPolylineAndHistogramView.setData(
|
||||
buildTemperatureArrayForItem(mTemperatures, position),
|
||||
|
@ -101,12 +98,8 @@ class HourlyTemperatureAdapter(
|
|||
null,
|
||||
mHighestTemperature,
|
||||
mLowestTemperature,
|
||||
if (p > 0) p else null,
|
||||
if (p > 0) {
|
||||
UnitUtils.formatPercent(activity, p.toDouble())
|
||||
} else {
|
||||
null
|
||||
},
|
||||
p?.takeIf { it.value > 0 && mShowPrecipitationProbability }?.inPercent?.toFloat(),
|
||||
p?.takeIf { it.value > 0 && mShowPrecipitationProbability }?.formatPercent(activity, UnitWidth.NARROW),
|
||||
100f,
|
||||
0f
|
||||
)
|
||||
|
|
|
@ -98,6 +98,7 @@ import org.breezyweather.unit.precipitation.Precipitation.Companion.inches
|
|||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.precipitation.PrecipitationUnit
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.speed.Speed.Companion.milesPerHour
|
||||
|
@ -432,10 +433,10 @@ class AccuService @Inject constructor(
|
|||
gusts = currentResult.WindGust?.Speed?.Metric?.Value?.kilometersPerHour
|
||||
),
|
||||
uV = UV(index = currentResult.UVIndex?.toDouble()),
|
||||
relativeHumidity = currentResult.RelativeHumidity?.toDouble(),
|
||||
relativeHumidity = currentResult.RelativeHumidity?.percent,
|
||||
dewPoint = currentResult.DewPoint?.Metric?.Value?.celsius,
|
||||
pressure = currentResult.Pressure?.Metric?.Value?.hectopascals,
|
||||
cloudCover = currentResult.CloudCover,
|
||||
cloudCover = currentResult.CloudCover?.percent,
|
||||
visibility = currentResult.Visibility?.Metric?.Value?.kilometers,
|
||||
ceiling = currentResult.Ceiling?.Metric?.Value?.meters,
|
||||
dailyForecast = dailyResult?.Headline?.Text,
|
||||
|
@ -465,11 +466,11 @@ class AccuService @Inject constructor(
|
|||
ice = getQuantity(forecasts.Day?.Ice)
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = forecasts.Day?.PrecipitationProbability?.toDouble(),
|
||||
thunderstorm = forecasts.Day?.ThunderstormProbability?.toDouble(),
|
||||
rain = forecasts.Day?.RainProbability?.toDouble(),
|
||||
snow = forecasts.Day?.SnowProbability?.toDouble(),
|
||||
ice = forecasts.Day?.IceProbability?.toDouble()
|
||||
total = forecasts.Day?.PrecipitationProbability?.percent,
|
||||
thunderstorm = forecasts.Day?.ThunderstormProbability?.percent,
|
||||
rain = forecasts.Day?.RainProbability?.percent,
|
||||
snow = forecasts.Day?.SnowProbability?.percent,
|
||||
ice = forecasts.Day?.IceProbability?.percent
|
||||
),
|
||||
precipitationDuration = PrecipitationDuration(
|
||||
total = forecasts.Day?.HoursOfPrecipitation?.hours,
|
||||
|
@ -498,11 +499,11 @@ class AccuService @Inject constructor(
|
|||
ice = getQuantity(forecasts.Night?.Ice)
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = forecasts.Night?.PrecipitationProbability?.toDouble(),
|
||||
thunderstorm = forecasts.Night?.ThunderstormProbability?.toDouble(),
|
||||
rain = forecasts.Night?.RainProbability?.toDouble(),
|
||||
snow = forecasts.Night?.SnowProbability?.toDouble(),
|
||||
ice = forecasts.Night?.IceProbability?.toDouble()
|
||||
total = forecasts.Night?.PrecipitationProbability?.percent,
|
||||
thunderstorm = forecasts.Night?.ThunderstormProbability?.percent,
|
||||
rain = forecasts.Night?.RainProbability?.percent,
|
||||
snow = forecasts.Night?.SnowProbability?.percent,
|
||||
ice = forecasts.Night?.IceProbability?.percent
|
||||
),
|
||||
precipitationDuration = PrecipitationDuration(
|
||||
total = forecasts.Night?.HoursOfPrecipitation?.hours,
|
||||
|
@ -588,11 +589,11 @@ class AccuService @Inject constructor(
|
|||
ice = getQuantity(result.Ice)
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = result.PrecipitationProbability?.toDouble(),
|
||||
thunderstorm = result.ThunderstormProbability?.toDouble(),
|
||||
rain = result.RainProbability?.toDouble(),
|
||||
snow = result.SnowProbability?.toDouble(),
|
||||
ice = result.IceProbability?.toDouble()
|
||||
total = result.PrecipitationProbability?.percent,
|
||||
thunderstorm = result.ThunderstormProbability?.percent,
|
||||
rain = result.RainProbability?.percent,
|
||||
snow = result.SnowProbability?.percent,
|
||||
ice = result.IceProbability?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = result.Wind?.Direction?.Degrees?.toDouble(),
|
||||
|
@ -600,9 +601,9 @@ class AccuService @Inject constructor(
|
|||
gusts = getSpeedInMetersPerSecond(result.WindGust?.Speed)
|
||||
),
|
||||
uV = UV(index = result.UVIndex?.toDouble()),
|
||||
relativeHumidity = result.RelativeHumidity?.toDouble(),
|
||||
relativeHumidity = result.RelativeHumidity?.percent,
|
||||
dewPoint = getTemperature(result.DewPoint),
|
||||
cloudCover = result.CloudCover,
|
||||
cloudCover = result.CloudCover?.percent,
|
||||
visibility = getDistance(result.Visibility)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ import org.breezyweather.sources.getWindDegree
|
|||
import org.breezyweather.unit.distance.Distance.Companion.meters
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
|
@ -275,7 +276,7 @@ class AemetService @Inject constructor(
|
|||
speed = it.vv?.metersPerSecond,
|
||||
gusts = it.vmax?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = it.hr,
|
||||
relativeHumidity = it.hr?.percent,
|
||||
dewPoint = it.tpr?.celsius,
|
||||
pressure = it.pres?.hectopascals,
|
||||
visibility = it.vis?.meters
|
||||
|
@ -366,7 +367,7 @@ class AemetService @Inject constructor(
|
|||
feelsLike = maxAtMap.getOrElse(key) { null }?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = ppMap.getOrElse(key) { null }
|
||||
total = ppMap.getOrElse(key) { null }?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = wdMap.getOrElse(key) { null },
|
||||
|
@ -382,7 +383,7 @@ class AemetService @Inject constructor(
|
|||
feelsLike = minAtMap.getOrElse(key) { null }?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = ppMap.getOrElse(key) { null }
|
||||
total = ppMap.getOrElse(key) { null }?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = wdMap.getOrElse(key) { null },
|
||||
|
@ -391,8 +392,8 @@ class AemetService @Inject constructor(
|
|||
)
|
||||
),
|
||||
relativeHumidity = DailyRelativeHumidity(
|
||||
max = maxRhMap.getOrElse(key) { null },
|
||||
min = minRhMap.getOrElse(key) { null }
|
||||
max = maxRhMap.getOrElse(key) { null }?.percent,
|
||||
min = minRhMap.getOrElse(key) { null }?.percent
|
||||
),
|
||||
uV = UV(
|
||||
index = uviMap.getOrElse(key) { null }
|
||||
|
@ -519,16 +520,16 @@ class AemetService @Inject constructor(
|
|||
snow = snMap.getOrElse(key) { null }?.millimeters
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = ppMap.getOrElse(key) { null },
|
||||
thunderstorm = ptMap.getOrElse(key) { null },
|
||||
snow = psMap.getOrElse(key) { null }
|
||||
total = ppMap.getOrElse(key) { null }?.percent,
|
||||
thunderstorm = ptMap.getOrElse(key) { null }?.percent,
|
||||
snow = psMap.getOrElse(key) { null }?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = wdMap.getOrElse(key) { null },
|
||||
speed = wsMap.getOrElse(key) { null }?.kilometersPerHour,
|
||||
gusts = wgMap.getOrElse(key) { null }?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = rhMap.getOrElse(key) { null }
|
||||
relativeHumidity = rhMap.getOrElse(key) { null }?.percent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.breezyweather.common.source.WeatherSource.Companion.PRIORITY_NONE
|
|||
import org.breezyweather.sources.bmd.json.BmdData
|
||||
import org.breezyweather.sources.bmd.json.BmdForecastResult
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -241,10 +242,10 @@ class BmdService @Inject constructor(
|
|||
)
|
||||
),
|
||||
relativeHumidity = rhMap.getOrElse(key) { null }?.let {
|
||||
DailyRelativeHumidity(average = it)
|
||||
DailyRelativeHumidity(average = it.percent)
|
||||
},
|
||||
cloudCover = ccMap.getOrElse(key) { null }?.let {
|
||||
DailyCloudCover(average = it)
|
||||
DailyCloudCover(average = it.percent)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -320,8 +321,8 @@ class BmdService @Inject constructor(
|
|||
speed = wsMap.getOrElse(key) { null }?.kilometersPerHour,
|
||||
gusts = wgMap.getOrElse(key) { null }?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = rhMap.getOrElse(key) { null },
|
||||
cloudCover = ccMap.getOrElse(key) { null }
|
||||
relativeHumidity = rhMap.getOrElse(key) { null }?.percent,
|
||||
cloudCover = ccMap.getOrElse(key) { null }?.percent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ import org.breezyweather.sources.bmkg.json.BmkgWarningResult
|
|||
import org.breezyweather.unit.distance.Distance.Companion.meters
|
||||
import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.microgramsPerCubicMeter
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -259,7 +260,7 @@ class BmkgService @Inject constructor(
|
|||
degree = currentResult.data?.cuaca?.wdDeg,
|
||||
speed = currentResult.data?.cuaca?.ws?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = currentResult.data?.cuaca?.hu,
|
||||
relativeHumidity = currentResult.data?.cuaca?.hu?.percent,
|
||||
visibility = currentResult.data?.cuaca?.vs?.meters
|
||||
)
|
||||
}
|
||||
|
@ -310,8 +311,8 @@ class BmkgService @Inject constructor(
|
|||
degree = it.wdDeg,
|
||||
speed = it.ws?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = it.hu,
|
||||
cloudCover = it.tcc?.toInt(),
|
||||
relativeHumidity = it.hu?.percent,
|
||||
cloudCover = it.tcc?.percent,
|
||||
visibility = it.vs?.meters
|
||||
)
|
||||
)
|
||||
|
|
|
@ -64,6 +64,8 @@ import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.microgr
|
|||
import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.milligramsPerCubicMeter
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -281,7 +283,7 @@ class ChinaService @Inject constructor(
|
|||
null
|
||||
},
|
||||
relativeHumidity = if (!current.humidity?.value.isNullOrEmpty()) {
|
||||
current.humidity.value.toDoubleOrNull()
|
||||
current.humidity.value.toDoubleOrNull()?.percent
|
||||
} else {
|
||||
null
|
||||
},
|
||||
|
@ -368,12 +370,12 @@ class ChinaService @Inject constructor(
|
|||
return dailyList
|
||||
}
|
||||
|
||||
private fun getPrecipitationProbability(forecast: ChinaForecastDaily, index: Int): Double? {
|
||||
private fun getPrecipitationProbability(forecast: ChinaForecastDaily, index: Int): Ratio? {
|
||||
if (forecast.precipitationProbability == null || forecast.precipitationProbability.value.isNullOrEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return forecast.precipitationProbability.value.getOrNull(index)?.toDoubleOrNull()
|
||||
return forecast.precipitationProbability.value.getOrNull(index)?.toDoubleOrNull()?.percent
|
||||
}
|
||||
|
||||
private fun getHourlyList(
|
||||
|
|
|
@ -80,6 +80,7 @@ import org.breezyweather.sources.nlsc.NlscService.Companion.WUQIU_BBOX
|
|||
import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.microgramsPerCubicMeter
|
||||
import org.breezyweather.unit.pressure.Pressure
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.beaufort
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature
|
||||
|
@ -467,7 +468,7 @@ class CwaService @Inject constructor(
|
|||
speed = windSpeed,
|
||||
gusts = windGusts
|
||||
),
|
||||
relativeHumidity = relativeHumidity,
|
||||
relativeHumidity = relativeHumidity?.percent,
|
||||
pressure = computeMeanSeaLevelPressure(
|
||||
barometricPressure = barometricPressure,
|
||||
altitude = altitude,
|
||||
|
@ -625,7 +626,7 @@ class CwaService @Inject constructor(
|
|||
feelsLike = maxAtMap.getOrElse(dayTime) { null }?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = popMap.getOrElse(dayTime) { null }
|
||||
total = popMap.getOrElse(dayTime) { null }?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = wdMap.getOrElse(dayTime) { null },
|
||||
|
@ -640,7 +641,7 @@ class CwaService @Inject constructor(
|
|||
feelsLike = minAtMap.getOrElse(nightTime) { null }?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = popMap.getOrElse(nightTime) { null }
|
||||
total = popMap.getOrElse(nightTime) { null }?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = wdMap.getOrElse(nightTime) { null },
|
||||
|
@ -762,13 +763,13 @@ class CwaService @Inject constructor(
|
|||
feelsLike = atMap.getOrElse(key) { null }?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = popMap.getOrElse(key) { null }
|
||||
total = popMap.getOrElse(key) { null }?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = wdMap.getOrElse(key) { null },
|
||||
speed = wsMap.getOrElse(key) { null }?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = rhMap.getOrElse(key) { null },
|
||||
relativeHumidity = rhMap.getOrElse(key) { null }?.percent,
|
||||
dewPoint = tdMap.getOrElse(key) { null }?.celsius
|
||||
)
|
||||
)
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.breezyweather.sources.dmi.json.DmiWarningResult
|
|||
import org.breezyweather.unit.distance.Distance.Companion.meters
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -214,7 +215,7 @@ class DmiService @Inject constructor(
|
|||
speed = result.windSpeed?.metersPerSecond,
|
||||
gusts = result.windGust?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = result.humidity,
|
||||
relativeHumidity = result.humidity?.percent,
|
||||
pressure = result.pressure?.hectopascals,
|
||||
visibility = result.visibility?.meters
|
||||
)
|
||||
|
|
|
@ -59,6 +59,7 @@ import org.breezyweather.sources.eccc.json.EcccUnit
|
|||
import org.breezyweather.sources.getWindDegree
|
||||
import org.breezyweather.unit.distance.Distance.Companion.kilometers
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.kilopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -203,7 +204,7 @@ class EcccService @Inject constructor(
|
|||
speed = getNonEmptyMetric(result.windSpeed)?.kilometersPerHour,
|
||||
gusts = getNonEmptyMetric(result.windGust)?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = result.humidity?.toDoubleOrNull(),
|
||||
relativeHumidity = result.humidity?.toDoubleOrNull()?.percent,
|
||||
dewPoint = getNonEmptyMetric(result.dewpoint)?.celsius,
|
||||
pressure = getNonEmptyMetric(result.pressure)?.kilopascals,
|
||||
visibility = getNonEmptyMetric(result.visibility)?.kilometers
|
||||
|
@ -263,7 +264,7 @@ class EcccService @Inject constructor(
|
|||
temperature = daytime.temperature?.periodHigh?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = daytime.precip?.toDoubleOrNull()
|
||||
total = daytime.precip?.toDoubleOrNull()?.percent
|
||||
)
|
||||
)
|
||||
} else {
|
||||
|
@ -277,7 +278,7 @@ class EcccService @Inject constructor(
|
|||
temperature = nighttime.temperature?.periodLow?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = nighttime.precip?.toDoubleOrNull()
|
||||
total = nighttime.precip?.toDoubleOrNull()?.percent
|
||||
)
|
||||
),
|
||||
sunshineDuration = daytime?.sun?.value?.toDoubleOrNull()?.hours
|
||||
|
@ -306,7 +307,7 @@ class EcccService @Inject constructor(
|
|||
feelsLike = getNonEmptyMetric(result.feelsLike)?.celsius
|
||||
),
|
||||
precipitationProbability = if (!result.precip.isNullOrEmpty()) {
|
||||
PrecipitationProbability(total = result.precip.toDoubleOrNull())
|
||||
PrecipitationProbability(total = result.precip.toDoubleOrNull()?.percent)
|
||||
} else {
|
||||
null
|
||||
},
|
||||
|
|
|
@ -54,6 +54,8 @@ import org.breezyweather.sources.geosphereat.json.GeoSphereAtWarningsResult
|
|||
import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.microgramsPerCubicMeter
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.pascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.fraction
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -361,10 +363,9 @@ class GeoSphereAtService @Inject constructor(
|
|||
} else {
|
||||
null
|
||||
},
|
||||
relativeHumidity = hourlyResult.features[0].properties!!.parameters!!.rh2m?.data?.getOrNull(i),
|
||||
relativeHumidity = hourlyResult.features[0].properties!!.parameters!!.rh2m?.data?.getOrNull(i)?.percent,
|
||||
pressure = hourlyResult.features[0].properties!!.parameters!!.sp?.data?.getOrNull(i)?.pascals,
|
||||
cloudCover = hourlyResult.features[0].properties!!.parameters!!.tcc?.data?.getOrNull(i)?.times(100)
|
||||
?.roundToInt()
|
||||
cloudCover = hourlyResult.features[0].properties!!.parameters!!.tcc?.data?.getOrNull(i)?.fraction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.breezyweather.sources.here.json.HereWeatherData
|
|||
import org.breezyweather.unit.distance.Distance.Companion.kilometers
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -181,7 +182,7 @@ class HereService @Inject constructor(
|
|||
speed = result.windSpeed?.kilometersPerHour
|
||||
),
|
||||
uV = UV(index = result.uvIndex?.toDouble()),
|
||||
relativeHumidity = result.humidity?.toDouble(),
|
||||
relativeHumidity = result.humidity?.toDoubleOrNull()?.percent,
|
||||
dewPoint = result.dewPoint?.celsius,
|
||||
pressure = result.barometerPressure?.hectopascals,
|
||||
visibility = result.visibility?.kilometers
|
||||
|
@ -251,14 +252,14 @@ class HereService @Inject constructor(
|
|||
snow = result.snowFall?.millimeters
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = result.precipitationProbability?.toDouble()
|
||||
total = result.precipitationProbability?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = result.windDirection,
|
||||
speed = result.windSpeed?.kilometersPerHour
|
||||
),
|
||||
uV = UV(index = result.uvIndex?.toDouble()),
|
||||
relativeHumidity = result.humidity?.toDouble(),
|
||||
relativeHumidity = result.humidity?.toDoubleOrNull()?.percent,
|
||||
dewPoint = result.dewPoint?.celsius,
|
||||
pressure = result.barometerPressure?.hectopascals,
|
||||
visibility = result.visibility?.kilometers
|
||||
|
|
|
@ -63,6 +63,8 @@ import org.breezyweather.sources.hko.json.HkoNormalsResult
|
|||
import org.breezyweather.sources.hko.json.HkoOneJsonResult
|
||||
import org.breezyweather.sources.hko.json.HkoWarningResult
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import org.json.JSONObject
|
||||
|
@ -337,7 +339,7 @@ class HkoService @Inject constructor(
|
|||
uV = UV(
|
||||
index = oneJson.RHRREAD?.UVIndex?.toDoubleOrNull()
|
||||
),
|
||||
relativeHumidity = regionalWeather?.RH?.Value?.toDoubleOrNull(),
|
||||
relativeHumidity = regionalWeather?.RH?.Value?.toDoubleOrNull()?.percent,
|
||||
pressure = regionalWeather?.Pressure?.Value?.toDoubleOrNull()?.hectopascals,
|
||||
dailyForecast = oneJson.F9D?.WeatherForecast?.getOrElse(0) { null }?.ForecastWeather
|
||||
)
|
||||
|
@ -496,7 +498,7 @@ class HkoService @Inject constructor(
|
|||
degree = value.ForecastWindDirection,
|
||||
speed = value.ForecastWindSpeed?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = value.ForecastRelativeHumidity
|
||||
relativeHumidity = value.ForecastRelativeHumidity?.percent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -935,7 +937,7 @@ class HkoService @Inject constructor(
|
|||
|
||||
private fun getPrecipitationProbability(
|
||||
probability: String?,
|
||||
): Double? {
|
||||
): Ratio? {
|
||||
return when (probability) {
|
||||
"<10%" -> 10.0
|
||||
"20%" -> 20.0
|
||||
|
@ -944,7 +946,7 @@ class HkoService @Inject constructor(
|
|||
"80%" -> 80.0
|
||||
">90%" -> 90.0
|
||||
else -> null
|
||||
}
|
||||
}?.percent
|
||||
}
|
||||
|
||||
private fun getAlertColor(
|
||||
|
|
|
@ -149,32 +149,26 @@ class IlmateenistusService @Inject constructor(
|
|||
context: Context,
|
||||
forecastResult: IlmateenistusForecastResult,
|
||||
): List<HourlyWrapper> {
|
||||
val hourlyList = mutableListOf<HourlyWrapper>()
|
||||
val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH)
|
||||
formatter.timeZone = TimeZone.getTimeZone("Europe/Tallinn")
|
||||
forecastResult.forecast?.tabular?.time?.forEach {
|
||||
if (it.attributes.from != null) {
|
||||
hourlyList.add(
|
||||
HourlyWrapper(
|
||||
date = formatter.parse(it.attributes.from)!!,
|
||||
weatherText = getWeatherText(context, it.phenomen?.attributes?.className),
|
||||
weatherCode = getWeatherCode(it.phenomen?.attributes?.className),
|
||||
temperature = TemperatureWrapper(
|
||||
temperature = it.temperature?.attributes?.value?.toDoubleOrNull()?.celsius
|
||||
),
|
||||
precipitation = Precipitation(
|
||||
total = it.precipitation?.attributes?.value?.toDoubleOrNull()?.millimeters
|
||||
),
|
||||
wind = Wind(
|
||||
degree = it.windDirection?.attributes?.deg?.toDoubleOrNull(),
|
||||
speed = it.windSpeed?.attributes?.mps?.toDoubleOrNull()?.metersPerSecond
|
||||
),
|
||||
pressure = it.pressure?.attributes?.value?.toDoubleOrNull()?.hectopascals
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return hourlyList
|
||||
return forecastResult.forecast?.tabular?.time?.filter { it.attributes.from != null }?.map {
|
||||
HourlyWrapper(
|
||||
date = formatter.parse(it.attributes.from!!)!!,
|
||||
weatherText = getWeatherText(context, it.phenomen?.attributes?.className),
|
||||
weatherCode = getWeatherCode(it.phenomen?.attributes?.className),
|
||||
temperature = TemperatureWrapper(
|
||||
temperature = it.temperature?.attributes?.value?.toDoubleOrNull()?.celsius
|
||||
),
|
||||
precipitation = Precipitation(
|
||||
total = it.precipitation?.attributes?.value?.toDoubleOrNull()?.millimeters
|
||||
),
|
||||
wind = Wind(
|
||||
degree = it.windDirection?.attributes?.deg?.toDoubleOrNull(),
|
||||
speed = it.windSpeed?.attributes?.mps?.toDoubleOrNull()?.metersPerSecond
|
||||
),
|
||||
pressure = it.pressure?.attributes?.value?.toDoubleOrNull()?.hectopascals
|
||||
)
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
private fun getWeatherText(
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.breezyweather.common.source.WeatherSource.Companion.PRIORITY_HIGHEST
|
|||
import org.breezyweather.common.source.WeatherSource.Companion.PRIORITY_NONE
|
||||
import org.breezyweather.sources.imd.json.ImdWeatherResult
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -278,8 +279,8 @@ class ImdService @Inject constructor(
|
|||
speed = wspdMap[it]?.metersPerSecond,
|
||||
gusts = gustMap[it]?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = rhMap[it],
|
||||
cloudCover = tcdcMap[it]?.toInt()
|
||||
relativeHumidity = rhMap[it]?.percent,
|
||||
cloudCover = tcdcMap[it]?.percent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ import org.breezyweather.common.utils.helpers.LogHelper
|
|||
import org.breezyweather.sources.RefreshHelper
|
||||
import org.breezyweather.sources.ims.json.ImsLocation
|
||||
import org.breezyweather.sources.ims.json.ImsWeatherData
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -227,7 +228,7 @@ class ImsService @Inject constructor(
|
|||
feelsLike = hourlyResult.value.windChill?.toDoubleOrNull()?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = hourlyResult.value.rainChance?.toDoubleOrNull()
|
||||
total = hourlyResult.value.rainChance?.toDoubleOrNull()?.percent
|
||||
),
|
||||
wind = hourlyResult.value.windSpeed?.let { windSpeed ->
|
||||
Wind(
|
||||
|
@ -240,7 +241,7 @@ class ImsService @Inject constructor(
|
|||
uV = hourlyResult.value.uvIndex?.toDoubleOrNull()?.let { uvi ->
|
||||
UV(uvi)
|
||||
},
|
||||
relativeHumidity = hourlyResult.value.relativeHumidity?.toDoubleOrNull()
|
||||
relativeHumidity = hourlyResult.value.relativeHumidity?.toDoubleOrNull()?.percent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -275,7 +276,7 @@ class ImsService @Inject constructor(
|
|||
)
|
||||
},
|
||||
uV = data.analysis.uvIndex?.toDoubleOrNull()?.let { UV(it) },
|
||||
relativeHumidity = data.analysis.relativeHumidity?.toDoubleOrNull(),
|
||||
relativeHumidity = data.analysis.relativeHumidity?.toDoubleOrNull()?.percent,
|
||||
dewPoint = data.analysis.dewPointTemp?.toDoubleOrNull()?.celsius,
|
||||
dailyForecast = dailyForecast
|
||||
)
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.breezyweather.sources.ipma.json.IpmaAlertResult
|
|||
import org.breezyweather.sources.ipma.json.IpmaDistrictResult
|
||||
import org.breezyweather.sources.ipma.json.IpmaForecastResult
|
||||
import org.breezyweather.sources.ipma.json.IpmaLocationResult
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -182,7 +183,7 @@ class IpmaService @Inject constructor(
|
|||
TemperatureWrapper(temperature = tMax.celsius)
|
||||
},
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = result.probabilidadePrecipita?.toDoubleOrNull()
|
||||
total = result.probabilidadePrecipita?.toDoubleOrNull()?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = getWindDegree(result.ddVento)
|
||||
|
@ -195,7 +196,7 @@ class IpmaService @Inject constructor(
|
|||
?.tMin?.toDoubleOrNull() // Get next day min temperature to have overnight temp
|
||||
?.let { tMin -> TemperatureWrapper(temperature = tMin.celsius) },
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = result.probabilidadePrecipita?.toDoubleOrNull()
|
||||
total = result.probabilidadePrecipita?.toDoubleOrNull()?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = getWindDegree(result.ddVento)
|
||||
|
@ -204,7 +205,7 @@ class IpmaService @Inject constructor(
|
|||
uV = UV(
|
||||
index = result.iUv?.toDoubleOrNull()
|
||||
),
|
||||
relativeHumidity = result.hR?.toDoubleOrNull()?.let { hr -> DailyRelativeHumidity(average = hr) }
|
||||
relativeHumidity = result.hR?.toDoubleOrNull()?.let { h -> DailyRelativeHumidity(average = h.percent) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -232,13 +233,13 @@ class IpmaService @Inject constructor(
|
|||
it.probabilidadePrecipita?.toDoubleOrNull()
|
||||
} else {
|
||||
lastPrecipitationProbability
|
||||
}
|
||||
}?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = getWindDegree(it.ddVento),
|
||||
speed = it.ffVento?.toDoubleOrNull()?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = it.hR?.toDoubleOrNull()
|
||||
relativeHumidity = it.hR?.toDoubleOrNull()?.percent
|
||||
).also { hourly ->
|
||||
if (it.probabilidadePrecipita != "-99.0") {
|
||||
lastPrecipitationProbability = it.probabilidadePrecipita?.toDoubleOrNull()
|
||||
|
|
|
@ -69,6 +69,7 @@ import org.breezyweather.sources.jma.json.JmaHourlyResult
|
|||
import org.breezyweather.sources.jma.json.JmaWeekAreaResult
|
||||
import org.breezyweather.unit.distance.Distance.Companion.meters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import org.json.JSONObject
|
||||
|
@ -317,7 +318,7 @@ class JmaService @Inject constructor(
|
|||
degree = getWindDirection(it.windDirection?.getOrNull(0)),
|
||||
speed = it.wind?.getOrNull(0)?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = it.humidity?.getOrNull(0),
|
||||
relativeHumidity = it.humidity?.getOrNull(0)?.percent,
|
||||
pressure = it.normalPressure?.getOrNull(0)?.hectopascals,
|
||||
visibility = it.visibility?.getOrNull(0)?.meters,
|
||||
dailyForecast = dailyForecast
|
||||
|
@ -446,12 +447,18 @@ class JmaService @Inject constructor(
|
|||
temperature = TemperatureWrapper(
|
||||
temperature = maxTMap.getOrElse(key) { null }?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = max(
|
||||
popMap.getOrElse(key + 6.hours.inWholeMilliseconds) { 0.0 },
|
||||
popMap.getOrElse(key + 12.hours.inWholeMilliseconds) { 0.0 }
|
||||
precipitationProbability = if (popMap.containsKey(key + 6.hours.inWholeMilliseconds) ||
|
||||
popMap.containsKey(key + 12.hours.inWholeMilliseconds)
|
||||
) {
|
||||
PrecipitationProbability(
|
||||
total = max(
|
||||
popMap.getOrElse(key + 6.hours.inWholeMilliseconds) { 0.0 },
|
||||
popMap.getOrElse(key + 12.hours.inWholeMilliseconds) { 0.0 }
|
||||
).percent
|
||||
)
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
),
|
||||
night = HalfDayWrapper(
|
||||
weatherText = getDailyWeatherText(
|
||||
|
@ -466,12 +473,18 @@ class JmaService @Inject constructor(
|
|||
temperature = TemperatureWrapper(
|
||||
temperature = minTMap.getOrElse(key + 1.days.inWholeMilliseconds) { null }?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = max(
|
||||
popMap.getOrElse(key + 18.hours.inWholeMilliseconds) { 0.0 },
|
||||
popMap.getOrElse(key + 24.hours.inWholeMilliseconds) { 0.0 }
|
||||
precipitationProbability = if (popMap.containsKey(key + 6.hours.inWholeMilliseconds) ||
|
||||
popMap.containsKey(key + 12.hours.inWholeMilliseconds)
|
||||
) {
|
||||
PrecipitationProbability(
|
||||
total = max(
|
||||
popMap.getOrElse(key + 6.hours.inWholeMilliseconds) { 0.0 },
|
||||
popMap.getOrElse(key + 12.hours.inWholeMilliseconds) { 0.0 }
|
||||
).percent
|
||||
)
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.breezyweather.sources.lhmt.json.LhmtLocationsResult
|
|||
import org.breezyweather.sources.lhmt.json.LhmtWeatherResult
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -209,9 +210,9 @@ class LhmtService @Inject constructor(
|
|||
speed = it.windSpeed?.metersPerSecond,
|
||||
gusts = it.windGust?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = it.relativeHumidity,
|
||||
relativeHumidity = it.relativeHumidity?.percent,
|
||||
pressure = it.seaLevelPressure?.hectopascals,
|
||||
cloudCover = it.cloudCover?.toInt()
|
||||
cloudCover = it.cloudCover?.percent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -256,9 +257,9 @@ class LhmtService @Inject constructor(
|
|||
speed = it.windSpeed?.metersPerSecond,
|
||||
gusts = it.windGust?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = it.relativeHumidity,
|
||||
relativeHumidity = it.relativeHumidity?.percent,
|
||||
pressure = it.seaLevelPressure?.hectopascals,
|
||||
cloudCover = it.cloudCover?.toInt()
|
||||
cloudCover = it.cloudCover?.percent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.microgr
|
|||
import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.milligramsPerCubicMeter
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -247,7 +248,7 @@ class LvgmcService @Inject constructor(
|
|||
uV = UV(
|
||||
index = it.uvIndex?.toDoubleOrNull()
|
||||
),
|
||||
relativeHumidity = it.relativeHumidity?.toDoubleOrNull(),
|
||||
relativeHumidity = it.relativeHumidity?.toDoubleOrNull()?.percent,
|
||||
pressure = it.pressure?.toDoubleOrNull()?.hectopascals,
|
||||
visibility = it.visibility?.toDoubleOrNull()?.meters
|
||||
)
|
||||
|
@ -360,8 +361,8 @@ class LvgmcService @Inject constructor(
|
|||
snow = it.snow?.toDoubleOrNull()?.millimeters
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = it.precipitationProbability?.toDoubleOrNull(),
|
||||
thunderstorm = it.thunderstormProbability?.toDoubleOrNull()
|
||||
total = it.precipitationProbability?.toDoubleOrNull()?.percent,
|
||||
thunderstorm = it.thunderstormProbability?.toDoubleOrNull()?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = it.windDirection?.toDoubleOrNull(),
|
||||
|
@ -371,9 +372,9 @@ class LvgmcService @Inject constructor(
|
|||
uV = UV(
|
||||
index = it.uvIndex?.toDoubleOrNull()
|
||||
),
|
||||
relativeHumidity = it.relativeHumidity?.toDoubleOrNull(),
|
||||
relativeHumidity = it.relativeHumidity?.toDoubleOrNull()?.percent,
|
||||
pressure = it.pressure?.toDoubleOrNull()?.hectopascals,
|
||||
cloudCover = it.cloudCover?.toIntOrNull()
|
||||
cloudCover = it.cloudCover?.toDoubleOrNull()?.percent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.breezyweather.sources.meteoam.json.MeteoAmObservationResult
|
|||
import org.breezyweather.sources.meteoam.json.MeteoAmReverseLocation
|
||||
import org.breezyweather.sources.meteoam.json.MeteoAmReverseLocationResult
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -185,8 +186,9 @@ class MeteoAmService @Inject constructor(
|
|||
currentResult.getOrElse(keys["wkmh"].toString()) { null }?.getOrElse("0") { null } as? Double
|
||||
)?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = currentResult.getOrElse(keys["r"].toString()) { null }
|
||||
?.getOrElse("0") { null } as? Double,
|
||||
relativeHumidity = (
|
||||
currentResult.getOrElse(keys["r"].toString()) { null }?.getOrElse("0") { null } as? Double
|
||||
)?.percent,
|
||||
pressure = (currentResult.getOrElse(keys["pmsl"].toString()) { null }?.getOrElse("0") { null } as? Double)
|
||||
?.hectopascals
|
||||
)
|
||||
|
@ -239,7 +241,9 @@ class MeteoAmService @Inject constructor(
|
|||
)?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = data.getOrElse(keys["tpp"].toString()) { null }?.getOrElse(i.toString()) { null } as? Double
|
||||
total = (
|
||||
data.getOrElse(keys["tpp"].toString()) { null }?.getOrElse(i.toString()) { null } as? Double
|
||||
)?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = data.getOrElse(keys["wdir"].toString()) { null }?.getOrElse(i.toString()) { null }?.let {
|
||||
|
@ -249,8 +253,9 @@ class MeteoAmService @Inject constructor(
|
|||
data.getOrElse(keys["wkmh"].toString()) { null }?.getOrElse(i.toString()) { null } as? Double
|
||||
)?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = data.getOrElse(keys["r"].toString()) { null }
|
||||
?.getOrElse(i.toString()) { null } as? Double,
|
||||
relativeHumidity = (
|
||||
data.getOrElse(keys["r"].toString()) { null }?.getOrElse(i.toString()) { null } as? Double
|
||||
)?.percent,
|
||||
pressure = (
|
||||
data.getOrElse(keys["pmsl"].toString()) { null }?.getOrElse(i.toString()) { null } as? Double
|
||||
)?.hectopascals
|
||||
|
|
|
@ -50,6 +50,7 @@ import org.breezyweather.sources.metie.json.MetIeWarning
|
|||
import org.breezyweather.sources.metie.json.MetIeWarningResult
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -210,7 +211,7 @@ class MetIeService @Inject constructor(
|
|||
degree = result.windDirection?.toDoubleOrNull(),
|
||||
speed = result.windSpeed?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = result.humidity?.toDoubleOrNull(),
|
||||
relativeHumidity = result.humidity?.toDoubleOrNull()?.percent,
|
||||
pressure = result.pressure?.toDoubleOrNull()?.hectopascals
|
||||
)
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ import org.breezyweather.sources.metno.json.MetNoNowcastResult
|
|||
import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.microgramsPerCubicMeter
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -294,10 +295,10 @@ class MetNoService @Inject constructor(
|
|||
} else {
|
||||
null
|
||||
},
|
||||
relativeHumidity = currentTimeseries.instant?.details?.relativeHumidity,
|
||||
relativeHumidity = currentTimeseries.instant?.details?.relativeHumidity?.percent,
|
||||
dewPoint = currentTimeseries.instant?.details?.dewPointTemperature?.celsius,
|
||||
pressure = currentTimeseries.instant?.details?.airPressureAtSeaLevel?.hectopascals,
|
||||
cloudCover = currentTimeseries.instant?.details?.cloudAreaFraction?.roundToInt()
|
||||
cloudCover = currentTimeseries.instant?.details?.cloudAreaFraction?.percent
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
@ -323,12 +324,12 @@ class MetNoService @Inject constructor(
|
|||
?: hourlyForecast.data?.next12Hours?.details?.precipitationAmount?.millimeters
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = hourlyForecast.data?.next1Hours?.details?.probabilityOfPrecipitation
|
||||
?: hourlyForecast.data?.next6Hours?.details?.probabilityOfPrecipitation
|
||||
?: hourlyForecast.data?.next12Hours?.details?.probabilityOfPrecipitation,
|
||||
thunderstorm = hourlyForecast.data?.next1Hours?.details?.probabilityOfThunder
|
||||
?: hourlyForecast.data?.next6Hours?.details?.probabilityOfThunder
|
||||
?: hourlyForecast.data?.next12Hours?.details?.probabilityOfThunder
|
||||
total = hourlyForecast.data?.next1Hours?.details?.probabilityOfPrecipitation?.percent
|
||||
?: hourlyForecast.data?.next6Hours?.details?.probabilityOfPrecipitation?.percent
|
||||
?: hourlyForecast.data?.next12Hours?.details?.probabilityOfPrecipitation?.percent,
|
||||
thunderstorm = hourlyForecast.data?.next1Hours?.details?.probabilityOfThunder?.percent
|
||||
?: hourlyForecast.data?.next6Hours?.details?.probabilityOfThunder?.percent
|
||||
?: hourlyForecast.data?.next12Hours?.details?.probabilityOfThunder?.percent
|
||||
),
|
||||
wind = hourlyForecast.data?.instant?.details?.let { details ->
|
||||
Wind(
|
||||
|
@ -337,10 +338,10 @@ class MetNoService @Inject constructor(
|
|||
)
|
||||
},
|
||||
uV = UV(index = hourlyForecast.data?.instant?.details?.ultravioletIndexClearSky),
|
||||
relativeHumidity = hourlyForecast.data?.instant?.details?.relativeHumidity,
|
||||
relativeHumidity = hourlyForecast.data?.instant?.details?.relativeHumidity?.percent,
|
||||
dewPoint = hourlyForecast.data?.instant?.details?.dewPointTemperature?.celsius,
|
||||
pressure = hourlyForecast.data?.instant?.details?.airPressureAtSeaLevel?.hectopascals,
|
||||
cloudCover = hourlyForecast.data?.instant?.details?.cloudAreaFraction?.roundToInt()
|
||||
cloudCover = hourlyForecast.data?.instant?.details?.cloudAreaFraction?.percent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.breezyweather.sources.metoffice.json.MetOfficeHourly
|
|||
import org.breezyweather.unit.distance.Distance.Companion.meters
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.pascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -135,10 +136,10 @@ class MetOfficeService @Inject constructor(
|
|||
feelsLike = result.dayMaxFeelsLikeTemp?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = result.dayProbabilityOfPrecipitation?.toDouble(),
|
||||
rain = result.dayProbabilityOfRain?.toDouble(),
|
||||
snow = result.dayProbabilityOfSnow?.toDouble(),
|
||||
thunderstorm = result.dayProbabilityOfSferics?.toDouble()
|
||||
total = result.dayProbabilityOfPrecipitation?.percent,
|
||||
rain = result.dayProbabilityOfRain?.percent,
|
||||
snow = result.dayProbabilityOfSnow?.percent,
|
||||
thunderstorm = result.dayProbabilityOfSferics?.percent
|
||||
)
|
||||
),
|
||||
night = HalfDayWrapper(
|
||||
|
@ -149,10 +150,10 @@ class MetOfficeService @Inject constructor(
|
|||
feelsLike = result.nightMinFeelsLikeTemp?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = result.nightProbabilityOfPrecipitation?.toDouble(),
|
||||
rain = result.nightProbabilityOfRain?.toDouble(),
|
||||
snow = result.nightProbabilityOfSnow?.toDouble(),
|
||||
thunderstorm = result.nightProbabilityOfSferics?.toDouble()
|
||||
total = result.nightProbabilityOfPrecipitation?.percent,
|
||||
rain = result.nightProbabilityOfRain?.percent,
|
||||
snow = result.nightProbabilityOfSnow?.percent,
|
||||
thunderstorm = result.nightProbabilityOfSferics?.percent
|
||||
)
|
||||
),
|
||||
uV = UV(index = result.maxUvIndex?.toDouble())
|
||||
|
@ -184,7 +185,7 @@ class MetOfficeService @Inject constructor(
|
|||
snow = result.totalSnowAmount?.millimeters
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = result.probOfPrecipitation?.toDouble()
|
||||
total = result.probOfPrecipitation?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = result.windDirectionFrom10m?.toDouble(),
|
||||
|
@ -194,7 +195,7 @@ class MetOfficeService @Inject constructor(
|
|||
uV = UV(
|
||||
index = result.uvIndex?.toDouble()
|
||||
),
|
||||
relativeHumidity = result.screenRelativeHumidity,
|
||||
relativeHumidity = result.screenRelativeHumidity?.percent,
|
||||
dewPoint = result.screenDewPointTemperature?.celsius,
|
||||
pressure = result.mslp?.toDouble()?.pascals,
|
||||
visibility = result.visibility?.toDouble()?.meters
|
||||
|
|
|
@ -75,6 +75,7 @@ import org.breezyweather.sources.mf.json.MfWarningsOverseasResult
|
|||
import org.breezyweather.sources.mf.json.MfWarningsResult
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -450,8 +451,8 @@ class MfService @Inject constructor(
|
|||
),
|
||||
uV = UV(index = dailyForecast.uvIndex?.toDouble()),
|
||||
relativeHumidity = DailyRelativeHumidity(
|
||||
min = dailyForecast.relativeHumidityMin?.toDouble(),
|
||||
max = dailyForecast.relativeHumidityMax?.toDouble()
|
||||
min = dailyForecast.relativeHumidityMin?.percent,
|
||||
max = dailyForecast.relativeHumidityMax?.percent
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -482,9 +483,9 @@ class MfService @Inject constructor(
|
|||
speed = hourlyForecast.windSpeed?.metersPerSecond,
|
||||
gusts = hourlyForecast.windSpeedGust?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = hourlyForecast.relativeHumidity?.toDouble(),
|
||||
relativeHumidity = hourlyForecast.relativeHumidity?.percent,
|
||||
pressure = hourlyForecast.pSea?.hectopascals,
|
||||
cloudCover = hourlyForecast.totalCloudCover
|
||||
cloudCover = hourlyForecast.totalCloudCover?.percent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -561,11 +562,13 @@ class MfService @Inject constructor(
|
|||
}
|
||||
}
|
||||
return PrecipitationProbability(
|
||||
maxOf(rainProbability ?: 0.0, snowProbability ?: 0.0, iceProbability ?: 0.0),
|
||||
maxOf(rainProbability ?: 0.0, snowProbability ?: 0.0, iceProbability ?: 0.0)
|
||||
.takeIf { rainProbability != null || snowProbability != null || iceProbability != null }
|
||||
?.percent,
|
||||
null,
|
||||
rainProbability,
|
||||
snowProbability,
|
||||
iceProbability
|
||||
rainProbability?.percent,
|
||||
snowProbability?.percent,
|
||||
iceProbability?.percent
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -25,5 +25,6 @@ import java.util.Date
|
|||
data class MfWarningOverseasComments(
|
||||
@Serializable(DateSerializer::class) @SerialName("begin_time") val beginTime: Date? = null,
|
||||
@Serializable(DateSerializer::class) @SerialName("end_time") val endTime: Date? = null,
|
||||
// TODO: Sometimes return a single string "pas de vigilance particulière", see VIGI973 for example
|
||||
@SerialName("text_bloc_item") val textBlocItems: List<MfWarningOverseasTextBlocItem>?,
|
||||
)
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.breezyweather.sources.mgm.json.MgmHourlyForecastResult
|
|||
import org.breezyweather.sources.mgm.json.MgmLocationResult
|
||||
import org.breezyweather.sources.mgm.json.MgmNormalsResult
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -249,7 +250,7 @@ class MgmService @Inject constructor(
|
|||
degree = getValid(currentResult?.windDirection),
|
||||
speed = getValid(currentResult?.windSpeed)?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = getValid(currentResult?.humidity),
|
||||
relativeHumidity = getValid(currentResult?.humidity)?.percent,
|
||||
pressure = getValid(currentResult?.pressure)?.hectopascals
|
||||
)
|
||||
}
|
||||
|
@ -341,7 +342,7 @@ class MgmService @Inject constructor(
|
|||
speed = it.windSpeed?.kilometersPerHour,
|
||||
gusts = it.gust?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = it.humidity
|
||||
relativeHumidity = it.humidity?.percent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.microgr
|
|||
import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.milligramsPerCubicMeter
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -253,7 +254,7 @@ class NamemService @Inject constructor(
|
|||
degree = current?.windDir,
|
||||
speed = current?.windSpeed?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = current?.ff,
|
||||
relativeHumidity = current?.ff?.percent,
|
||||
pressure = current?.pslp?.hectopascals
|
||||
)
|
||||
}
|
||||
|
@ -330,7 +331,7 @@ class NamemService @Inject constructor(
|
|||
feelsLike = forecast.temNFeel?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = forecast.wwNPer
|
||||
total = forecast.wwNPer?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
speed = forecast.wndN?.metersPerSecond
|
||||
|
@ -350,7 +351,7 @@ class NamemService @Inject constructor(
|
|||
feelsLike = forecast.temDFeel?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = forecast.wwDPer
|
||||
total = forecast.wwDPer?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
speed = forecast.wndD?.metersPerSecond
|
||||
|
@ -365,7 +366,7 @@ class NamemService @Inject constructor(
|
|||
feelsLike = it.temNFeel?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = it.wwNPer
|
||||
total = it.wwNPer?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
speed = it.wndN?.metersPerSecond
|
||||
|
@ -394,7 +395,7 @@ class NamemService @Inject constructor(
|
|||
total = it.pre?.toDoubleOrNull()?.millimeters
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = it.preProb?.toDoubleOrNull()
|
||||
total = it.preProb?.toDoubleOrNull()?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
speed = it.wnd?.toDoubleOrNull()?.metersPerSecond
|
||||
|
|
|
@ -69,6 +69,7 @@ import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
|||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.inchesOfMercury
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.pascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.speed.Speed.Companion.milesPerHour
|
||||
|
@ -282,7 +283,7 @@ class NwsService @Inject constructor(
|
|||
} else {
|
||||
null
|
||||
},
|
||||
relativeHumidity = it.relativeHumidity?.value,
|
||||
relativeHumidity = it.relativeHumidity?.value?.percent,
|
||||
dewPoint = it.dewpoint?.value?.celsius,
|
||||
pressure = if (it.seaLevelPressure != null) {
|
||||
it.seaLevelPressure.value?.pascals
|
||||
|
@ -320,7 +321,7 @@ class NwsService @Inject constructor(
|
|||
temperature = it.temperature?.value?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = it.probabilityOfPrecipitation?.value
|
||||
total = it.probabilityOfPrecipitation?.value?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = getWindDegree(it.windDirection),
|
||||
|
@ -336,7 +337,7 @@ class NwsService @Inject constructor(
|
|||
temperature = it.temperature?.value?.celsius
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = it.probabilityOfPrecipitation?.value
|
||||
total = it.probabilityOfPrecipitation?.value?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = getWindDegree(it.windDirection),
|
||||
|
@ -450,18 +451,18 @@ class NwsService @Inject constructor(
|
|||
ice = iceAccumulationForecastList.getOrElse(it) { null }?.millimeters
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
total = probabilityOfPrecipitationForecastList.getOrElse(it) { null }?.toDouble(),
|
||||
thunderstorm = probabilityOfThunderForecastList.getOrElse(it) { null }?.toDouble()
|
||||
total = probabilityOfPrecipitationForecastList.getOrElse(it) { null }?.percent,
|
||||
thunderstorm = probabilityOfThunderForecastList.getOrElse(it) { null }?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = windDirectionForecastList.getOrElse(it) { null }?.toDouble(),
|
||||
speed = windSpeedForecastList.getOrElse(it) { null }?.kilometersPerHour,
|
||||
gusts = windGustForecastList.getOrElse(it) { null }?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = relativeHumidityList.getOrElse(it) { null }?.toDouble(),
|
||||
relativeHumidity = relativeHumidityList.getOrElse(it) { null }?.percent,
|
||||
dewPoint = dewpointForecastList.getOrElse(it) { null }?.celsius,
|
||||
pressure = pressureForecastList.getOrElse(it) { null }?.inchesOfMercury,
|
||||
cloudCover = skyCoverForecastList.getOrElse(it) { null },
|
||||
cloudCover = skyCoverForecastList.getOrElse(it) { null }?.percent,
|
||||
visibility = visibilityForecastList.getOrElse(it) { null }?.meters
|
||||
)
|
||||
}
|
||||
|
|
|
@ -55,6 +55,8 @@ import org.breezyweather.unit.distance.Distance.Companion.meters
|
|||
import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.microgramsPerCubicMeter
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.fraction
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -187,10 +189,10 @@ class OpenWeatherService @Inject constructor(
|
|||
speed = currentResult.wind?.speed?.metersPerSecond,
|
||||
gusts = currentResult.wind?.gust?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = currentResult.main?.humidity?.toDouble(),
|
||||
relativeHumidity = currentResult.main?.humidity?.percent,
|
||||
pressure = currentResult.main?.pressure?.hectopascals,
|
||||
cloudCover = currentResult.clouds?.all,
|
||||
visibility = currentResult.visibility?.toDouble()?.meters
|
||||
cloudCover = currentResult.clouds?.all?.percent,
|
||||
visibility = currentResult.visibility?.meters
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -234,16 +236,16 @@ class OpenWeatherService @Inject constructor(
|
|||
rain = result.rain?.cumul3h?.millimeters,
|
||||
snow = result.snow?.cumul3h?.millimeters
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(total = result.pop?.times(100.0)),
|
||||
precipitationProbability = PrecipitationProbability(total = result.pop?.fraction),
|
||||
wind = Wind(
|
||||
degree = result.wind?.deg?.toDouble(),
|
||||
speed = result.wind?.speed?.metersPerSecond,
|
||||
gusts = result.wind?.gust?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = result.main?.humidity?.toDouble(),
|
||||
relativeHumidity = result.main?.humidity?.percent,
|
||||
pressure = result.main?.pressure?.hectopascals,
|
||||
cloudCover = result.clouds?.all,
|
||||
visibility = result.visibility?.toDouble()?.meters
|
||||
cloudCover = result.clouds?.all?.percent,
|
||||
visibility = result.visibility?.meters
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.breezyweather.sources.pagasa.json.PagasaHourlyResult
|
|||
import org.breezyweather.sources.pagasa.json.PagasaLocationResult
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
|
@ -206,7 +207,7 @@ class PagasaService @Inject constructor(
|
|||
degree = getWindDegree(it.windDirection),
|
||||
speed = it.windSpeed?.substringBefore(" ")?.toDoubleOrNull()?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = it.humidity?.substringBefore(" ")?.toDoubleOrNull(),
|
||||
relativeHumidity = it.humidity?.substringBefore(" ")?.toDoubleOrNull()?.percent,
|
||||
pressure = it.pressure?.toDoubleOrNull()?.hectopascals
|
||||
)
|
||||
}
|
||||
|
@ -264,7 +265,7 @@ class PagasaService @Inject constructor(
|
|||
degree = it.windDirection?.attributes?.deg?.toDoubleOrNull(),
|
||||
speed = it.windSpeed?.attributes?.mps?.toDoubleOrNull()?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = it.relativeHumidity?.attributes?.value?.toDoubleOrNull()
|
||||
relativeHumidity = it.relativeHumidity?.attributes?.value?.toDoubleOrNull()?.percent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ import org.breezyweather.sources.smg.json.SmgWarningResult
|
|||
import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.microgramsPerCubicMeter
|
||||
import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.milligramsPerCubicMeter
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.kilometersPerHour
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -323,7 +324,7 @@ class SmgService @Inject constructor(
|
|||
index = uvResult.UV?.Custom?.getOrNull(0)?.ActualUVBReport?.getOrNull(0)?.index
|
||||
?.getOrNull(0)?.Value?.getOrNull(0)?.toDoubleOrNull()
|
||||
),
|
||||
relativeHumidity = it.Humidity?.getOrNull(0)?.dValue?.getOrNull(0)?.toDoubleOrNull(),
|
||||
relativeHumidity = it.Humidity?.getOrNull(0)?.dValue?.getOrNull(0)?.toDoubleOrNull()?.percent,
|
||||
dewPoint = it.DewPoint?.getOrNull(0)?.dValue?.getOrNull(0)?.toDoubleOrNull()?.celsius,
|
||||
pressure = it.MeanSeaLevelPressure?.getOrNull(0)?.dValue?.getOrNull(0)?.toDoubleOrNull()
|
||||
?.hectopascals,
|
||||
|
@ -405,7 +406,7 @@ class SmgService @Inject constructor(
|
|||
degree = it.Winddiv?.getOrNull(0)?.Value?.getOrNull(0)?.toDoubleOrNull(),
|
||||
speed = it.Windspd?.getOrNull(0)?.Value?.getOrNull(0)?.toDoubleOrNull()?.kilometersPerHour
|
||||
),
|
||||
relativeHumidity = it.Humidity?.getOrNull(0)?.Value?.getOrNull(0)?.toDoubleOrNull()
|
||||
relativeHumidity = it.Humidity?.getOrNull(0)?.Value?.getOrNull(0)?.toDoubleOrNull()?.percent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.breezyweather.sources.smhi.json.SmhiTimeSeries
|
|||
import org.breezyweather.unit.distance.Distance.Companion.kilometers
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import retrofit2.Retrofit
|
||||
|
@ -153,14 +154,14 @@ class SmhiService @Inject constructor(
|
|||
total = result.parameters.firstOrNull { it.name == "pmean" }?.values?.getOrNull(0)?.millimeters
|
||||
),
|
||||
precipitationProbability = PrecipitationProbability(
|
||||
thunderstorm = result.parameters.firstOrNull { it.name == "tstm" }?.values?.getOrNull(0)
|
||||
thunderstorm = result.parameters.firstOrNull { it.name == "tstm" }?.values?.getOrNull(0)?.percent
|
||||
),
|
||||
wind = Wind(
|
||||
degree = result.parameters.firstOrNull { it.name == "wd" }?.values?.getOrNull(0),
|
||||
speed = result.parameters.firstOrNull { it.name == "ws" }?.values?.getOrNull(0)?.metersPerSecond,
|
||||
gusts = result.parameters.firstOrNull { it.name == "gust" }?.values?.getOrNull(0)?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = result.parameters.firstOrNull { it.name == "r" }?.values?.getOrNull(0),
|
||||
relativeHumidity = result.parameters.firstOrNull { it.name == "r" }?.values?.getOrNull(0)?.percent,
|
||||
pressure = result.parameters.firstOrNull { it.name == "msl" }?.values?.getOrNull(0)?.hectopascals,
|
||||
visibility = result.parameters.firstOrNull { it.name == "vis" }?.values?.getOrNull(0)?.kilometers
|
||||
)
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.breezyweather.sources.veduris.json.VedurIsStationForecast
|
|||
import org.breezyweather.sources.veduris.json.VedurIsStationResult
|
||||
import org.breezyweather.unit.precipitation.Precipitation.Companion.millimeters
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.hectopascals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.speed.Speed.Companion.metersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature.Companion.celsius
|
||||
import org.json.JSONObject
|
||||
|
@ -202,7 +203,7 @@ class VedurIsService @Inject constructor(
|
|||
degree = it.windDirection,
|
||||
speed = it.windSpeed?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = if (it.humidity != 0.0) it.humidity else null
|
||||
relativeHumidity = it.humidity.takeIf { h -> h != 0.0 }?.percent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -226,7 +227,7 @@ class VedurIsService @Inject constructor(
|
|||
degree = it.windDirection,
|
||||
speed = it.windSpeed?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = if (it.humidity != 0.0) it.humidity else null
|
||||
relativeHumidity = it.humidity.takeIf { h -> h != 0.0 }?.percent
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -277,10 +278,10 @@ class VedurIsService @Inject constructor(
|
|||
speed = it.windSpeed?.metersPerSecond,
|
||||
gusts = it.maxWindGust?.metersPerSecond
|
||||
),
|
||||
relativeHumidity = if (it.humidity != 0.0) it.humidity else null,
|
||||
relativeHumidity = it.humidity.takeIf { h -> h != 0.0 }?.percent,
|
||||
dewPoint = it.dewPoint?.celsius,
|
||||
pressure = it.pressure?.hectopascals,
|
||||
cloudCover = it.cloudCover?.toInt()
|
||||
cloudCover = it.cloudCover?.percent
|
||||
)
|
||||
} ?: CurrentWrapper()
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ import org.breezyweather.unit.precipitation.Precipitation
|
|||
import org.breezyweather.unit.precipitation.Precipitation.Companion.micrometers
|
||||
import org.breezyweather.unit.pressure.Pressure
|
||||
import org.breezyweather.unit.pressure.Pressure.Companion.pascals
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.permille
|
||||
import org.breezyweather.unit.speed.Speed
|
||||
import org.breezyweather.unit.speed.Speed.Companion.centimetersPerSecond
|
||||
import org.breezyweather.unit.temperature.Temperature
|
||||
|
@ -122,3 +124,9 @@ object DurationColumnAdapter : ColumnAdapter<Duration, Long> {
|
|||
|
||||
override fun encode(value: Duration): Long = value.inWholeNanoseconds
|
||||
}
|
||||
|
||||
object RatioColumnAdapter : ColumnAdapter<Ratio, Long> {
|
||||
override fun decode(databaseValue: Long): Ratio = databaseValue.permille
|
||||
|
||||
override fun encode(value: Ratio): Long = value.value
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.breezyweather.unit.pollen.PollenConcentration
|
|||
import org.breezyweather.unit.pollutant.PollutantConcentration
|
||||
import org.breezyweather.unit.precipitation.Precipitation
|
||||
import org.breezyweather.unit.pressure.Pressure
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import org.breezyweather.unit.speed.Speed
|
||||
import org.breezyweather.unit.temperature.Temperature
|
||||
import java.util.Date
|
||||
|
@ -82,11 +83,11 @@ object WeatherMapper {
|
|||
no2: PollutantConcentration?,
|
||||
o3: PollutantConcentration?,
|
||||
co: PollutantConcentration?,
|
||||
relativeHumidity: Double?,
|
||||
relativeHumidity: Ratio?,
|
||||
dewPoint: Temperature?,
|
||||
pressure: Pressure?,
|
||||
visibility: Distance?,
|
||||
cloudCover: Long?,
|
||||
cloudCover: Ratio?,
|
||||
ceiling: Distance?,
|
||||
dailyForecast: String?,
|
||||
hourlyForecast: String?,
|
||||
|
@ -130,7 +131,7 @@ object WeatherMapper {
|
|||
relativeHumidity,
|
||||
dewPoint,
|
||||
pressure,
|
||||
cloudCover?.toInt(),
|
||||
cloudCover,
|
||||
visibility,
|
||||
ceiling,
|
||||
dailyForecast,
|
||||
|
@ -153,11 +154,11 @@ object WeatherMapper {
|
|||
daytimeRainPrecipitation: Precipitation?,
|
||||
daytimeSnowPrecipitation: Precipitation?,
|
||||
daytimeIcePrecipitation: Precipitation?,
|
||||
daytimeTotalPrecipitationProbability: Double?,
|
||||
daytimeThunderstormPrecipitationProbability: Double?,
|
||||
daytimeRainPrecipitationProbability: Double?,
|
||||
daytimeSnowPrecipitationProbability: Double?,
|
||||
daytimeIcePrecipitationProbability: Double?,
|
||||
daytimeTotalPrecipitationProbability: Ratio?,
|
||||
daytimeThunderstormPrecipitationProbability: Ratio?,
|
||||
daytimeRainPrecipitationProbability: Ratio?,
|
||||
daytimeSnowPrecipitationProbability: Ratio?,
|
||||
daytimeIcePrecipitationProbability: Ratio?,
|
||||
daytimeTotalPrecipitationDuration: Duration?,
|
||||
daytimeThunderstormPrecipitationDuration: Duration?,
|
||||
daytimeRainPrecipitationDuration: Duration?,
|
||||
|
@ -179,11 +180,11 @@ object WeatherMapper {
|
|||
nighttimeRainPrecipitation: Precipitation?,
|
||||
nighttimeSnowPrecipitation: Precipitation?,
|
||||
nighttimeIcePrecipitation: Precipitation?,
|
||||
nighttimeTotalPrecipitationProbability: Double?,
|
||||
nighttimeThunderstormPrecipitationProbability: Double?,
|
||||
nighttimeRainPrecipitationProbability: Double?,
|
||||
nighttimeSnowPrecipitationProbability: Double?,
|
||||
nighttimeIcePrecipitationProbability: Double?,
|
||||
nighttimeTotalPrecipitationProbability: Ratio?,
|
||||
nighttimeThunderstormPrecipitationProbability: Ratio?,
|
||||
nighttimeRainPrecipitationProbability: Ratio?,
|
||||
nighttimeSnowPrecipitationProbability: Ratio?,
|
||||
nighttimeIcePrecipitationProbability: Ratio?,
|
||||
nighttimeTotalPrecipitationDuration: Duration?,
|
||||
nighttimeThunderstormPrecipitationDuration: Duration?,
|
||||
nighttimeRainPrecipitationDuration: Duration?,
|
||||
|
@ -230,18 +231,18 @@ object WeatherMapper {
|
|||
willow: PollenConcentration?,
|
||||
uvIndex: Double?,
|
||||
sunshineDuration: Duration?,
|
||||
relativeHumidityAverage: Double?,
|
||||
relativeHumidityMin: Double?,
|
||||
relativeHumidityMax: Double?,
|
||||
relativeHumidityAverage: Ratio?,
|
||||
relativeHumidityMin: Ratio?,
|
||||
relativeHumidityMax: Ratio?,
|
||||
dewpointAverage: Temperature?,
|
||||
dewpointMin: Temperature?,
|
||||
dewpointMax: Temperature?,
|
||||
pressureAverage: Pressure?,
|
||||
pressureMin: Pressure?,
|
||||
pressureMax: Pressure?,
|
||||
cloudCoverAverage: Long?,
|
||||
cloudCoverMin: Long?,
|
||||
cloudCoverMax: Long?,
|
||||
cloudCoverAverage: Ratio?,
|
||||
cloudCoverMin: Ratio?,
|
||||
cloudCoverMax: Ratio?,
|
||||
visibilityAverage: Distance?,
|
||||
visibilityMin: Distance?,
|
||||
visibilityMax: Distance?,
|
||||
|
@ -377,9 +378,9 @@ object WeatherMapper {
|
|||
max = pressureMax
|
||||
),
|
||||
cloudCover = DailyCloudCover(
|
||||
average = cloudCoverAverage?.toInt(),
|
||||
min = cloudCoverMin?.toInt(),
|
||||
max = cloudCoverMax?.toInt()
|
||||
average = cloudCoverAverage,
|
||||
min = cloudCoverMin,
|
||||
max = cloudCoverMax
|
||||
),
|
||||
visibility = DailyVisibility(
|
||||
average = visibilityAverage,
|
||||
|
@ -403,11 +404,11 @@ object WeatherMapper {
|
|||
rainPrecipitation: Precipitation?,
|
||||
snowPrecipitation: Precipitation?,
|
||||
icePrecipitation: Precipitation?,
|
||||
totalPrecipitationProbability: Double?,
|
||||
thunderstormPrecipitationProbability: Double?,
|
||||
rainPrecipitationProbability: Double?,
|
||||
snowPrecipitationProbability: Double?,
|
||||
icePrecipitationProbability: Double?,
|
||||
totalPrecipitationProbability: Ratio?,
|
||||
thunderstormPrecipitationProbability: Ratio?,
|
||||
rainPrecipitationProbability: Ratio?,
|
||||
snowPrecipitationProbability: Ratio?,
|
||||
icePrecipitationProbability: Ratio?,
|
||||
windDegree: Double?,
|
||||
windSpeed: Speed?,
|
||||
windGusts: Speed?,
|
||||
|
@ -418,10 +419,10 @@ object WeatherMapper {
|
|||
o3: PollutantConcentration?,
|
||||
co: PollutantConcentration?,
|
||||
uvIndex: Double?,
|
||||
relativeHumidity: Double?,
|
||||
relativeHumidity: Ratio?,
|
||||
dewPoint: Temperature?,
|
||||
pressure: Pressure?,
|
||||
cloudCover: Long?,
|
||||
cloudCover: Ratio?,
|
||||
visibility: Distance?,
|
||||
): Hourly = Hourly(
|
||||
Date(date),
|
||||
|
@ -466,7 +467,7 @@ object WeatherMapper {
|
|||
relativeHumidity,
|
||||
dewPoint,
|
||||
pressure,
|
||||
cloudCover?.toInt(),
|
||||
cloudCover,
|
||||
visibility
|
||||
)
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ class WeatherRepository(
|
|||
relativeHumidity = weather.current?.relativeHumidity,
|
||||
dewPoint = weather.current?.dewPoint,
|
||||
pressure = weather.current?.pressure,
|
||||
cloudCover = weather.current?.cloudCover?.toLong(),
|
||||
cloudCover = weather.current?.cloudCover,
|
||||
visibility = weather.current?.visibility,
|
||||
ceiling = weather.current?.ceiling,
|
||||
dailyForecast = weather.current?.dailyForecast,
|
||||
|
@ -311,9 +311,9 @@ class WeatherRepository(
|
|||
pressureMin = daily.pressure?.min,
|
||||
pressureMax = daily.pressure?.max,
|
||||
|
||||
cloudCoverAverage = daily.cloudCover?.average?.toLong(),
|
||||
cloudCoverMin = daily.cloudCover?.min?.toLong(),
|
||||
cloudCoverMax = daily.cloudCover?.max?.toLong(),
|
||||
cloudCoverAverage = daily.cloudCover?.average,
|
||||
cloudCoverMin = daily.cloudCover?.min,
|
||||
cloudCoverMax = daily.cloudCover?.max,
|
||||
|
||||
visibilityAverage = daily.visibility?.average,
|
||||
visibilityMin = daily.visibility?.min,
|
||||
|
@ -368,7 +368,7 @@ class WeatherRepository(
|
|||
relativeHumidity = hourly.relativeHumidity,
|
||||
dewPoint = hourly.dewPoint,
|
||||
pressure = hourly.pressure,
|
||||
cloudCover = hourly.cloudCover?.toLong(),
|
||||
cloudCover = hourly.cloudCover,
|
||||
visibility = hourly.visibility
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import org.breezyweather.unit.pollen.PollenConcentration;
|
|||
import org.breezyweather.unit.pollutant.PollutantConcentration;
|
||||
import org.breezyweather.unit.precipitation.Precipitation;
|
||||
import org.breezyweather.unit.pressure.Pressure;
|
||||
import org.breezyweather.unit.ratio.Ratio;
|
||||
import org.breezyweather.unit.speed.Speed;
|
||||
import org.breezyweather.unit.temperature.Temperature;
|
||||
|
||||
|
@ -31,11 +32,11 @@ CREATE TABLE dailys(
|
|||
daytime_snow_precipitation INTEGER AS Precipitation,
|
||||
daytime_ice_precipitation INTEGER AS Precipitation,
|
||||
|
||||
daytime_total_precipitation_probability REAL,
|
||||
daytime_thunderstorm_precipitation_probability REAL,
|
||||
daytime_rain_precipitation_probability REAL,
|
||||
daytime_snow_precipitation_probability REAL,
|
||||
daytime_ice_precipitation_probability REAL,
|
||||
daytime_total_precipitation_probability INTEGER AS Ratio,
|
||||
daytime_thunderstorm_precipitation_probability INTEGER AS Ratio,
|
||||
daytime_rain_precipitation_probability INTEGER AS Ratio,
|
||||
daytime_snow_precipitation_probability INTEGER AS Ratio,
|
||||
daytime_ice_precipitation_probability INTEGER AS Ratio,
|
||||
|
||||
daytime_total_precipitation_duration INTEGER AS Duration,
|
||||
daytime_thunderstorm_precipitation_duration INTEGER AS Duration,
|
||||
|
@ -64,11 +65,11 @@ CREATE TABLE dailys(
|
|||
nighttime_snow_precipitation INTEGER AS Precipitation,
|
||||
nighttime_ice_precipitation INTEGER AS Precipitation,
|
||||
|
||||
nighttime_total_precipitation_probability REAL,
|
||||
nighttime_thunderstorm_precipitation_probability REAL,
|
||||
nighttime_rain_precipitation_probability REAL,
|
||||
nighttime_snow_precipitation_probability REAL,
|
||||
nighttime_ice_precipitation_probability REAL,
|
||||
nighttime_total_precipitation_probability INTEGER AS Ratio,
|
||||
nighttime_thunderstorm_precipitation_probability INTEGER AS Ratio,
|
||||
nighttime_rain_precipitation_probability INTEGER AS Ratio,
|
||||
nighttime_snow_precipitation_probability INTEGER AS Ratio,
|
||||
nighttime_ice_precipitation_probability INTEGER AS Ratio,
|
||||
|
||||
nighttime_total_precipitation_duration INTEGER AS Duration,
|
||||
nighttime_thunderstorm_precipitation_duration INTEGER AS Duration,
|
||||
|
@ -135,9 +136,9 @@ CREATE TABLE dailys(
|
|||
sunshine_duration INTEGER AS Duration,
|
||||
|
||||
-- relative humidity
|
||||
relative_humidity_average REAL,
|
||||
relative_humidity_min REAL,
|
||||
relative_humidity_max REAL,
|
||||
relative_humidity_average INTEGER AS Ratio,
|
||||
relative_humidity_min INTEGER AS Ratio,
|
||||
relative_humidity_max INTEGER AS Ratio,
|
||||
|
||||
-- dewpoint
|
||||
dewpoint_average INTEGER AS Temperature,
|
||||
|
@ -150,9 +151,9 @@ CREATE TABLE dailys(
|
|||
pressure_max INTEGER AS Pressure,
|
||||
|
||||
-- cloud cover
|
||||
cloud_cover_average INTEGER,
|
||||
cloud_cover_min INTEGER,
|
||||
cloud_cover_max INTEGER,
|
||||
cloud_cover_average INTEGER AS Ratio,
|
||||
cloud_cover_min INTEGER AS Ratio,
|
||||
cloud_cover_max INTEGER AS Ratio,
|
||||
|
||||
-- visibility
|
||||
visibility_average INTEGER AS Distance,
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.breezyweather.unit.distance.Distance;
|
|||
import org.breezyweather.unit.pollutant.PollutantConcentration;
|
||||
import org.breezyweather.unit.precipitation.Precipitation;
|
||||
import org.breezyweather.unit.pressure.Pressure;
|
||||
import org.breezyweather.unit.ratio.Ratio;
|
||||
import org.breezyweather.unit.speed.Speed;
|
||||
import org.breezyweather.unit.temperature.Temperature;
|
||||
|
||||
|
@ -29,11 +30,11 @@ CREATE TABLE hourlys(
|
|||
snow_precipitation INTEGER AS Precipitation,
|
||||
ice_precipitation INTEGER AS Precipitation,
|
||||
|
||||
total_precipitation_probability REAL,
|
||||
thunderstorm_precipitation_probability REAL,
|
||||
rain_precipitation_probability REAL,
|
||||
snow_precipitation_probability REAL,
|
||||
ice_precipitation_probability REAL,
|
||||
total_precipitation_probability INTEGER AS Ratio,
|
||||
thunderstorm_precipitation_probability INTEGER AS Ratio,
|
||||
rain_precipitation_probability INTEGER AS Ratio,
|
||||
snow_precipitation_probability INTEGER AS Ratio,
|
||||
ice_precipitation_probability INTEGER AS Ratio,
|
||||
|
||||
wind_degree REAL,
|
||||
wind_speed INTEGER AS Speed,
|
||||
|
@ -50,10 +51,10 @@ CREATE TABLE hourlys(
|
|||
uvIndex REAL,
|
||||
|
||||
-- details
|
||||
relative_humidity REAL,
|
||||
relative_humidity INTEGER AS Ratio,
|
||||
dew_point INTEGER AS Temperature,
|
||||
pressure INTEGER AS Pressure,
|
||||
cloud_cover INTEGER,
|
||||
cloud_cover INTEGER AS Ratio,
|
||||
visibility INTEGER AS Distance,
|
||||
|
||||
UNIQUE(location_formatted_id, date) ON CONFLICT REPLACE,
|
||||
|
|
|
@ -2,6 +2,7 @@ import breezyweather.domain.weather.reference.WeatherCode;
|
|||
import org.breezyweather.unit.distance.Distance;
|
||||
import org.breezyweather.unit.pollutant.PollutantConcentration;
|
||||
import org.breezyweather.unit.pressure.Pressure;
|
||||
import org.breezyweather.unit.ratio.Ratio;
|
||||
import org.breezyweather.unit.speed.Speed;
|
||||
import org.breezyweather.unit.temperature.Temperature;
|
||||
|
||||
|
@ -44,11 +45,11 @@ CREATE TABLE weathers(
|
|||
o3 INTEGER AS PollutantConcentration,
|
||||
co INTEGER AS PollutantConcentration,
|
||||
|
||||
relative_humidity REAL,
|
||||
relative_humidity INTEGER AS Ratio,
|
||||
dew_point INTEGER AS Temperature,
|
||||
pressure INTEGER AS Pressure,
|
||||
visibility INTEGER AS Distance,
|
||||
cloud_cover INTEGER,
|
||||
cloud_cover INTEGER AS Ratio,
|
||||
ceiling INTEGER AS Distance,
|
||||
daily_forecast TEXT,
|
||||
hourly_forecast TEXT,
|
||||
|
|
123
data/src/main/sqldelight/breezyweather/migrations/25.sqm
Normal file
123
data/src/main/sqldelight/breezyweather/migrations/25.sqm
Normal file
|
@ -0,0 +1,123 @@
|
|||
ALTER TABLE dailys
|
||||
DROP COLUMN daytime_total_precipitation_probability;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN daytime_total_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE dailys
|
||||
DROP COLUMN daytime_thunderstorm_precipitation_probability;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN daytime_thunderstorm_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE dailys
|
||||
DROP COLUMN daytime_rain_precipitation_probability;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN daytime_rain_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE dailys
|
||||
DROP COLUMN daytime_snow_precipitation_probability;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN daytime_snow_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE dailys
|
||||
DROP COLUMN daytime_ice_precipitation_probability;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN daytime_ice_precipitation_probability INTEGER;
|
||||
|
||||
|
||||
ALTER TABLE dailys
|
||||
DROP COLUMN nighttime_total_precipitation_probability;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN nighttime_total_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE dailys
|
||||
DROP COLUMN nighttime_thunderstorm_precipitation_probability;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN nighttime_thunderstorm_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE dailys
|
||||
DROP COLUMN nighttime_rain_precipitation_probability;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN nighttime_rain_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE dailys
|
||||
DROP COLUMN nighttime_snow_precipitation_probability;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN nighttime_snow_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE dailys
|
||||
DROP COLUMN nighttime_ice_precipitation_probability;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN nighttime_ice_precipitation_probability INTEGER;
|
||||
|
||||
|
||||
ALTER TABLE dailys
|
||||
DROP COLUMN relative_humidity_average;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN relative_humidity_average INTEGER;
|
||||
|
||||
ALTER TABLE dailys
|
||||
DROP COLUMN relative_humidity_min;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN relative_humidity_min INTEGER;
|
||||
|
||||
ALTER TABLE dailys
|
||||
DROP COLUMN relative_humidity_max;
|
||||
|
||||
ALTER TABLE dailys
|
||||
ADD COLUMN relative_humidity_max INTEGER;
|
||||
|
||||
|
||||
ALTER TABLE hourlys
|
||||
DROP COLUMN total_precipitation_probability;
|
||||
|
||||
ALTER TABLE hourlys
|
||||
ADD COLUMN total_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE hourlys
|
||||
DROP COLUMN thunderstorm_precipitation_probability;
|
||||
|
||||
ALTER TABLE hourlys
|
||||
ADD COLUMN thunderstorm_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE hourlys
|
||||
DROP COLUMN rain_precipitation_probability;
|
||||
|
||||
ALTER TABLE hourlys
|
||||
ADD COLUMN rain_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE hourlys
|
||||
DROP COLUMN snow_precipitation_probability;
|
||||
|
||||
ALTER TABLE hourlys
|
||||
ADD COLUMN snow_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE hourlys
|
||||
DROP COLUMN ice_precipitation_probability;
|
||||
|
||||
ALTER TABLE hourlys
|
||||
ADD COLUMN ice_precipitation_probability INTEGER;
|
||||
|
||||
ALTER TABLE hourlys
|
||||
DROP COLUMN relative_humidity;
|
||||
|
||||
ALTER TABLE hourlys
|
||||
ADD COLUMN relative_humidity INTEGER;
|
||||
|
||||
|
||||
ALTER TABLE weathers
|
||||
DROP COLUMN relative_humidity;
|
||||
|
||||
ALTER TABLE weathers
|
||||
ADD COLUMN relative_humidity INTEGER;
|
|
@ -20,13 +20,11 @@ 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.
|
||||
*
|
||||
* default unit
|
||||
* [.relativeHumidity] : [RelativeHumidityUnit.PERCENT]
|
||||
*/
|
||||
data class Current(
|
||||
val weatherText: String? = null,
|
||||
|
@ -35,14 +33,14 @@ data class Current(
|
|||
val wind: Wind? = null,
|
||||
val uV: UV? = null,
|
||||
val airQuality: AirQuality? = null,
|
||||
val relativeHumidity: Double? = 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: Int? = null,
|
||||
val cloudCover: Ratio? = null,
|
||||
val visibility: Distance? = null,
|
||||
val ceiling: Distance? = null,
|
||||
val dailyForecast: String? = null,
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
|
||||
data class DailyCloudCover(
|
||||
override val average: Int? = null,
|
||||
override val max: Int? = null,
|
||||
override val min: Int? = null,
|
||||
override val average: Ratio? = null,
|
||||
override val max: Ratio? = null,
|
||||
override val min: Ratio? = null,
|
||||
override val summary: String? = null,
|
||||
) : DailyAvgMinMax<Int>
|
||||
) : DailyAvgMinMax<Ratio>
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
|
||||
data class DailyRelativeHumidity(
|
||||
override val average: Double? = null,
|
||||
override val max: Double? = null,
|
||||
override val min: Double? = null,
|
||||
override val average: Ratio? = null,
|
||||
override val max: Ratio? = null,
|
||||
override val min: Ratio? = null,
|
||||
override val summary: String? = null,
|
||||
) : DailyAvgMinMax<Double>
|
||||
) : DailyAvgMinMax<Ratio>
|
||||
|
|
|
@ -20,6 +20,7 @@ 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
|
||||
|
||||
|
@ -37,14 +38,14 @@ data class Hourly(
|
|||
val wind: Wind? = null,
|
||||
val airQuality: AirQuality? = null,
|
||||
val uV: UV? = null,
|
||||
val relativeHumidity: Double? = 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: Int? = null,
|
||||
val cloudCover: Ratio? = null,
|
||||
val visibility: Distance? = null,
|
||||
) : Serializable {
|
||||
|
||||
|
|
|
@ -16,21 +16,20 @@
|
|||
|
||||
package breezyweather.domain.weather.model
|
||||
|
||||
import org.breezyweather.unit.ratio.Ratio
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Precipitation duration.
|
||||
*
|
||||
* default unit : [ProbabilityUnit.PERCENT]
|
||||
*/
|
||||
data class PrecipitationProbability(
|
||||
val total: Double? = null,
|
||||
val thunderstorm: Double? = null,
|
||||
val rain: Double? = null,
|
||||
val snow: Double? = null,
|
||||
val ice: Double? = null,
|
||||
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 > 0
|
||||
get() = total != null && total.value > 0
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ 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
|
||||
|
||||
/**
|
||||
|
@ -33,14 +34,14 @@ data class CurrentWrapper(
|
|||
val temperature: TemperatureWrapper? = null,
|
||||
val wind: Wind? = null,
|
||||
val uV: UV? = null,
|
||||
val relativeHumidity: Double? = 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: Int? = null,
|
||||
val cloudCover: Ratio? = null,
|
||||
val visibility: Distance? = null,
|
||||
val ceiling: Distance? = null,
|
||||
val dailyForecast: String? = null,
|
||||
|
|
|
@ -25,6 +25,7 @@ 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
|
||||
|
@ -42,14 +43,14 @@ data class HourlyWrapper(
|
|||
val precipitationProbability: PrecipitationProbability? = null,
|
||||
val wind: Wind? = null,
|
||||
val uV: UV? = null,
|
||||
val relativeHumidity: Double? = 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: Int? = null,
|
||||
val cloudCover: Ratio? = null,
|
||||
val visibility: Distance? = null,
|
||||
/**
|
||||
* Duration of sunshine, NOT duration of daylight
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Breezy Weather unit conversion and formatting library
|
||||
|
||||
Android library to handle:
|
||||
|
||||
- Unit conversion
|
||||
- Formatting in various languages, including on devices without ICU support or with missing CLDR data, with a simplified backport (no handling of plural and non-nominative rules)
|
||||
|
||||
|
@ -10,7 +11,6 @@ Some precision may be lost during conversions.
|
|||
|
||||
Remains to do:
|
||||
|
||||
- Percentage formatting
|
||||
- Add missing non-English Android translations (for the units we use in Breezy Weather)
|
||||
- Plus and minus operations
|
||||
- Parse from string
|
||||
|
@ -33,6 +33,12 @@ Android translations are only in English at the moment.
|
|||
|
||||
Supports temperature deviations conversions (such as degree days).
|
||||
|
||||
Supported widths for Android translations:
|
||||
|
||||
| Narrow | Short | Long |
|
||||
|--------|-------|------|
|
||||
| ❌ | ✅ | ✅ |
|
||||
|
||||
|
||||
## Distance
|
||||
|
||||
|
@ -46,6 +52,12 @@ Android translations are only in English at the moment.
|
|||
| Nautical mile | Android >= 11 | Android 7 to 10 | Android < 7 |
|
||||
| Foot | Android >= 11 | Android 7 to 10 | Android < 7 |
|
||||
|
||||
Supported widths for Android translations:
|
||||
|
||||
| Narrow | Short | Long |
|
||||
|--------|-------|------|
|
||||
| ❌ | ✅ | ✅ |
|
||||
|
||||
|
||||
## Speed
|
||||
|
||||
|
@ -63,6 +75,12 @@ Android translations are only in English at the moment.
|
|||
|
||||
¹ Not an unit, but a scale, so during conversions, uses the starting value in meters per second of the scale level
|
||||
|
||||
Supported widths for Android translations:
|
||||
|
||||
| Narrow | Short | Long |
|
||||
|--------|-------|------|
|
||||
| ❌ | ✅ | ✅ |
|
||||
|
||||
|
||||
## Precipitation
|
||||
|
||||
|
@ -84,6 +102,12 @@ Android translations are only in English at the moment.
|
|||
| Inch per hour | Android >= 11 | Android 8 to 10 | Android < 8 |
|
||||
| Liter per square meter per hour | ❌ | ❌ | ✅ |
|
||||
|
||||
Supported widths for Android translations:
|
||||
|
||||
| Narrow | Short | Long |
|
||||
|--------|-------|------|
|
||||
| ❌ | ✅ | ✅ |
|
||||
|
||||
|
||||
## Pressure
|
||||
|
||||
|
@ -96,6 +120,12 @@ Android translations are only in English at the moment.
|
|||
| Millimeter of mercury | Android >= 11 | Android 7 to 10 | Android < 7 |
|
||||
| Inch of mercury | Android >= 11 | Android 7 to 10 | Android < 7 |
|
||||
|
||||
Supported widths for Android translations:
|
||||
|
||||
| Narrow | Short | Long |
|
||||
|--------|-------|------|
|
||||
| ❌ | ✅ | ✅ |
|
||||
|
||||
|
||||
## Air pollutant concentration
|
||||
|
||||
|
@ -106,6 +136,12 @@ Android translations are only in English at the moment.
|
|||
| Microgram per cubic meter | Android >= 11 | Android 8 to 10 | Android < 8 |
|
||||
| Milligram per cubic meter | Android >= 11 | Android 8 to 10 | Android < 8 |
|
||||
|
||||
Supported widths for Android translations:
|
||||
|
||||
| Narrow | Short | Long |
|
||||
|--------|-------|------|
|
||||
| ❌ | ✅ | ✅ |
|
||||
|
||||
|
||||
## Pollen concentration
|
||||
|
||||
|
@ -115,6 +151,12 @@ Android translations are only in English at the moment.
|
|||
|-----------------|-------------------|-----------------|----------------------|
|
||||
| Per cubic meter | ❌ | ❌ | ✅ |
|
||||
|
||||
Supported widths for Android translations:
|
||||
|
||||
| Narrow | Short | Long |
|
||||
|--------|-------|------|
|
||||
| ❌ | ✅ | ✅ |
|
||||
|
||||
|
||||
## Duration
|
||||
|
||||
|
@ -131,6 +173,29 @@ Android translations are only in English at the moment.
|
|||
* ¹ `NumberFormatter` supports only single duration, and will not be used when needing a formatting like `1 hour and 30 minutes`.
|
||||
* ² Only English translations are provided.
|
||||
|
||||
Supported widths for Android translations:
|
||||
|
||||
| Narrow | Short | Long |
|
||||
|--------|-------|------|
|
||||
| ❌ | ✅ | ✅ |
|
||||
|
||||
|
||||
## Ratio
|
||||
|
||||
| Unit | `NumberFormatter`¹ | `NumberFormat` | Android translations |
|
||||
|----------|--------------------|----------------|----------------------|
|
||||
| Permille | Android >= 11 | ❌ | Android < 11¹ |
|
||||
| Percent | Android >= 11 | Android < 11 | ❌ |
|
||||
| Fraction | Android >= 11 | Android < 11 | N/A |
|
||||
|
||||
* ¹ Only English translations are provided.
|
||||
|
||||
Supported widths for `NumberFormat` and Android translations:
|
||||
|
||||
| Narrow | Short | Long |
|
||||
|--------|-------|------|
|
||||
| ❌ | ✅ | ❌ |
|
||||
|
||||
|
||||
# License
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ value class Distance internal constructor(
|
|||
* No more than [unit.decimals.max] decimals will be shown, even if a larger number is requested.
|
||||
*
|
||||
* @return the value of distance in the specified [unit] followed by that unit abbreviated name:
|
||||
* `pa`, `hpa`, `mb`, `atm`, `mmhg`, `inhg`.
|
||||
* `m`, `km`, `mi`, `nmi`, `ft`.
|
||||
*
|
||||
* @throws IllegalArgumentException if [decimals] is less than zero.
|
||||
*/
|
||||
|
@ -203,8 +203,6 @@ fun Long.toDistance(unit: DistanceUnit): Distance {
|
|||
/**
|
||||
* Returns a [Distance] equal to this [Double] number of the specified [unit].
|
||||
*
|
||||
* Depending on its magnitude, the value is rounded to an integer number of nanoseconds or milliseconds.
|
||||
*
|
||||
* @throws IllegalArgumentException if this `Double` value is `NaN`.
|
||||
*/
|
||||
fun Double.toDistance(unit: DistanceUnit): Distance {
|
||||
|
|
|
@ -61,7 +61,7 @@ value class PollenConcentration internal constructor(
|
|||
* The following format is accepted:
|
||||
*
|
||||
* - The format of string returned by the default [PollenConcentration.toString] and `toString` in a specific unit,
|
||||
* e.g. `1013.25hpa` or `29.95inhg`.
|
||||
* e.g. `24pcum`.
|
||||
*
|
||||
* @throws IllegalArgumentException if the string doesn't represent a pollen concentration in any of the supported formats.
|
||||
*/
|
||||
|
@ -78,7 +78,7 @@ value class PollenConcentration internal constructor(
|
|||
* The following formats is accepted:
|
||||
*
|
||||
* - The format of string returned by the default [PollenConcentration.toString] and `toString` in a specific unit,
|
||||
* e.g. `1013.25hpa` or `29.95inhg`.
|
||||
* e.g. `24pcum`.
|
||||
*/
|
||||
fun parseOrNull(value: String): PollenConcentration? = try {
|
||||
parsePollenConcentration(value)
|
||||
|
@ -125,7 +125,7 @@ value class PollenConcentration internal constructor(
|
|||
* No more than [unit.decimals.max] decimals will be shown, even if a larger number is requested.
|
||||
*
|
||||
* @return the value of pollen concentration in the specified [unit] followed by that unit abbreviated name:
|
||||
* `pa`, `hpa`, `mb`, `atm`, `mmhg`, `inhg`.
|
||||
* `pcum`.
|
||||
*
|
||||
* @throws IllegalArgumentException if [decimals] is less than zero.
|
||||
*/
|
||||
|
@ -151,8 +151,6 @@ fun Long.toPollenConcentration(unit: PollenConcentrationUnit): PollenConcentrati
|
|||
/**
|
||||
* Returns a [PollenConcentration] equal to this [Double] number of the specified [unit].
|
||||
*
|
||||
* Depending on its magnitude, the value is rounded to an integer number of nanoseconds or milliseconds.
|
||||
*
|
||||
* @throws IllegalArgumentException if this `Double` value is `NaN`.
|
||||
*/
|
||||
fun Double.toPollenConcentration(unit: PollenConcentrationUnit): PollenConcentration {
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
package org.breezyweather.unit.pollutant
|
||||
|
||||
import android.content.Context
|
||||
import org.breezyweather.unit.WeatherValue
|
||||
import org.breezyweather.unit.formatting.UnitDecimals.Companion.formatToExactDecimals
|
||||
import org.breezyweather.unit.formatting.UnitWidth
|
||||
import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.microgramsPerCubicMeter
|
||||
import org.breezyweather.unit.pollutant.PollutantConcentration.Companion.milligramsPerCubicMeter
|
||||
import java.util.Locale
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
/*
|
||||
|
@ -74,7 +71,7 @@ value class PollutantConcentration internal constructor(
|
|||
* The following format is accepted:
|
||||
*
|
||||
* - The format of string returned by the default [PollutantConcentration.toString] and `toString` in a specific unit,
|
||||
* e.g. `1013.25hpa` or `29.95inhg`.
|
||||
* e.g. `10microgpcum` or `2mgpcum`.
|
||||
*
|
||||
* @throws IllegalArgumentException if the string doesn't represent a pollutant concentration in any of the supported formats.
|
||||
*/
|
||||
|
@ -91,7 +88,7 @@ value class PollutantConcentration internal constructor(
|
|||
* The following formats is accepted:
|
||||
*
|
||||
* - The format of string returned by the default [PollutantConcentration.toString] and `toString` in a specific unit,
|
||||
* e.g. `1013.25hpa` or `29.95inhg`.
|
||||
* e.g. `10microgpcum` or `2mgpcum`.
|
||||
*/
|
||||
fun parseOrNull(value: String): PollutantConcentration? = try {
|
||||
parsePollutantConcentration(value)
|
||||
|
@ -138,7 +135,7 @@ value class PollutantConcentration internal constructor(
|
|||
* No more than [unit.decimals.max] decimals will be shown, even if a larger number is requested.
|
||||
*
|
||||
* @return the value of pollutant concentration in the specified [unit] followed by that unit abbreviated name:
|
||||
* `pa`, `hpa`, `mb`, `atm`, `mmhg`, `inhg`.
|
||||
* `microgpcum`, `mgpcum`.
|
||||
*
|
||||
* @throws IllegalArgumentException if [decimals] is less than zero.
|
||||
*/
|
||||
|
@ -170,8 +167,6 @@ fun Long.toPollutantConcentration(unit: PollutantConcentrationUnit): PollutantCo
|
|||
/**
|
||||
* Returns a [PollutantConcentration] equal to this [Double] number of the specified [unit].
|
||||
*
|
||||
* Depending on its magnitude, the value is rounded to an integer number of nanoseconds or milliseconds.
|
||||
*
|
||||
* @throws IllegalArgumentException if this `Double` value is `NaN`.
|
||||
*/
|
||||
fun Double.toPollutantConcentration(unit: PollutantConcentrationUnit): PollutantConcentration {
|
||||
|
|
|
@ -105,7 +105,7 @@ value class Precipitation internal constructor(
|
|||
* The following format is accepted:
|
||||
*
|
||||
* - The format of string returned by the default [Precipitation.toString] and `toString` in a specific unit,
|
||||
* e.g. `50000m` or `30.5km`.
|
||||
* e.g. `5mm` or `1cm`.
|
||||
*
|
||||
* @throws IllegalArgumentException if the string doesn't represent a precipitation in any of the supported formats.
|
||||
*/
|
||||
|
@ -122,7 +122,7 @@ value class Precipitation internal constructor(
|
|||
* The following formats is accepted:
|
||||
*
|
||||
* - The format of string returned by the default [Precipitation.toString] and `toString` in a specific unit,
|
||||
* e.g. `50000m` or `30.5km`.
|
||||
* e.g. `5mm` or `1cm`.
|
||||
*/
|
||||
fun parseOrNull(value: String): Precipitation? = try {
|
||||
parsePrecipitation(value)
|
||||
|
@ -181,7 +181,7 @@ value class Precipitation internal constructor(
|
|||
* No more than [unit.decimals.max] decimals will be shown, even if a larger number is requested.
|
||||
*
|
||||
* @return the value of precipitation in the specified [unit] followed by that unit abbreviated name:
|
||||
* `pa`, `hpa`, `mb`, `atm`, `mmhg`, `inhg`.
|
||||
* `microm`, `mm`, `cm`, `in`, `lpsqm`.
|
||||
*
|
||||
* @throws IllegalArgumentException if [decimals] is less than zero.
|
||||
*/
|
||||
|
@ -317,8 +317,6 @@ fun Long.toPrecipitation(unit: PrecipitationUnit): Precipitation {
|
|||
/**
|
||||
* Returns a [Precipitation] equal to this [Double] number of the specified [unit].
|
||||
*
|
||||
* Depending on its magnitude, the value is rounded to an integer number of nanoseconds or milliseconds.
|
||||
*
|
||||
* @throws IllegalArgumentException if this `Double` value is `NaN`.
|
||||
*/
|
||||
fun Double.toPrecipitation(unit: PrecipitationUnit): Precipitation {
|
||||
|
|
|
@ -228,8 +228,6 @@ fun Long.toPressure(unit: PressureUnit): Pressure {
|
|||
/**
|
||||
* Returns a [Pressure] equal to this [Double] number of the specified [unit].
|
||||
*
|
||||
* Depending on its magnitude, the value is rounded to an integer number of nanoseconds or milliseconds.
|
||||
*
|
||||
* @throws IllegalArgumentException if this `Double` value is `NaN`.
|
||||
*/
|
||||
fun Double.toPressure(unit: PressureUnit): Pressure {
|
||||
|
|
194
weather-unit/src/main/java/org/breezyweather/unit/ratio/Ratio.kt
Normal file
194
weather-unit/src/main/java/org/breezyweather/unit/ratio/Ratio.kt
Normal file
|
@ -0,0 +1,194 @@
|
|||
package org.breezyweather.unit.ratio
|
||||
|
||||
import org.breezyweather.unit.WeatherValue
|
||||
import org.breezyweather.unit.formatting.UnitDecimals.Companion.formatToExactDecimals
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.fraction
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.percent
|
||||
import org.breezyweather.unit.ratio.Ratio.Companion.permille
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents the ratio.
|
||||
*
|
||||
* To construct a ratio, use either the extension function [toRatio],
|
||||
* or the extension properties [permille], [percent] and [fraction],
|
||||
* available on [Int], [Long], and [Double] numeric types.
|
||||
*
|
||||
* To get the value of this ratio expressed in a particular [ratio unit][RatioUnit]
|
||||
* use the functions [toInt], [toLong], and [toDouble]
|
||||
* or the properties [inPermille], [inPercent] and [inFraction].
|
||||
*/
|
||||
@JvmInline
|
||||
value class Ratio internal constructor(
|
||||
private val rawValue: Long,
|
||||
) : Comparable<Ratio>, WeatherValue<RatioUnit> {
|
||||
val value: Long get() = rawValue
|
||||
private val storageUnit get() = RatioUnit.PERMILLE
|
||||
|
||||
companion object {
|
||||
/** Returns a [Ratio] equal to this [Int] number of permille. */
|
||||
inline val Int.permille: Ratio get() = toRatio(RatioUnit.PERMILLE)
|
||||
|
||||
/** Returns a [Ratio] equal to this [Long] number of permille. */
|
||||
inline val Long.permille: Ratio get() = toRatio(RatioUnit.PERMILLE)
|
||||
|
||||
/** Returns a [Ratio] equal to this [Double] number of permille. */
|
||||
inline val Double.permille: Ratio get() = toRatio(RatioUnit.PERMILLE)
|
||||
|
||||
/** Returns a [Ratio] equal to this [Int] number of percent. */
|
||||
inline val Int.percent: Ratio get() = toRatio(RatioUnit.PERCENT)
|
||||
|
||||
/** Returns a [Ratio] equal to this [Long] number of percent. */
|
||||
inline val Long.percent: Ratio get() = toRatio(RatioUnit.PERCENT)
|
||||
|
||||
/** Returns a [Ratio] equal to this [Double] number of percent. */
|
||||
inline val Double.percent: Ratio get() = toRatio(RatioUnit.PERCENT)
|
||||
|
||||
/** Returns a [Ratio] equal to this [Int] number of fraction. */
|
||||
inline val Int.fraction: Ratio get() = toRatio(RatioUnit.FRACTION)
|
||||
|
||||
/** Returns a [Ratio] equal to this [Long] number of fraction. */
|
||||
inline val Long.fraction: Ratio get() = toRatio(RatioUnit.FRACTION)
|
||||
|
||||
/** Returns a [Ratio] equal to this [Double] number of percent. */
|
||||
inline val Double.fraction: Ratio get() = toRatio(RatioUnit.FRACTION)
|
||||
|
||||
/**
|
||||
* Parses a string that represents a ratio and returns the parsed [Ratio] value.
|
||||
*
|
||||
* The following format is accepted:
|
||||
*
|
||||
* - The format of string returned by the default [Ratio.toString] and `toString` in a specific unit,
|
||||
* e.g. `30percent` or `542permille`.
|
||||
*
|
||||
* @throws IllegalArgumentException if the string doesn't represent a ratio in any of the supported formats.
|
||||
*/
|
||||
fun parse(value: String): Ratio = try {
|
||||
parseRatio(value)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
throw IllegalArgumentException("Invalid ratio string format: '$value'.", e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string that represents a ratio and returns the parsed [Ratio] value,
|
||||
* or `null` if the string doesn't represent a ratio in any of the supported formats.
|
||||
*
|
||||
* The following formats is accepted:
|
||||
*
|
||||
* - The format of string returned by the default [Ratio.toString] and `toString` in a specific unit,
|
||||
* e.g. `30percent` or `542permille`.
|
||||
*/
|
||||
fun parseOrNull(value: String): Ratio? = try {
|
||||
parseRatio(value)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun compareTo(other: Ratio): Int {
|
||||
return this.rawValue.compareTo(other.rawValue)
|
||||
}
|
||||
|
||||
// conversion to units
|
||||
|
||||
/**
|
||||
* Returns the value of this ratio expressed as a [Double] number of the specified [unit].
|
||||
*
|
||||
* The operation may involve rounding when the result cannot be represented exactly with a [Double] number.
|
||||
*/
|
||||
override fun toDouble(unit: RatioUnit): Double {
|
||||
return convertRatioUnit(value.toDouble(), storageUnit, unit)
|
||||
}
|
||||
|
||||
/** The value of this ratio expressed as a [Double] number of permille. */
|
||||
val inPermille: Double
|
||||
get() = toDouble(RatioUnit.PERMILLE)
|
||||
|
||||
/** The value of this ratio expressed as a [Double] number of percent. */
|
||||
val inPercent: Double
|
||||
get() = toDouble(RatioUnit.PERCENT)
|
||||
|
||||
/** The value of this ratio expressed as a [Double] number of fraction. */
|
||||
val inFraction: Double
|
||||
get() = toDouble(RatioUnit.FRACTION)
|
||||
|
||||
/**
|
||||
* Returns a string representation of this ratio value
|
||||
*/
|
||||
override fun toString(): String {
|
||||
return toString(storageUnit)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this ratio value expressed in the given [unit]
|
||||
* and formatted with the specified [decimals] number of digits after decimal point.
|
||||
*
|
||||
* @param decimals the number of digits after decimal point to show. The value must be non-negative.
|
||||
* No more than [unit.decimals.max] decimals will be shown, even if a larger number is requested.
|
||||
*
|
||||
* @return the value of ratio in the specified [unit] followed by that unit abbreviated name:
|
||||
* `fraction`, `percent`, `permille`.
|
||||
*
|
||||
* @throws IllegalArgumentException if [decimals] is less than zero.
|
||||
*/
|
||||
fun toString(unit: RatioUnit, decimals: Int = unit.decimals.short): String {
|
||||
require(decimals >= 0) { "decimals must be not negative, but was $decimals" }
|
||||
return formatToExactDecimals(toDouble(unit), decimals.coerceAtMost(unit.decimals.long)) + unit.id
|
||||
}
|
||||
|
||||
/**
|
||||
* Return null if the value is not between the provided range, otherwise this value
|
||||
*/
|
||||
fun toValidRangeOrNull(range: IntRange = 0..1000): Ratio? {
|
||||
return takeIf { rawValue in range }
|
||||
}
|
||||
}
|
||||
|
||||
// constructing from number of units
|
||||
// extension functions
|
||||
|
||||
/** Returns a [Ratio] equal to this [Int] number of the specified [unit]. */
|
||||
fun Int.toRatio(unit: RatioUnit): Ratio {
|
||||
return toLong().toRatio(unit)
|
||||
}
|
||||
|
||||
/** Returns a [Ratio] equal to this [Long] number of the specified [unit]. */
|
||||
fun Long.toRatio(unit: RatioUnit): Ratio {
|
||||
return ratioOf(convertRatioUnit(this.toDouble(), unit, RatioUnit.PERMILLE).toLong())
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a [Ratio] equal to this [Double] number of the specified [unit].
|
||||
*
|
||||
* @throws IllegalArgumentException if this `Double` value is `NaN`.
|
||||
*/
|
||||
fun Double.toRatio(unit: RatioUnit): Ratio {
|
||||
val valueInPermille = convertRatioUnit(this, unit, RatioUnit.PERMILLE)
|
||||
require(!valueInPermille.isNaN()) { "Ratio value cannot be NaN." }
|
||||
return ratioOf(valueInPermille.roundToLong())
|
||||
}
|
||||
|
||||
private fun parseRatio(value: String): Ratio {
|
||||
var length = value.length
|
||||
if (length == 0) throw IllegalArgumentException("The string is empty")
|
||||
|
||||
TODO()
|
||||
}
|
||||
|
||||
private fun ratioOf(normalPermille: Long) = Ratio(normalPermille)
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* 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 org.breezyweather.unit.ratio
|
||||
|
||||
import android.content.Context
|
||||
import android.icu.text.NumberFormat
|
||||
import android.icu.util.MeasureUnit
|
||||
import android.os.Build
|
||||
import org.breezyweather.unit.R
|
||||
import org.breezyweather.unit.WeatherUnit
|
||||
import org.breezyweather.unit.formatting.UnitDecimals
|
||||
import org.breezyweather.unit.formatting.UnitTranslation
|
||||
import org.breezyweather.unit.formatting.UnitWidth
|
||||
import org.breezyweather.unit.formatting.format
|
||||
import org.breezyweather.unit.formatting.formatWithNumberFormatter
|
||||
import java.util.Locale
|
||||
|
||||
enum class RatioUnit(
|
||||
override val id: String,
|
||||
override val displayName: UnitTranslation,
|
||||
override val nominative: UnitTranslation,
|
||||
override val per: UnitTranslation? = null,
|
||||
override val measureUnit: MeasureUnit?,
|
||||
override val perMeasureUnit: MeasureUnit? = null,
|
||||
val convertFromReference: (Double) -> Double,
|
||||
val convertToReference: (Double) -> Double,
|
||||
override val decimals: UnitDecimals,
|
||||
val chartStep: Double,
|
||||
) : WeatherUnit {
|
||||
|
||||
PERMILLE(
|
||||
id = "permille",
|
||||
displayName = UnitTranslation(R.string.ratio_permille_display_name_short),
|
||||
nominative = UnitTranslation(R.string.ratio_permille_nominative_short),
|
||||
measureUnit = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) MeasureUnit.PERMILLE else null,
|
||||
convertFromReference = { valueInDefaultUnit -> valueInDefaultUnit },
|
||||
convertToReference = { valueInThisUnit -> valueInThisUnit },
|
||||
decimals = UnitDecimals(0),
|
||||
chartStep = 200.0
|
||||
),
|
||||
PERCENT(
|
||||
id = "percent",
|
||||
displayName = UnitTranslation(R.string.ratio_percent_display_name_short),
|
||||
nominative = UnitTranslation(R.string.ratio_percent_nominative_short),
|
||||
measureUnit = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) MeasureUnit.PERCENT else null,
|
||||
convertFromReference = { valueInDefaultUnit -> valueInDefaultUnit.div(10.0) },
|
||||
convertToReference = { valueInThisUnit -> valueInThisUnit.times(10.0) },
|
||||
decimals = UnitDecimals(narrow = 0, short = 1, long = 1),
|
||||
chartStep = 20.0
|
||||
),
|
||||
FRACTION(
|
||||
id = "fraction",
|
||||
displayName = UnitTranslation(R.string.ratio_fraction_display_name_short),
|
||||
nominative = UnitTranslation(R.string.ratio_fraction_nominative_short),
|
||||
measureUnit = null,
|
||||
convertFromReference = { valueInDefaultUnit -> valueInDefaultUnit.div(1000.0) },
|
||||
convertToReference = { valueInThisUnit -> valueInThisUnit.times(1000.0) },
|
||||
decimals = UnitDecimals(narrow = 1, short = 2, long = 3),
|
||||
chartStep = 0.2
|
||||
),
|
||||
;
|
||||
|
||||
/**
|
||||
* @param useMeasureFormat ignored, never supported
|
||||
*/
|
||||
override fun format(
|
||||
context: Context,
|
||||
value: Number,
|
||||
valueWidth: UnitWidth,
|
||||
unitWidth: UnitWidth,
|
||||
locale: Locale,
|
||||
showSign: Boolean,
|
||||
useNumberFormatter: Boolean,
|
||||
useMeasureFormat: Boolean,
|
||||
): String {
|
||||
if (this == FRACTION) {
|
||||
return value.format(
|
||||
decimals = getPrecision(valueWidth),
|
||||
locale = locale,
|
||||
showSign = showSign,
|
||||
useNumberFormatter = useNumberFormatter,
|
||||
useMeasureFormat = useMeasureFormat
|
||||
)
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && useNumberFormatter) {
|
||||
return measureUnit!!.formatWithNumberFormatter(
|
||||
locale = locale,
|
||||
value = value,
|
||||
perUnit = null,
|
||||
precision = getPrecision(valueWidth),
|
||||
numberFormatterWidth = unitWidth.numberFormatterWidth!!,
|
||||
showSign = showSign
|
||||
)
|
||||
}
|
||||
|
||||
if (this == PERCENT && !showSign) {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
NumberFormat.getPercentInstance(locale)
|
||||
.apply { maximumFractionDigits = getPrecision(valueWidth) }
|
||||
.format(if (value.toDouble() > 0) value.toDouble().div(100.0) else 0)
|
||||
} else {
|
||||
java.text.NumberFormat.getPercentInstance(locale)
|
||||
.apply { maximumFractionDigits = getPrecision(valueWidth) }
|
||||
.format(if (value.toDouble() > 0) value.toDouble().div(100.0) else 0)
|
||||
}
|
||||
}
|
||||
|
||||
return formatWithAndroidTranslations(
|
||||
context = context,
|
||||
value = value,
|
||||
valueWidth = valueWidth,
|
||||
unitWidth = unitWidth,
|
||||
locale = locale,
|
||||
showSign = showSign,
|
||||
useNumberFormatter = useNumberFormatter,
|
||||
useMeasureFormat = useMeasureFormat
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun getUnit(id: String): RatioUnit? {
|
||||
return entries.firstOrNull { it.id == id }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Converts the given time ratio [value] expressed in the specified [sourceUnit] into the specified [targetUnit]. */
|
||||
internal fun convertRatioUnit(
|
||||
value: Double,
|
||||
sourceUnit: RatioUnit,
|
||||
targetUnit: RatioUnit,
|
||||
): Double {
|
||||
return if (sourceUnit == RatioUnit.PERMILLE) {
|
||||
targetUnit.convertFromReference(value)
|
||||
} else if (targetUnit == RatioUnit.PERMILLE) {
|
||||
sourceUnit.convertToReference(value)
|
||||
} else {
|
||||
targetUnit.convertFromReference(sourceUnit.convertToReference(value))
|
||||
}
|
||||
}
|
|
@ -112,7 +112,7 @@ value class Speed internal constructor(
|
|||
* The following format is accepted:
|
||||
*
|
||||
* - The format of string returned by the default [Speed.toString] and `toString` in a specific unit,
|
||||
* e.g. `50000m` or `30.5km`.
|
||||
* e.g. `4.2mps` or `30.5kph`.
|
||||
*
|
||||
* @throws IllegalArgumentException if the string doesn't represent a speed in any of the supported formats.
|
||||
*/
|
||||
|
@ -129,7 +129,7 @@ value class Speed internal constructor(
|
|||
* The following formats is accepted:
|
||||
*
|
||||
* - The format of string returned by the default [Speed.toString] and `toString` in a specific unit,
|
||||
* e.g. `50000m` or `30.5km`.
|
||||
* e.g. `4.2mps` or `30.5kph`.
|
||||
*/
|
||||
fun parseOrNull(value: String): Speed? = try {
|
||||
parseSpeed(value)
|
||||
|
@ -196,7 +196,7 @@ value class Speed internal constructor(
|
|||
* No more than [unit.decimals.max] decimals will be shown, even if a larger number is requested.
|
||||
*
|
||||
* @return the value of speed in the specified [unit] followed by that unit abbreviated name:
|
||||
* `pa`, `hpa`, `mb`, `atm`, `mmhg`, `inhg`.
|
||||
* `cmps`, `mps`, `kph`, `mph`, `kn`, `ftps`, `bf`.
|
||||
*
|
||||
* @throws IllegalArgumentException if [decimals] is less than zero.
|
||||
*/
|
||||
|
@ -229,8 +229,6 @@ fun Long.toSpeed(unit: SpeedUnit): Speed {
|
|||
/**
|
||||
* Returns a [Speed] equal to this [Double] number of the specified [unit].
|
||||
*
|
||||
* Depending on its magnitude, the value is rounded to an integer number of nanoseconds or milliseconds.
|
||||
*
|
||||
* @throws IllegalArgumentException if this `Double` value is `NaN`.
|
||||
*/
|
||||
fun Double.toSpeed(unit: SpeedUnit): Speed {
|
||||
|
|
|
@ -81,7 +81,7 @@ value class Temperature internal constructor(
|
|||
* The following format is accepted:
|
||||
*
|
||||
* - The format of string returned by the default [Temperature.toString] and `toString` in a specific unit,
|
||||
* e.g. `1013.25hpa` or `29.95inhg`.
|
||||
* e.g. `32c` or `273.15k`.
|
||||
*
|
||||
* @throws IllegalArgumentException if the string doesn't represent a temperature in any of the supported formats.
|
||||
*/
|
||||
|
@ -98,7 +98,7 @@ value class Temperature internal constructor(
|
|||
* The following formats is accepted:
|
||||
*
|
||||
* - The format of string returned by the default [Temperature.toString] and `toString` in a specific unit,
|
||||
* e.g. `1013.25hpa` or `29.95inhg`.
|
||||
* e.g. `32c` or `273.15k`.
|
||||
*/
|
||||
fun parseOrNull(value: String): Temperature? = try {
|
||||
parseTemperature(value)
|
||||
|
@ -163,7 +163,7 @@ value class Temperature internal constructor(
|
|||
* No more than [unit.decimals.max] decimals will be shown, even if a larger number is requested.
|
||||
*
|
||||
* @return the value of temperature in the specified [unit] followed by that unit abbreviated name:
|
||||
* `pa`, `hpa`, `mb`, `atm`, `mmhg`, `inhg`.
|
||||
* `dc`, `c`, `f`, `k`.
|
||||
*
|
||||
* @throws IllegalArgumentException if [decimals] is less than zero.
|
||||
*/
|
||||
|
@ -196,8 +196,6 @@ fun Long.toTemperature(unit: TemperatureUnit): Temperature {
|
|||
/**
|
||||
* Returns a [Temperature] equal to this [Double] number of the specified [unit].
|
||||
*
|
||||
* Depending on its magnitude, the value is rounded to an integer number of nanoseconds or milliseconds.
|
||||
*
|
||||
* @throws IllegalArgumentException if this `Double` value is `NaN`.
|
||||
*/
|
||||
fun Double.toTemperature(unit: TemperatureUnit): Temperature {
|
||||
|
|
|
@ -178,7 +178,7 @@
|
|||
<string name="pressure_inhg_nominative_short">%s inHg</string>
|
||||
<string name="pressure_inhg_nominative_long">@string/pressure_inhg_nominative_short</string>
|
||||
|
||||
<!-- Duration units TODO: In other languages -->
|
||||
<!-- Duration units -->
|
||||
|
||||
<!-- Days / Not used in Breezy Weather, so not translating -->
|
||||
<string name="duration_day_display_name_short" translatable="false">day</string>
|
||||
|
@ -230,4 +230,18 @@
|
|||
<string name="duration_ns_nominative_short" translatable="false">%s ns</string>
|
||||
<string name="duration_ns_nominative_long" translatable="false">@string/duration_ns_nominative_short</string>
|
||||
|
||||
<!-- Ratio units -->
|
||||
|
||||
<!-- Permille -->
|
||||
<string name="ratio_permille_display_name_short" translatable="false">‰</string>
|
||||
<string name="ratio_permille_nominative_short" translatable="false">%s ‰</string>
|
||||
|
||||
<!-- Percent -->
|
||||
<string name="ratio_percent_display_name_short" translatable="false">%</string>
|
||||
<string name="ratio_percent_nominative_short" translatable="false">%s %</string>
|
||||
|
||||
<!-- Fragment -->
|
||||
<string name="ratio_fraction_display_name_short" translatable="false">/</string>
|
||||
<string name="ratio_fraction_nominative_short" translatable="false">%s</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue