File indexing completed on 2024-04-28 04:42:43
0001 /* 0002 * SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com> 0003 * SPDX-FileCopyrightText: 2020 Devin Lin <espidev@gmail.com> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "pendingweatherforecast.h" 0009 #include "geotimezone.h" 0010 #include "kweathercore_p.h" 0011 #include "kweathercore_version.h" 0012 #include "pendingweatherforecast_p.h" 0013 0014 #include <QDir> 0015 #include <QFile> 0016 #include <QJsonArray> 0017 #include <QJsonDocument> 0018 #include <QJsonObject> 0019 #include <QNetworkAccessManager> 0020 #include <QNetworkReply> 0021 #include <QStandardPaths> 0022 #include <QTimeZone> 0023 #include <QUrlQuery> 0024 0025 namespace KWeatherCore 0026 { 0027 0028 PendingWeatherForecastPrivate::PendingWeatherForecastPrivate(PendingWeatherForecast *qq) 0029 : q(qq) 0030 { 0031 } 0032 0033 void PendingWeatherForecastPrivate::getTimezone(double latitude, double longitude) 0034 { 0035 auto timezoneSource = new GeoTimezone(m_manager, latitude, longitude, q); 0036 QObject::connect(timezoneSource, &GeoTimezone::finished, q, [this, timezoneSource]() { 0037 timezoneSource->deleteLater(); 0038 parseTimezoneResult(timezoneSource->timezone()); 0039 }); 0040 } 0041 void PendingWeatherForecastPrivate::parseTimezoneResult(const QString &result) 0042 { 0043 hasTimezone = true; 0044 parser.forecast.setTimezone(result); 0045 m_timezone = result; 0046 if (parser.hasData()) { 0047 parser.applySunriseToForecast(QTimeZone(m_timezone.toUtf8())); 0048 Q_EMIT q->finished(); 0049 } 0050 } 0051 0052 void PendingWeatherForecastPrivate::parseWeatherForecastResults(QNetworkReply *reply) 0053 { 0054 reply->deleteLater(); 0055 if (reply->error() != QNetworkReply::NoError) { 0056 qWarning() << "network error when fetching forecast:" << reply->errorString(); 0057 setError(PendingWeatherForecast::NetworkError, reply->errorString()); 0058 Q_EMIT q->finished(); 0059 return; 0060 } 0061 0062 parser.parseLocationForecast(reply->readAll()); 0063 if (hasTimezone) { 0064 parser.applySunriseToForecast(QTimeZone(m_timezone.toUtf8())); 0065 Q_EMIT q->finished(); 0066 } 0067 } 0068 0069 PendingWeatherForecast::PendingWeatherForecast(double latitude, 0070 double longitude, 0071 const QString &timezone, 0072 QNetworkAccessManager *nam, 0073 QObject *parent) 0074 : Reply(new PendingWeatherForecastPrivate(this), parent) 0075 { 0076 Q_D(PendingWeatherForecast); 0077 d->m_manager = nam; 0078 0079 // query weather api 0080 QUrl url(QStringLiteral("https://api.met.no/weatherapi/locationforecast/2.0/complete")); 0081 QUrlQuery query; 0082 query.addQueryItem(QStringLiteral("lat"), KWeatherCorePrivate::toFixedString(latitude)); 0083 query.addQueryItem(QStringLiteral("lon"), KWeatherCorePrivate::toFixedString(longitude)); 0084 url.setQuery(query); 0085 QNetworkRequest req(url); 0086 req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); 0087 0088 // see §Identification on https://api.met.no/conditions_service.html 0089 req.setHeader(QNetworkRequest::UserAgentHeader, QStringLiteral("KWeatherCore/" KWEATHERCORE_VERSION_STRING " kde-frameworks-devel@kde.org")); 0090 auto reply = d->m_manager->get(req); 0091 connect(reply, &QNetworkReply::finished, this, [reply, this]() { 0092 Q_D(PendingWeatherForecast); 0093 d->parseWeatherForecastResults(reply); 0094 }); 0095 0096 d->parser.forecast.setCoordinate(latitude, longitude); 0097 0098 if (timezone.isEmpty()) { 0099 d->hasTimezone = false; 0100 d->getTimezone(latitude, longitude); 0101 } else { 0102 d->hasTimezone = true; 0103 d->parser.forecast.setTimezone(timezone); 0104 d->m_timezone = timezone; 0105 } 0106 } 0107 PendingWeatherForecast::PendingWeatherForecast(WeatherForecast data, QObject *parent) 0108 : Reply(new PendingWeatherForecastPrivate(this), parent) 0109 { 0110 Q_D(PendingWeatherForecast); 0111 d->parser.forecast = data; 0112 QMetaObject::invokeMethod(this, &PendingWeatherForecast::finished, Qt::QueuedConnection); 0113 } 0114 0115 PendingWeatherForecast::~PendingWeatherForecast() = default; 0116 0117 WeatherForecast PendingWeatherForecast::value() const 0118 { 0119 Q_D(const PendingWeatherForecast); 0120 return d->parser.forecast; 0121 } 0122 } 0123 0124 #include "moc_pendingweatherforecast.cpp"