diff options
author | Wolfgang Müller | 2024-10-19 20:52:09 +0200 |
---|---|---|
committer | Wolfgang Müller | 2024-10-19 20:52:09 +0200 |
commit | a8e7092c765db51409ae26696c7d536a365116f1 (patch) | |
tree | 7f13f56fbde9af9392e4b561da487a8d96cf0183 | |
parent | 99f8caa6aecf66ed98202826e6629c3695c09306 (diff) | |
download | portage-roles-a8e7092c765db51409ae26696c7d536a365116f1.tar.gz |
desktop-plasma: Add patches related to the DWD ion
These fix two small issues and introduce support for night-time icons.
They've been merged upstream [1] but will only be available in 6.3.
[1] https://invent.kde.org/plasma/plasma-workspace/-/merge_requests/4848
3 files changed, 317 insertions, 0 deletions
diff --git a/desktop-plasma/patches/kde-plasma/plasma-workspace/0001-weather-dwd-fix-icon-for-condition-2.patch b/desktop-plasma/patches/kde-plasma/plasma-workspace/0001-weather-dwd-fix-icon-for-condition-2.patch new file mode 100644 index 0000000..382ac00 --- /dev/null +++ b/desktop-plasma/patches/kde-plasma/plasma-workspace/0001-weather-dwd-fix-icon-for-condition-2.patch @@ -0,0 +1,69 @@ +From 2af745e41bf2639a3a4a81855f500ce147a3a731 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Wolfgang=20M=C3=BCller?= <wolf@oriole.systems> +Date: Tue, 15 Oct 2024 18:38:57 +0200 +Subject: [PATCH 1/3] weather/dwd: fix icon for condition 2 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Condition 2, "Sonne, leicht bewölkt", indicates a sunny day with few +clouds. Use the more specific FewCloudsDay condition icon instead of +PartlyCloudyDay, which is already correctly used for condition 3. +--- + dataengines/weather/ions/dwd/ion_dwd.cpp | 40 ++++++------------------ + 1 file changed, 10 insertions(+), 30 deletions(-) + +diff --git a/dataengines/weather/ions/dwd/ion_dwd.cpp b/dataengines/weather/ions/dwd/ion_dwd.cpp +index 83e193d70b..5909b5f5e9 100644 +--- a/dataengines/weather/ions/dwd/ion_dwd.cpp ++++ b/dataengines/weather/ions/dwd/ion_dwd.cpp +@@ -86,36 +86,16 @@ QMap<QString, IonInterface::ConditionIcons> DWDIon::setupDayIconMappings() const + { + // DWD supplies it's own icon number which we can use to determine a condition + +- return QMap<QString, ConditionIcons>{{QStringLiteral("1"), ClearDay}, +- {QStringLiteral("2"), PartlyCloudyDay}, +- {QStringLiteral("3"), PartlyCloudyDay}, +- {QStringLiteral("4"), Overcast}, +- {QStringLiteral("5"), Mist}, +- {QStringLiteral("6"), Mist}, +- {QStringLiteral("7"), LightRain}, +- {QStringLiteral("8"), Rain}, +- {QStringLiteral("9"), Rain}, +- {QStringLiteral("10"), LightRain}, +- {QStringLiteral("11"), Rain}, +- {QStringLiteral("12"), Flurries}, +- {QStringLiteral("13"), RainSnow}, +- {QStringLiteral("14"), LightSnow}, +- {QStringLiteral("15"), Snow}, +- {QStringLiteral("16"), Snow}, +- {QStringLiteral("17"), Hail}, +- {QStringLiteral("18"), LightRain}, +- {QStringLiteral("19"), Rain}, +- {QStringLiteral("20"), Flurries}, +- {QStringLiteral("21"), RainSnow}, +- {QStringLiteral("22"), LightSnow}, +- {QStringLiteral("23"), Snow}, +- {QStringLiteral("24"), Hail}, +- {QStringLiteral("25"), Hail}, +- {QStringLiteral("26"), Thunderstorm}, +- {QStringLiteral("27"), Thunderstorm}, +- {QStringLiteral("28"), Thunderstorm}, +- {QStringLiteral("29"), Thunderstorm}, +- {QStringLiteral("30"), Thunderstorm}, ++ return QMap<QString, ConditionIcons>{{QStringLiteral("1"), ClearDay}, {QStringLiteral("2"), FewCloudsDay}, {QStringLiteral("3"), PartlyCloudyDay}, ++ {QStringLiteral("4"), Overcast}, {QStringLiteral("5"), Mist}, {QStringLiteral("6"), Mist}, ++ {QStringLiteral("7"), LightRain}, {QStringLiteral("8"), Rain}, {QStringLiteral("9"), Rain}, ++ {QStringLiteral("10"), LightRain}, {QStringLiteral("11"), Rain}, {QStringLiteral("12"), Flurries}, ++ {QStringLiteral("13"), RainSnow}, {QStringLiteral("14"), LightSnow}, {QStringLiteral("15"), Snow}, ++ {QStringLiteral("16"), Snow}, {QStringLiteral("17"), Hail}, {QStringLiteral("18"), LightRain}, ++ {QStringLiteral("19"), Rain}, {QStringLiteral("20"), Flurries}, {QStringLiteral("21"), RainSnow}, ++ {QStringLiteral("22"), LightSnow}, {QStringLiteral("23"), Snow}, {QStringLiteral("24"), Hail}, ++ {QStringLiteral("25"), Hail}, {QStringLiteral("26"), Thunderstorm}, {QStringLiteral("27"), Thunderstorm}, ++ {QStringLiteral("28"), Thunderstorm}, {QStringLiteral("29"), Thunderstorm}, {QStringLiteral("30"), Thunderstorm}, + {QStringLiteral("31"), ClearWindyDay}}; + } + +-- +2.47.0 + diff --git a/desktop-plasma/patches/kde-plasma/plasma-workspace/0002-weather-dwd-Use-more-robust-parsing-for-timestamps.patch b/desktop-plasma/patches/kde-plasma/plasma-workspace/0002-weather-dwd-Use-more-robust-parsing-for-timestamps.patch new file mode 100644 index 0000000..22b9713 --- /dev/null +++ b/desktop-plasma/patches/kde-plasma/plasma-workspace/0002-weather-dwd-Use-more-robust-parsing-for-timestamps.patch @@ -0,0 +1,66 @@ +From 85f11eeabd8d0a7cef8ef76a129e1b4ec4c82f3e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Wolfgang=20M=C3=BCller?= <wolf@oriole.systems> +Date: Thu, 17 Oct 2024 13:50:47 +0200 +Subject: [PATCH 2/3] weather/dwd: Use more robust parsing for timestamps + +When parsing the observationDateTime from the DWD API, we directly +convert a QMap lookup by using toLongLong(). For invalid values, or when +the map lookup returns QVariant() for a missing key, this will return 0, +creating a valid date at millisecond offset 0. Later in the code there +is a check for observationDateTime.isNull() which will therefore never +return true. + +For a more robust check, use a helper function parseDateFromMSecs() +which will make sure the conversion to qint64 succeeded before creating +the QDateTime instance. If the conversion fails for any reason, we +instead return a null datetime by simply calling the empty QDateTime() +constructor. These null datetimes will indicate isNull() correctly. +--- + dataengines/weather/ions/dwd/ion_dwd.cpp | 11 +++++++++-- + dataengines/weather/ions/dwd/ion_dwd.h | 1 + + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/dataengines/weather/ions/dwd/ion_dwd.cpp b/dataengines/weather/ions/dwd/ion_dwd.cpp +index 5909b5f5e9..9ab9ce5a0b 100644 +--- a/dataengines/weather/ions/dwd/ion_dwd.cpp ++++ b/dataengines/weather/ions/dwd/ion_dwd.cpp +@@ -498,8 +498,7 @@ void DWDIon::parseMeasureData(const QString source, QJsonDocument doc) + QVariantMap weatherMap = doc.object().toVariantMap(); + + if (!weatherMap.isEmpty()) { +- QDateTime time = QDateTime::fromMSecsSinceEpoch(weatherMap[QStringLiteral("time")].toLongLong()); +- weatherData.observationDateTime = time; ++ weatherData.observationDateTime = parseDateFromMSecs(weatherMap[QStringLiteral("time")]); + + QString condIconNumber = weatherMap[QStringLiteral("icon")].toString(); + if (condIconNumber != QLatin1String("")) { +@@ -669,6 +668,14 @@ float DWDIon::parseNumber(QVariant number) + return static_cast<float>(intValue) / 10; + } + ++QDateTime DWDIon::parseDateFromMSecs(QVariant timestamp) ++{ ++ bool isValid = false; ++ const qint64 msecs = timestamp.toLongLong(&isValid); ++ ++ return isValid ? QDateTime::fromMSecsSinceEpoch(msecs) : QDateTime(); ++} ++ + QString DWDIon::roundWindDirections(int windDirection) + { + QString roundedWindDirection = QString::number(qRound(((float)windDirection) / 100) * 10); +diff --git a/dataengines/weather/ions/dwd/ion_dwd.h b/dataengines/weather/ions/dwd/ion_dwd.h +index dc86bd43ce..38b9ce3cac 100644 +--- a/dataengines/weather/ions/dwd/ion_dwd.h ++++ b/dataengines/weather/ions/dwd/ion_dwd.h +@@ -135,6 +135,7 @@ private: + QString extractString(QByteArray array, int start, int length); + QString roundWindDirections(int windDirection); + float parseNumber(QVariant number); ++ QDateTime parseDateFromMSecs(QVariant timestamp); + + private: + // Key dicts +-- +2.47.0 + diff --git a/desktop-plasma/patches/kde-plasma/plasma-workspace/0003-weather-dwd-Add-support-for-night-time-icons.patch b/desktop-plasma/patches/kde-plasma/plasma-workspace/0003-weather-dwd-Add-support-for-night-time-icons.patch new file mode 100644 index 0000000..45d1330 --- /dev/null +++ b/desktop-plasma/patches/kde-plasma/plasma-workspace/0003-weather-dwd-Add-support-for-night-time-icons.patch @@ -0,0 +1,182 @@ +From 63a5abc6b1eb409ca5cdb06a96860af2d1d74994 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Wolfgang=20M=C3=BCller?= <wolf@oriole.systems> +Date: Thu, 17 Oct 2024 17:36:41 +0200 +Subject: [PATCH 3/3] weather/dwd: Add support for night-time icons + +The DWD Ion currently shows only day-time icons which feels a bit off +when checking the weather after dusk or at night. Implement the missing +night-time icons and use sunrise and sunset times from DWD's forecast +endpoint to accurately determine when to switch. This will only affect +the display of the current conditions, the forecast icons will continue +to be displayed as day-time only. + +Since we need to have both observation data (for the current observation +time) and forecast data (for sunrise and sunset times), only determine +the icon at a very late stage in updateWeather(). Additionally, make +sure to safely fall back to day-time only icons if we could not fetch +sunrise or sunset times. +--- + dataengines/weather/ions/dwd/ion_dwd.cpp | 70 ++++++++++++++++++------ + dataengines/weather/ions/dwd/ion_dwd.h | 8 ++- + 2 files changed, 59 insertions(+), 19 deletions(-) + +diff --git a/dataengines/weather/ions/dwd/ion_dwd.cpp b/dataengines/weather/ions/dwd/ion_dwd.cpp +index 9ab9ce5a0b..e4a1c1dc74 100644 +--- a/dataengines/weather/ions/dwd/ion_dwd.cpp ++++ b/dataengines/weather/ions/dwd/ion_dwd.cpp +@@ -82,21 +82,38 @@ void DWDIon::deleteForecasts() + } + } + ++QMap<QString, IonInterface::ConditionIcons> DWDIon::getUniversalIcons() const ++{ ++ return QMap<QString, ConditionIcons>{ ++ {QStringLiteral("4"), Overcast}, {QStringLiteral("5"), Mist}, {QStringLiteral("6"), Mist}, {QStringLiteral("7"), LightRain}, ++ {QStringLiteral("8"), Rain}, {QStringLiteral("9"), Rain}, {QStringLiteral("10"), LightRain}, {QStringLiteral("11"), Rain}, ++ {QStringLiteral("12"), Flurries}, {QStringLiteral("13"), RainSnow}, {QStringLiteral("14"), LightSnow}, {QStringLiteral("15"), Snow}, ++ {QStringLiteral("16"), Snow}, {QStringLiteral("17"), Hail}, {QStringLiteral("18"), LightRain}, {QStringLiteral("19"), Rain}, ++ {QStringLiteral("20"), Flurries}, {QStringLiteral("21"), RainSnow}, {QStringLiteral("22"), LightSnow}, {QStringLiteral("23"), Snow}, ++ {QStringLiteral("24"), Hail}, {QStringLiteral("25"), Hail}, {QStringLiteral("26"), Thunderstorm}, {QStringLiteral("27"), Thunderstorm}, ++ {QStringLiteral("28"), Thunderstorm}, {QStringLiteral("29"), Thunderstorm}, {QStringLiteral("30"), Thunderstorm}}; ++} ++ + QMap<QString, IonInterface::ConditionIcons> DWDIon::setupDayIconMappings() const + { +- // DWD supplies it's own icon number which we can use to determine a condition ++ QMap<QString, ConditionIcons> universalIcons = getUniversalIcons(); ++ QMap<QString, ConditionIcons> dayIcons = {{QStringLiteral("1"), ClearDay}, ++ {QStringLiteral("2"), FewCloudsDay}, ++ {QStringLiteral("3"), PartlyCloudyDay}, ++ {QStringLiteral("31"), ClearWindyDay}}; ++ dayIcons.insert(universalIcons); ++ return dayIcons; ++} + +- return QMap<QString, ConditionIcons>{{QStringLiteral("1"), ClearDay}, {QStringLiteral("2"), FewCloudsDay}, {QStringLiteral("3"), PartlyCloudyDay}, +- {QStringLiteral("4"), Overcast}, {QStringLiteral("5"), Mist}, {QStringLiteral("6"), Mist}, +- {QStringLiteral("7"), LightRain}, {QStringLiteral("8"), Rain}, {QStringLiteral("9"), Rain}, +- {QStringLiteral("10"), LightRain}, {QStringLiteral("11"), Rain}, {QStringLiteral("12"), Flurries}, +- {QStringLiteral("13"), RainSnow}, {QStringLiteral("14"), LightSnow}, {QStringLiteral("15"), Snow}, +- {QStringLiteral("16"), Snow}, {QStringLiteral("17"), Hail}, {QStringLiteral("18"), LightRain}, +- {QStringLiteral("19"), Rain}, {QStringLiteral("20"), Flurries}, {QStringLiteral("21"), RainSnow}, +- {QStringLiteral("22"), LightSnow}, {QStringLiteral("23"), Snow}, {QStringLiteral("24"), Hail}, +- {QStringLiteral("25"), Hail}, {QStringLiteral("26"), Thunderstorm}, {QStringLiteral("27"), Thunderstorm}, +- {QStringLiteral("28"), Thunderstorm}, {QStringLiteral("29"), Thunderstorm}, {QStringLiteral("30"), Thunderstorm}, +- {QStringLiteral("31"), ClearWindyDay}}; ++QMap<QString, IonInterface::ConditionIcons> DWDIon::setupNightIconMappings() const ++{ ++ QMap<QString, ConditionIcons> universalIcons = getUniversalIcons(); ++ QMap<QString, ConditionIcons> nightIcons = {{QStringLiteral("1"), ClearNight}, ++ {QStringLiteral("2"), FewCloudsNight}, ++ {QStringLiteral("3"), PartlyCloudyNight}, ++ {QStringLiteral("31"), ClearWindyNight}}; ++ nightIcons.insert(universalIcons); ++ return nightIcons; + } + + QMap<QString, IonInterface::WindDirections> DWDIon::setupWindIconMappings() const +@@ -119,6 +136,12 @@ QMap<QString, IonInterface::ConditionIcons> const &DWDIon::dayIcons() const + return dval; + } + ++QMap<QString, IonInterface::ConditionIcons> const &DWDIon::nightIcons() const ++{ ++ static QMap<QString, ConditionIcons> const dval = setupNightIconMappings(); ++ return dval; ++} ++ + QMap<QString, IonInterface::WindDirections> const &DWDIon::windIcons() const + { + static QMap<QString, WindDirections> const wval = setupWindIconMappings(); +@@ -448,6 +471,10 @@ void DWDIon::parseForecastData(const QString source, QJsonDocument doc) + weatherData.gustSpeedAlt = parseNumber(dayMap[QStringLiteral("windGust")]); + QString windDirection = roundWindDirections(dayMap[QStringLiteral("windDirection")].toInt()); + weatherData.windDirectionAlt = getWindDirectionIcon(windIcons(), windDirection); ++ ++ // Also fetch today's sunrise and sunset times to determine whether to pick day or night icons ++ weatherData.sunriseTime = parseDateFromMSecs(dayMap[QStringLiteral("sunrise")].toLongLong()); ++ weatherData.sunsetTime = parseDateFromMSecs(dayMap[QStringLiteral("sunset")].toLongLong()); + } + + forecasts.append(forecast); +@@ -500,10 +527,7 @@ void DWDIon::parseMeasureData(const QString source, QJsonDocument doc) + if (!weatherMap.isEmpty()) { + weatherData.observationDateTime = parseDateFromMSecs(weatherMap[QStringLiteral("time")]); + +- QString condIconNumber = weatherMap[QStringLiteral("icon")].toString(); +- if (condIconNumber != QLatin1String("")) { +- weatherData.conditionIcon = getWeatherIcon(dayIcons(), condIconNumber); +- } ++ weatherData.condIconNumber = weatherMap[QStringLiteral("icon")].toString(); + + bool windIconValid = false; + const int windDirection = weatherMap[QStringLiteral("winddirection")].toInt(&windIconValid); +@@ -573,8 +597,8 @@ void DWDIon::updateWeather(const QString &source) + else + data.insert(QStringLiteral("Observation Timestamp"), QDateTime::currentDateTime()); + +- if (!weatherData.conditionIcon.isEmpty()) +- data.insert(QStringLiteral("Condition Icon"), weatherData.conditionIcon); ++ if (!weatherData.condIconNumber.isEmpty()) ++ data.insert(QStringLiteral("Condition Icon"), getWeatherIcon(isNightTime(weatherData) ? nightIcons() : dayIcons(), weatherData.condIconNumber)); + + if (!qIsNaN(weatherData.temperature)) + data.insert(QStringLiteral("Temperature"), weatherData.temperature); +@@ -717,6 +741,16 @@ QString DWDIon::camelCaseString(const QString text) + return result; + } + ++bool DWDIon::isNightTime(const WeatherData &weatherData) ++{ ++ if (weatherData.sunriseTime.isNull() || weatherData.sunsetTime.isNull()) { ++ // default to daytime icons if we're missing sunrise/sunset times ++ return false; ++ } ++ ++ return weatherData.observationDateTime < weatherData.sunriseTime || weatherData.observationDateTime > weatherData.sunsetTime; ++} ++ + K_PLUGIN_CLASS_WITH_JSON(DWDIon, "ion-dwd.json") + + #include "ion_dwd.moc" +diff --git a/dataengines/weather/ions/dwd/ion_dwd.h b/dataengines/weather/ions/dwd/ion_dwd.h +index 38b9ce3cac..c1ed8651b6 100644 +--- a/dataengines/weather/ions/dwd/ion_dwd.h ++++ b/dataengines/weather/ions/dwd/ion_dwd.h +@@ -40,8 +40,10 @@ public: + + // Current observation information. + QDateTime observationDateTime; ++ QDateTime sunriseTime; ++ QDateTime sunsetTime; + +- QString conditionIcon; ++ QString condIconNumber; + QString windDirection; + float temperature; + float humidity; +@@ -110,10 +112,13 @@ private Q_SLOTS: + void forecast_slotJobFinished(KJob *); + + private: ++ QMap<QString, ConditionIcons> getUniversalIcons() const; + QMap<QString, ConditionIcons> setupDayIconMappings() const; ++ QMap<QString, ConditionIcons> setupNightIconMappings() const; + QMap<QString, WindDirections> setupWindIconMappings() const; + + QMap<QString, ConditionIcons> const &dayIcons() const; ++ QMap<QString, ConditionIcons> const &nightIcons() const; + QMap<QString, WindDirections> const &windIcons() const; + + void findPlace(const QString &searchText); +@@ -134,6 +139,7 @@ private: + QString camelCaseString(const QString text); + QString extractString(QByteArray array, int start, int length); + QString roundWindDirections(int windDirection); ++ bool isNightTime(const WeatherData &weatherData); + float parseNumber(QVariant number); + QDateTime parseDateFromMSecs(QVariant timestamp); + +-- +2.47.0 + |