From b6cb4791b766fa810e37e4b7784dbdba7bd5b298 Mon Sep 17 00:00:00 2001 From: nizienko Date: Wed, 19 Jun 2024 23:49:24 +0200 Subject: [PATCH] added pressure, weather code, fixed minor bugs --- build.gradle.kts | 2 +- src/main/kotlin/services/WeatherCode.kt | 35 +++++++++++++++++++ src/main/kotlin/services/WeatherService.kt | 35 +++++++++++++------ .../settings/WeatherWidgetConfigurable.kt | 13 +++++-- .../settings/WeatherWidgetSettingsState.kt | 17 ++++++++- src/main/kotlin/widget/Widget.kt | 32 +++++++++++++---- 6 files changed, 112 insertions(+), 22 deletions(-) create mode 100644 src/main/kotlin/services/WeatherCode.kt diff --git a/build.gradle.kts b/build.gradle.kts index 54427e9..dc3b2ef 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "com.guthub.nizienko" -version = "1.0.1" +version = "1.0.3" repositories { mavenCentral() diff --git a/src/main/kotlin/services/WeatherCode.kt b/src/main/kotlin/services/WeatherCode.kt new file mode 100644 index 0000000..7d50f0c --- /dev/null +++ b/src/main/kotlin/services/WeatherCode.kt @@ -0,0 +1,35 @@ +package services + +object WeatherCode { + fun get(code: Int): String = when (code) { + 0 -> "Clear sky" + 1 -> "Mainly clear" + 2 -> "Partly cloudy" + 3 -> "Overcast" + 45 -> "Fog" + 48 -> "Depositing rime fog" + 51 -> "Light drizzle" + 53 -> "Moderate drizzle" + 55 -> "Dense intensity drizzle" + 56 -> "Light freezing drizzle" + 57 -> "Dense freezing drizzle" + 61 -> "Slight rain" + 63 -> "Moderate rain" + 65 -> "Heavy rain" + 66 -> "Light freezing rain" + 67 -> "Heavy freezing rain" + 71 -> "Slight snow fall" + 73 -> "Moderate snow fall" + 75 -> "Heavy snow fall" + 77 -> "Snow grains" + 80 -> "Slight rain showers" + 81 -> "Moderate rain showers" + 82 -> "Violent rain showers" + 85 -> "Slight Snow showers" + 86 -> "Heavy Snow showers" + 95 -> "Thunderstorm" + 96 -> "Thunderstorm with slight hail" + 99 -> "Thunderstorm with heavy hail" + else -> "___" + } +} \ No newline at end of file diff --git a/src/main/kotlin/services/WeatherService.kt b/src/main/kotlin/services/WeatherService.kt index 248f903..0130c4e 100644 --- a/src/main/kotlin/services/WeatherService.kt +++ b/src/main/kotlin/services/WeatherService.kt @@ -1,5 +1,6 @@ package services +import com.intellij.openapi.application.invokeLater import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.openmeteo.api.Forecast @@ -44,8 +45,10 @@ class WeatherService(coroutineScope: CoroutineScope) { fun update() { activeWidget?.let { cachedRainData = loadWeather() - activeWidget?.repaint() - activeWidget?.revalidate() + invokeLater { + activeWidget?.revalidate() + activeWidget?.repaint() + } } } @@ -55,11 +58,11 @@ class WeatherService(coroutineScope: CoroutineScope) { private var lastAttempt: Long = 0L private fun loadWeather(): WeatherData { return try { - WeatherData.Present(WeatherClient(settings).getRainData()) - .also { - lastUpdate = System.currentTimeMillis() - lastAttempt = System.currentTimeMillis() - } + val data = WeatherClient(settings).getRainData() + WeatherData.Present(data).also { + lastUpdate = System.currentTimeMillis() + lastAttempt = System.currentTimeMillis() + } } catch (e: Throwable) { lastAttempt = System.currentTimeMillis() val error = buildString { @@ -78,7 +81,15 @@ sealed interface WeatherData { class Error(val message: String) : WeatherData } -data class HourData(val rain: Double, val temperature: Double, val wind: Double, val windDirection: Double) +data class HourData( + val rain: Double, + val temperature: Double, + val wind: Double, + val windDirection: Double, + val weatherCode: Int, + val surfacePressure: Double, +) + class WeatherClient(private val settings: WeatherWidgetSettingsState) { private val client = OpenMeteo(settings.latitude, settings.longitude) @@ -86,7 +97,7 @@ class WeatherClient(private val settings: WeatherWidgetSettingsState) { fun getRainData(): List> { val forecast = client.forecast { hourly = Forecast.Hourly { - listOf(precipitation, temperature2m, windspeed10m, winddirection10m) + listOf(precipitation, temperature2m, windspeed10m, winddirection10m, weathercode, surfacePressure) } forecastDays = 2 temperatureUnit = settings.temperatureUnit @@ -99,12 +110,16 @@ class WeatherClient(private val settings: WeatherWidgetSettingsState) { val temperature = forecast.hourly.getValue(temperature2m).values.filter { (t, _) -> t.time > now } val wind = forecast.hourly.getValue(windspeed10m).values.filter { (t, _) -> t.time > now } val windDirection = forecast.hourly.getValue(winddirection10m).values.filter { (t, _) -> t.time > now } + val weatherCode = forecast.hourly.getValue(weathercode).values.filter { (t, _) -> t.time > now } + val surfacePressure = forecast.hourly.getValue(surfacePressure).values.filter { (t, _) -> t.time > now } val merged = precipitationData.map { it.key to HourData( it.value!!, temperature[it.key] ?: 0.0, wind[it.key] ?: 0.0, - windDirection[it.key] ?: 0.0 + windDirection[it.key] ?: 0.0, + weatherCode[it.key]?.toInt() ?: 0, + surfacePressure[it.key] ?: 0.0 ) } forecast.hourly.getValue(precipitation).run { diff --git a/src/main/kotlin/settings/WeatherWidgetConfigurable.kt b/src/main/kotlin/settings/WeatherWidgetConfigurable.kt index 4b2474a..088ee30 100644 --- a/src/main/kotlin/settings/WeatherWidgetConfigurable.kt +++ b/src/main/kotlin/settings/WeatherWidgetConfigurable.kt @@ -6,11 +6,9 @@ import com.intellij.openapi.options.Configurable import com.intellij.openapi.ui.MessageType import com.intellij.openapi.ui.popup.util.PopupUtil import com.intellij.ui.ColorPanel -import com.intellij.ui.ColorPicker import com.intellij.ui.components.JBCheckBox +import com.intellij.ui.components.JBLabel import com.intellij.ui.components.JBTextField -import com.intellij.ui.tabs.ColorSelectionComponent -import com.intellij.ui.util.preferredWidth import com.intellij.util.ui.FormBuilder import com.intellij.util.ui.components.BorderLayoutPanel import com.openmeteo.api.common.units.TemperatureUnit @@ -40,6 +38,7 @@ class WeatherWidgetConfigurable : Configurable { || ui.colorPicker.selectedColor != settings.rainBarColor || ui.temperatureUnit.selectedItem != settings.temperatureUnit || ui.windSpeedUnit.selectedItem != settings.windSpeedUnit + || ui.pressureUnit.selectedItem != settings.pressureUnit } override fun apply() { @@ -53,6 +52,7 @@ class WeatherWidgetConfigurable : Configurable { settings.rainBarColor = ui.colorPicker.selectedColor ?: settings.rainBarColor settings.temperatureUnit = ui.temperatureUnit.selectedItem as TemperatureUnit settings.windSpeedUnit = ui.windSpeedUnit.selectedItem as WindSpeedUnit + settings.pressureUnit = ui.pressureUnit.selectedItem as PressureUnit service().update() } @@ -132,6 +132,12 @@ private class SettingsComponent(settingsState: WeatherWidgetSettingsState) : Dis selectedItem = settingsState.windSpeedUnit } + val pressureUnit = JComboBox().apply { + PressureUnit.entries.forEach { addItem(it) } + selectedItem = settingsState.pressureUnit + setRenderer { _, value, _, _, _ -> JBLabel(value.value) } + } + val cityName = JBTextField(settingsState.cityName) fun getHours(): Int = hours.value as Int @@ -148,6 +154,7 @@ private class SettingsComponent(settingsState: WeatherWidgetSettingsState) : Dis .addSeparator() .addLabeledComponent("Show temperature", showTemperature) .addLabeledComponent("Temperature unit", temperatureUnit) + .addLabeledComponent("Pressure unit", pressureUnit) .addSeparator() .addLabeledComponent("Precipitation bars color", colorPicker) .panel.let { diff --git a/src/main/kotlin/settings/WeatherWidgetSettingsState.kt b/src/main/kotlin/settings/WeatherWidgetSettingsState.kt index ae3a80b..34bfa82 100644 --- a/src/main/kotlin/settings/WeatherWidgetSettingsState.kt +++ b/src/main/kotlin/settings/WeatherWidgetSettingsState.kt @@ -33,6 +33,9 @@ class WeatherWidgetSettingsState : PersistentStateComponent() } @@ -74,4 +77,16 @@ internal class WindSpeedUnitConverter : Converter() { override fun toString(value: WindSpeedUnit): String { return value.name } -} \ No newline at end of file +} + +internal class PressureUnitConverter : Converter() { + override fun fromString(value: String): PressureUnit { + return PressureUnit.valueOf(value) + } + + override fun toString(value: PressureUnit): String { + return value.name + } +} + +enum class PressureUnit(val value: String, val multiplier: Double) { MMHG("mmHg", 0.75006375541921), HPA("hPa", 1.0)} diff --git a/src/main/kotlin/widget/Widget.kt b/src/main/kotlin/widget/Widget.kt index 082e6c1..ef0d36c 100644 --- a/src/main/kotlin/widget/Widget.kt +++ b/src/main/kotlin/widget/Widget.kt @@ -18,7 +18,7 @@ import com.intellij.openapi.wm.StatusBarWidgetFactory import com.intellij.openapi.wm.impl.status.TextPanel import com.intellij.ui.InplaceButton import com.intellij.ui.NewUI -import com.intellij.ui.awt.RelativePoint +import com.intellij.ui.awt.AnchoredPoint import com.intellij.ui.components.JBLabel import com.intellij.util.ui.JBUI import com.intellij.util.ui.UIUtil @@ -27,8 +27,10 @@ import com.openmeteo.api.common.time.Time import com.openmeteo.api.common.units.TemperatureUnit import com.openmeteo.api.common.units.WindSpeedUnit import services.HourData +import services.WeatherCode import services.WeatherData import services.WeatherService +import settings.PressureUnit import settings.WeatherWidgetConfigurable import settings.WeatherWidgetSettingsState import java.awt.* @@ -95,7 +97,7 @@ class WidgetComponent(private val model: WidgetModel) : JPanel(), Disposable { append("") append("") if (isPrecipitationExpected) append("") - append("") + append("") weatherData.forEach { (time, hourData) -> append("") append("") if (isPrecipitationExpected) { append("") + if (hourData.weatherCode > 3) append(WeatherCode.get(hourData.weatherCode) + " ") + if (hourData.rain > 0.0) { + append(hourData.rain) + append(" mm") + } + append("") } append("") + append("") @@ -144,7 +153,11 @@ class WidgetComponent(private val model: WidgetModel) : JPanel(), Disposable { is WeatherData.Present -> JBUI.CurrentTheme.GotItTooltip.foreground(true) } val panel = BorderLayoutPanel() - val title = JBLabel("

${model.city}

", UIUtil.ComponentStyle.LARGE) + val weather = when(val rainData = model.rainData) { + is WeatherData.Error -> "" + is WeatherData.Present -> rainData.data[0].second.weatherCode.let { WeatherCode.get(it.toInt()) } + } + val title = JBLabel("

$weather in ${model.city}

", UIUtil.ComponentStyle.LARGE) val settingsButton = InplaceButton( IconButton( "Settings", @@ -172,7 +185,7 @@ class WidgetComponent(private val model: WidgetModel) : JPanel(), Disposable { .setCornerRadius(JBUI.scale(8)) .setFadeoutTime(10_000) .createBalloon() - .show(RelativePoint.getCenterOf(this@WidgetComponent), Balloon.Position.above) + .show(AnchoredPoint(AnchoredPoint.Anchor.TOP, this@WidgetComponent), Balloon.Position.above) } } @@ -194,6 +207,7 @@ class WidgetComponent(private val model: WidgetModel) : JPanel(), Disposable { } override fun paint(g: Graphics) { + g.clearRect(0, 0, width, height) g.font = TextPanel.getFont() super.paintComponents(g) setupAntialiasing(g) @@ -313,4 +327,8 @@ class WidgetModel { get() = settings.temperatureUnit val windSpeedUnit get() = settings.windSpeedUnit -} \ No newline at end of file + val pressureUnit + get() = settings.pressureUnit +} + +private fun Double.recalculate(unit: PressureUnit) = this * unit.multiplier \ No newline at end of file
TimeTempPrecipitationWind
PressureWind
") @@ -109,10 +111,17 @@ class WidgetComponent(private val model: WidgetModel) : JPanel(), Disposable { append("") - append(hourData.rain) - append(" mm") + append(hourData.surfacePressure.recalculate(model.pressureUnit).roundToInt().toString() + " " + model.pressureUnit.value) + append("") append(hourData.wind.roundToInt()) append(" " + windSpeedUnitText(model.windSpeedUnit)) append("