KWeatherCore

kweathercore.cpp
1/*
2 * SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com>
3 * SPDX-FileCopyrightText: 2020-2021 Devin Lin <espidev@gmail.com>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8#include "kweathercore_p.h"
9
10#include <KLazyLocalizedString>
11
12#include <QStandardPaths>
13
14#include <cstring>
15#include <iomanip>
16#include <sstream>
17
18namespace KWeatherCore
19{
20CAPPolygon KWeatherCorePrivate::stringToPolygon(const QString &str)
21{
22 CAPPolygon res;
23#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
24 const auto pairList = QStringView(str).split(QLatin1Char(' '), Qt::SkipEmptyParts);
25#else
26 const auto pairList = str.splitRef(QLatin1Char(' '), Qt::SkipEmptyParts);
27#endif
28
29 res.reserve(pairList.size());
30 for (auto &pair : pairList) {
31 auto coordinate = pair.split(QLatin1Char(','));
32 if (coordinate.size() != 2) {
33 continue;
34 }
35 bool latOk = false, lonOk = false;
36 res.push_back({coordinate.front().toFloat(&latOk), coordinate.back().toFloat(&lonOk)});
37 if (!latOk || !lonOk) {
38 res.pop_back();
39 }
40 }
41 return res;
42}
43
44QString KWeatherCorePrivate::toFixedString(double num)
45{
46 std::ostringstream oss;
47 oss << std::fixed << std::setprecision(2) << num;
48 return QString::fromStdString(oss.str());
49}
50
51QDir KWeatherCorePrivate::getCacheDirectory(double latitude, double longitude)
52{
53#ifdef Q_OS_ANDROID
54 QDir dir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QStringLiteral("/cache/") + toFixedString(latitude) + QStringLiteral("/")
55 + toFixedString(longitude));
56 if (!dir.exists())
57 dir.mkpath(QStringLiteral("."));
58 return dir;
59#else
60 QDir dir(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QStringLiteral("/kweather/cache/") + toFixedString(latitude)
61 + QStringLiteral("/") + toFixedString(longitude));
62 if (!dir.exists()) {
63 dir.mkpath(QStringLiteral("."));
64 }
65 return dir;
66#endif
67}
68
69CAPAlertInfo::Urgency KWeatherCorePrivate::urgencyStringToEnum(const QString &str)
70{
71 if (str == QLatin1String("Immediate")) {
72 return CAPAlertInfo::Urgency::Immediate;
73 } else if (str == QLatin1String("Expected")) {
74 return CAPAlertInfo::Urgency::Expected;
75 } else if (str == QLatin1String("Future")) {
76 return CAPAlertInfo::Urgency::Future;
77 } else if (str == QLatin1String("Past")) {
78 return CAPAlertInfo::Urgency::Past;
79 } else {
80 return CAPAlertInfo::Urgency::UnknownUrgency;
81 }
82}
83
84CAPAlertInfo::Severity KWeatherCorePrivate::severityStringToEnum(const QString &str)
85{
86 if (str == QLatin1String("Extreme")) {
87 return CAPAlertInfo::Severity::Extreme;
88 } else if (str == QLatin1String("Severe")) {
89 return CAPAlertInfo::Severity::Severe;
90 } else if (str == QLatin1String("Moderate")) {
91 return CAPAlertInfo::Severity::Moderate;
92 } else if (str == QLatin1String("Minor")) {
93 return CAPAlertInfo::Severity::Minor;
94 } else {
95 return CAPAlertInfo::Severity::UnknownSeverity;
96 }
97}
98
99CAPAlertInfo::Certainty KWeatherCorePrivate::certaintyStringToEnum(const QString &str)
100{
101 if (str == QLatin1String("Observed")) {
102 return CAPAlertInfo::Certainty::Observed;
103 } else if (str == QLatin1String("Likely")) {
104 return CAPAlertInfo::Certainty::Likely;
105 } else if (str == QLatin1String("Possible")) {
106 return CAPAlertInfo::Certainty::Possible;
107 } else if (str == QLatin1String("Unlikely")) {
108 return CAPAlertInfo::Certainty::Unlikely;
109 } else {
110 return CAPAlertInfo::Certainty::UnknownCertainty;
111 }
112}
113
114QString KWeatherCorePrivate::urgencyToString(CAPAlertInfo::Urgency urgency)
115{
116 QString res;
117 switch (urgency) {
118 case CAPAlertInfo::Urgency::Immediate:
119 res = i18n("Immediate");
120 break;
121 case CAPAlertInfo::Urgency::Expected:
122 res = i18n("Expected");
123 break;
124 case CAPAlertInfo::Urgency::Future:
125 res = i18n("Future");
126 break;
127 case CAPAlertInfo::Urgency::Past:
128 res = i18n("Past");
129 break;
130 case CAPAlertInfo::Urgency::UnknownUrgency:
131 res = i18n("Unknown");
132 }
133 return res;
134}
135
136QString KWeatherCorePrivate::severityToString(CAPAlertInfo::Severity severity)
137{
138 QString res;
139 switch (severity) {
140 case CAPAlertInfo::Severity::Extreme:
141 res = i18n("Extreme");
142 break;
143 case CAPAlertInfo::Severity::Severe:
144 res = i18n("Severe");
145 break;
146 case CAPAlertInfo::Severity::Moderate:
147 res = i18n("Moderate");
148 break;
149 case CAPAlertInfo::Severity::Minor:
150 res = i18n("Minor");
151 break;
152 case CAPAlertInfo::Severity::UnknownSeverity:
153 res = i18n("Unknown");
154 }
155 return res;
156}
157
158QString KWeatherCorePrivate::certaintyToString(CAPAlertInfo::Certainty certainty)
159{
160 QString res;
161 switch (certainty) {
162 case CAPAlertInfo::Certainty::Observed:
163 res = i18n("Observed");
164 break;
165 case CAPAlertInfo::Certainty::Likely:
166 res = i18n("Likely");
167 break;
168 case CAPAlertInfo::Certainty::Possible:
169 res = i18n("Possible");
170 break;
171 case CAPAlertInfo::Certainty::Unlikely:
172 res = i18n("Unlikely");
173 break;
174 case CAPAlertInfo::Certainty::UnknownCertainty:
175 res = i18n("Unknown");
176 }
177 return res;
178}
179
180// rank weather (for what best describes the day overall)
181// only need neutral icons
182// ### needs to be alphabetically sorted by icon name!
183struct {
184 const char *iconName;
185 int rank;
186} static constexpr const WEATHER_ICON_PRIORITY_RANK[] = {
187 {"weather-clear", 0},
188 {"weather-clouds", 2},
189 {"weather-few-clouds", 1},
190 {"weather-fog", 3},
191 {"weather-freezing-rain", 6},
192 {"weather-freezing-scattered-rain", 6},
193 {"weather-freezing-scattered-rain-storm", 7},
194 {"weather-freezing-storm", 6},
195 {"weather-hail", 5},
196 {"weather-mist", 3},
197 {"weather-none-available", -1},
198 {"weather-showers", 5},
199 {"weather-showers-scattered", 4},
200 {"weather-showers-scattered-storm", 7},
201 {"weather-snow", 5},
202 {"weather-snow-rain", 6},
203 {"weather-snow-scattered", 4},
204 {"weather-snow-scattered-storm", 7},
205 {"weather-snow-storm", 7},
206 {"weather-storm", 7},
207};
208
209int KWeatherCorePrivate::weatherIconPriorityRank(const QString &icon)
210{
211 const auto it = std::lower_bound(std::begin(WEATHER_ICON_PRIORITY_RANK), std::end(WEATHER_ICON_PRIORITY_RANK), icon, [](const auto &lhs, const auto &rhs) {
212 return QLatin1String(lhs.iconName) < rhs;
213 });
214 if (it != std::end(WEATHER_ICON_PRIORITY_RANK) && QLatin1String((*it).iconName) == icon) {
215 return (*it).rank;
216 }
217
218 return 0;
219}
220
221// https://api.met.no/weatherapi/weathericon/2.0/legends
222// ### needs to be alphabetically sorted by key!
223struct {
224 const char *key;
225 const char *icon;
226 const KLazyLocalizedString desc;
227} static constexpr const WEATHER_API_DESC_MAP[] = {
228 {"clearsky_day", "weather-clear", kli18n("Clear")},
229 {"clearsky_neutral", "weather-clear", kli18n("Clear")},
230 {"clearsky_night", "weather-clear-night", kli18n("Clear")},
231 {"cloudy_day", "weather-clouds", kli18n("Cloudy")},
232 {"cloudy_neutral", "weather-clouds", kli18n("Cloudy")},
233 {"cloudy_night", "weather-clouds-night", kli18n("Cloudy")},
234 {"fair_day", "weather-few-clouds", kli18n("Partly Sunny")},
235 {"fair_neutral", "weather-few-clouds", kli18n("Light Clouds")},
236 {"fair_night", "weather-few-clouds-night", kli18n("Light Clouds")},
237 {"fog_day", "weather-fog", kli18n("Fog")},
238 {"fog_neutral", "weather-fog", kli18n("Fog")},
239 {"fog_night", "weather-fog", kli18n("Fog")},
240
241 {"heavyrain_day", "weather-showers-day", kli18n("Heavy Rain")},
242 {"heavyrain_neutral", "weather-showers", kli18n("Heavy Rain")},
243 {"heavyrain_night", "weather-showers-night", kli18n("Heavy Rain")},
244 {"heavyrainandthunder_day", "weather-storm-day", kli18n("Thunderstorm with Heavy Rain")},
245 {"heavyrainandthunder_neutral", "weather-storm", kli18n("Thunderstorm with Heavy Rain")},
246 {"heavyrainandthunder_night", "weather-storm-night", kli18n("Thunderstorm with Heavy Rain")},
247 {"heavyrainshowers_day", "weather-showers-day", kli18n("Heavy Rain Shower")},
248 {"heavyrainshowers_neutral", "weather-showers", kli18n("Heavy Rain Shower")},
249 {"heavyrainshowers_night", "weather-showers-night", kli18n("Heavy Rain Shower")},
250 {"heavyrainshowersandthunder_day", "weather-storm-day", kli18n("Thunderstorm with Heavy Rain Shower")},
251 {"heavyrainshowersandthunder_neutral", "weather-storm", kli18n("Thunderstorm with Heavy Rain Shower")},
252 {"heavyrainshowersandthunder_night", "weather-storm-night", kli18n("Thunderstorm with Heavy Rain Shower")},
253
254 {"heavysleet_day", "weather-freezing-rain", kli18n("Heavy Sleet")},
255 {"heavysleet_neutral", "weather-freezing-rain", kli18n("Heavy Sleet")},
256 {"heavysleet_night", "weather-freezing-rain", kli18n("Heavy Sleet")},
257 {"heavysleetandthunder_day", "weather-freezing-storm", kli18n("Thunderstorm with Heavy Sleet")},
258 {"heavysleetandthunder_neutral", "weather-freezing-storm", kli18n("Thunderstorm with Heavy Sleet")},
259 {"heavysleetandthunder_night", "weather-freezing-storm", kli18n("Thunderstorm with Heavy Sleet")},
260 {"heavysleetshowers_day", "weather-freezing-rain-day", kli18n("Heavy Sleet Shower")},
261 {"heavysleetshowers_neutral", "weather-freezing-rain", kli18n("Heavy Sleet Shower")},
262 {"heavysleetshowers_night", "weather-freezing-rain-night", kli18n("Heavy Sleet Shower")},
263 {"heavysleetshowersandthunder_day", "weather-freezing-storm-day", kli18n("Thunderstorm with Heavy Sleet Shower")},
264 {"heavysleetshowersandthunder_neutral", "weather-freezing-storm", kli18n("Thunderstorm with Heavy Sleet Shower")},
265 {"heavysleetshowersandthunder_night", "weather-freezing-storm-night", kli18n("Thunderstorm with Heavy Sleet Shower")},
266
267 {"heavysnow_day", "weather-snow", kli18n("Heavy Snow")},
268 {"heavysnow_neutral", "weather-snow", kli18n("Heavy Snow")},
269 {"heavysnow_night", "weather-snow", kli18n("Heavy Snow")},
270 {"heavysnowshowers_day", "weather-snow-day", kli18n("Heavy Snow Shower")},
271 {"heavysnowshowers_neutral", "weather-snow", kli18n("Heavy Snow Shower")},
272 {"heavysnowshowers_night", "weather-snow-night", kli18n("Heavy Snow Shower")},
273 {"heavysnowshowersandthunder_day", "weather-snow-storm-day", kli18n("Thunderstorm with Heavy Snow Shower")},
274 {"heavysnowshowersandthunder_neutral", "weather-snow-storm", kli18n("Thunderstorm with Heavy Snow Shower")},
275 {"heavysnowshowersandthunder_night", "weather-snow-storm-night", kli18n("Thunderstorm with Heavy Snow Shower")},
276
277 {"lightrain_day", "weather-showers-scattered", kli18n("Light Rain")},
278 {"lightrain_neutral", "weather-showers-scattered", kli18n("Light Rain")},
279 {"lightrain_night", "weather-showers-scattered", kli18n("Light Rain")},
280 {"lightrainandthunder_day", "weather-showers-scattered-storm", kli18n("Thunderstorm with Light Rain")},
281 {"lightrainandthunder_neutral", "weather-showers-scattered-storm", kli18n("Thunderstorm with Light Rain")},
282 {"lightrainandthunder_night", "weather-showers-scattered-storm", kli18n("Thunderstorm with Light Rain")},
283 {"lightrainshowers_day", "weather-showers-scattered-day", kli18n("Light Rain Shower")},
284 {"lightrainshowers_neutral", "weather-showers-scattered", kli18n("Light Rain Shower")},
285 {"lightrainshowers_night", "weather-showers-scattered-night", kli18n("Light Rain Shower")},
286 {"lightrainshowersandthunder_day", "weather-showers-scattered-storm-day", kli18n("Thunderstorm with Light Rain Shower")},
287 {"lightrainshowersandthunder_neutral", "weather-showers-scattered-storm", kli18n("Thunderstorm with Light Rain Shower")},
288 {"lightrainshowersandthunder_night", "weather-showers-scattered-storm-night", kli18n("Thunderstorm with Light Rain Shower")},
289
290 {"lightsleet_day", "weather-showers-scattered", kli18n("Light Sleet")},
291 {"lightsleet_neutral", "weather-showers-scattered", kli18n("Light Sleet")},
292 {"lightsleet_night", "weather-showers-scattered", kli18n("Light Sleet")},
293 {"lightsleetandthunder_day", "weather-freezing-scattered-rain-storm", kli18n("Thunderstorm with Light Sleet")},
294 {"lightsleetandthunder_neutral", "weather-freezing-scattered-rain-storm", kli18n("Thunderstorm with Light Sleet")},
295 {"lightsleetandthunder_night", "weather-freezing-scattered-rain-storm", kli18n("Thunderstorm with Light Sleet")},
296 {"lightsleetshowers_day", "weather-freezing-scattered-rain-day", kli18n("Light Sleet Shower")},
297 {"lightsleetshowers_neutral", "weather-freezing-scattered-rain", kli18n("Light Sleet Shower")},
298 {"lightsleetshowers_night", "weather-freezing-scattered-rain-night", kli18n("Light Sleet Shower")},
299
300 {"lightsnow_day", "weather-snow-scattered", kli18n("Light Snow")},
301 {"lightsnow_neutral", "weather-snow-scattered", kli18n("Light Snow")},
302 {"lightsnow_night", "weather-snow-scattered", kli18n("Light Snow")},
303 {"lightsnowandthunder_day", "weather-snow-scattered-storm", kli18n("Thunderstorm with Light Snow")},
304 {"lightsnowandthunder_neutral", "weather-snow-scattered-storm", kli18n("Thunderstorm with Light Snow")},
305 {"lightsnowandthunder_night", "weather-snow-scattered-storm", kli18n("Thunderstorm with Light Snow")},
306 {"lightsnowshowers_day", "weather-snow-scattered-day", kli18n("Light Snow Shower")},
307 {"lightsnowshowers_neutral", "weather-snow-scattered", kli18n("Light Snow Shower")},
308 {"lightsnowshowers_night", "weather-snow-scattered-night", kli18n("Light Snow Shower")},
309
310 {"lightssleetshowersandthunder_day", "weather-freezing-scattered-rain-storm-day", kli18n("Thunderstorm with Light Sleet Shower")},
311 {"lightssleetshowersandthunder_neutral", "weather-freezing-scattered-rain-storm", kli18n("Thunderstorm with Light Sleet Shower")},
312 {"lightssleetshowersandthunder_night", "weather-freezing-scattered-rain-storm-night", kli18n("Thunderstorm with Light Sleet Shower")},
313 {"lightssnowshowersandthunder_day", "weather-snow-scattered-storm-day", kli18n("Thunderstorm with Light Snow Shower")},
314 {"lightssnowshowersandthunder_neutral", "weather-snow-scattered-storm", kli18n("Thunderstorm with Light Snow Shower")},
315 {"lightssnowshowersandthunder_night", "weather-snow-scattered-storm-night", kli18n("Thunderstorm with Light Snow Shower")},
316
317 {"partlycloudy_day", "weather-clouds", kli18n("Partly Cloudy")},
318 {"partlycloudy_neutral", "weather-clouds", kli18n("Partly Cloudy")},
319 {"partlycloudy_night", "weather-clouds-night", kli18n("Partly Cloudy")},
320
321 {"rain_day", "weather-showers", kli18n("Rain")},
322 {"rain_neutral", "weather-showers", kli18n("Rain")},
323 {"rain_night", "weather-showers", kli18n("Rain")},
324 {"rainandthunder_day", "weather-storm", kli18n("Thunderstorm with Rain")},
325 {"rainandthunder_neutral", "weather-storm", kli18n("Thunderstorm with Rain")},
326 {"rainandthunder_night", "weather-storm", kli18n("Thunderstorm with Rain")},
327 {"rainshowers_day", "weather-showers-day", kli18n("Rain Shower")},
328 {"rainshowers_neutral", "weather-showers", kli18n("Rain Shower")},
329 {"rainshowers_night", "weather-showers-night", kli18n("Rain Shower")},
330 {"rainshowersandthunder_day", "weather-storm-day", kli18n("Thunderstorm with Rain Shower")},
331 {"rainshowersandthunder_neutral", "weather-storm", kli18n("Thunderstorm with Rain Shower")},
332 {"rainshowersandthunder_night", "weather-storm-night", kli18n("Thunderstorm with Rain Shower")},
333
334 {"sleet_day", "weather-freezing-rain", kli18n("Sleet")},
335 {"sleet_neutral", "weather-freezing-rain", kli18n("Sleet")},
336 {"sleet_night", "weather-freezing-rain", kli18n("Sleet")},
337 {"sleetandthunder_day", "weather-storm", kli18n("Thunderstorm with Sleet")},
338 {"sleetandthunder_neutral", "weather-storm", kli18n("Thunderstorm with Sleet")},
339 {"sleetandthunder_night", "weather-storm", kli18n("Thunderstorm with Sleet")},
340 {"sleetshowers_day", "weather-freezing-rain-day", kli18n("Sleet Shower")},
341 {"sleetshowers_neutral", "weather-freezing-rain", kli18n("Sleet Shower")},
342 {"sleetshowers_night", "weather-freezing-rain-night", kli18n("Sleet Shower")},
343 {"sleetshowersandthunder_day", "weather-freezing-storm-day", kli18n("Thunderstorm with Sleet Shower")},
344 {"sleetshowersandthunder_neutral", "weather-freezing-storm", kli18n("Thunderstorm with Sleet Shower")},
345 {"sleetshowersandthunder_night", "weather-freezing-storm-night", kli18n("Thunderstorm with Sleet Shower")},
346
347 {"snow_day", "weather-snow", kli18n("Snow")},
348 {"snow_neutral", "weather-snow", kli18n("Snow")},
349 {"snow_night", "weather-snow", kli18n("Snow")},
350 {"snowandthunder_day", "weather-snow-storm", kli18n("Thunderstorm with Snow")},
351 {"snowandthunder_neutral", "weather-snow-storm", kli18n("Thunderstorm with Snow")},
352 {"snowandthunder_night", "weather-snow-storm", kli18n("Thunderstorm with Snow")},
353 {"snowshowers_day", "weather-snow-day", kli18n("Snow Shower")},
354 {"snowshowers_neutral", "weather-snow", kli18n("Snow Shower")},
355 {"snowshowers_night", "weather-snow-night", kli18n("Snow Shower")},
356 {"snowshowersandthunder_day", "weather-snow-storm-day", kli18n("Thunderstorm with Snow Shower")},
357 {"snowshowersandthunder_neutral", "weather-snow-storm", kli18n("Thunderstorm with Snow Shower")},
358 {"snowshowersandthunder_night", "weather-snow-storm-night", kli18n("Thunderstorm with Snow Shower")},
359
360};
361
362ResolvedWeatherDesc KWeatherCorePrivate::resolveAPIWeatherDesc(const QString &desc)
363{
364 const auto key = desc.toUtf8();
365 const auto it = std::lower_bound(std::begin(WEATHER_API_DESC_MAP), std::end(WEATHER_API_DESC_MAP), key, [](const auto &lhs, const auto &rhs) {
366 return std::strcmp(lhs.key, rhs.constData()) < 0;
367 });
368 if (it != std::end(WEATHER_API_DESC_MAP) && std::strcmp((*it).key, key.constData()) == 0) {
369 return ResolvedWeatherDesc(QLatin1String((*it).icon), (*it).desc.toString());
370 }
371
372 return {};
373}
374
375}
QString i18n(const char *text, const TYPE &arg...)
KIOCORE_EXPORT QString dir(const QString &fileClass)
QString writableLocation(StandardLocation type)
QString fromStdString(const std::string &str)
void reserve(qsizetype size)
QList< QStringView > split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
SkipEmptyParts
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:42 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.