Commit 38931181 authored by Volker Krause's avatar Volker Krause

Initial work on retrieving weather forecast data

parent 1b7db97f
......@@ -27,6 +27,8 @@ find_package(KPimItinerary CONFIG REQUIRED)
find_package(QmlLint)
set_package_properties(QmlLint PROPERTIES URL "https://qt.io" PURPOSE "Validate QML code.")
find_package(SharedMimeInfo 1.0 REQUIRED)
find_package(ZLIB REQUIRED)
set_package_properties("ZLIB" PROPERTIES PURPOSE "Needed for retrieving weather forecast data.")
include(ECMQMLModules)
ecm_find_qmlmodule(org.kde.prison 1.0)
......
......@@ -3,3 +3,5 @@ add_definitions(-DSOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
ecm_add_test(pkpassmanagertest.cpp LINK_LIBRARIES Qt5::Test itinerary)
ecm_add_test(reservationmanagertest.cpp LINK_LIBRARIES Qt5::Test itinerary)
ecm_add_test(timelinemodeltest.cpp LINK_LIBRARIES Qt5::Test itinerary)
ecm_add_test(weathertest.cpp LINK_LIBRARIES Qt5::Test itinerary-weather)
target_include_directories(weathertest PRIVATE ${CMAKE_BINARY_DIR})
/*
Copyright (C) 2018 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program 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 Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "itinerary_version.h"
#include <weatherforecast.h>
#include <weatherforecastmanager.h>
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QSignalSpy>
#include <QStandardPaths>
#include <QTest>
class WeatherTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase()
{
QCoreApplication::setApplicationName(QStringLiteral("kde-itinerary-weatherunittest"));
QCoreApplication::setApplicationVersion(QStringLiteral(ITINERARY_VERSION_STRING));
QStandardPaths::setTestModeEnabled(true);
QDir d(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/weather"));
d.removeRecursively();
QVERIFY(!d.exists());
}
void testForecastRetrieval()
{
WeatherForecastManager mgr;
const auto now = QDateTime::currentDateTimeUtc().addSecs(1800);
auto fc = mgr.forecast(46.1, 7.78, now).value<WeatherForecast>();
QVERIFY(!fc.isValid());
QSignalSpy updateSpy(&mgr, &WeatherForecastManager::forecastUpdated);
QVERIFY(updateSpy.isValid());
mgr.monitorLocation(46.1, 7.78);
QVERIFY(updateSpy.wait());
fc = mgr.forecast(46.1, 7.78, now).value<WeatherForecast>();
qDebug() << fc.dateTime() << fc.temperature() << fc.symbolType() << fc.symbolIconName();
QVERIFY(fc.isValid());
QVERIFY(fc.dateTime().isValid());
QVERIFY(fc.dateTime() <= now);
QVERIFY(fc.symbolType() != WeatherForecast::Unknown);
QVERIFY(fc.temperature() > -50);
QVERIFY(fc.temperature() < 50);
}
};
QTEST_GUILESS_MAIN(WeatherTest)
#include "weathertest.moc"
add_subdirectory(weather)
add_subdirectory(app)
......@@ -27,6 +27,7 @@ add_executable(itinerary-app
target_include_directories(itinerary-app PRIVATE ${CMAKE_BINARY_DIR})
target_link_libraries(itinerary-app PRIVATE
itinerary
itinerary-weather
Qt5::Quick
KF5::Contacts
)
......
set(weather_srcs
weatherforecast.cpp
weatherforecastmanager.cpp
)
add_library(itinerary-weather STATIC ${weather_srcs})
target_link_libraries(itinerary-weather
PUBLIC
Qt5::Core
PRIVATE
Qt5::Network
${ZLIB_LIBRARIES}
)
/*
Copyright (C) 2018 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program 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 Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "weatherforecast.h"
#include <QDateTime>
class WeatherForecastPrivate : public QSharedData {
public:
QDateTime m_dt;
float m_temp = -300;
WeatherForecast::SymbolType m_symbol = WeatherForecast::Unknown;
};
WeatherForecast::WeatherForecast()
: d(new WeatherForecastPrivate)
{
}
WeatherForecast::WeatherForecast(const WeatherForecast&) = default;
WeatherForecast::~WeatherForecast() = default;
WeatherForecast& WeatherForecast::operator=(const WeatherForecast&) = default;
bool WeatherForecast::isValid() const
{
return d->m_dt.isValid();
}
QDateTime WeatherForecast::dateTime() const
{
return d->m_dt;
}
void WeatherForecast::setDateTime(const QDateTime &dt)
{
d.detach();
d->m_dt = dt;
}
float WeatherForecast::temperature() const
{
return d->m_temp;
}
void WeatherForecast::setTemperature(float t)
{
d.detach();
d->m_temp = t;
}
WeatherForecast::SymbolType WeatherForecast::symbolType() const
{
return d->m_symbol;
}
void WeatherForecast::setSymbolType(WeatherForecast::SymbolType type)
{
d.detach();
d->m_symbol = type;
}
QString WeatherForecast::symbolIconName() const
{
return {}; // TODO map to breeze icons and determine day/night version
}
void WeatherForecast::merge(WeatherForecast &other)
{
d.detach();
if (d->m_temp < -273.15) {
d->m_temp = other.temperature();
}
if (d->m_symbol == Unknown) {
d->m_symbol = other.symbolType();
}
}
/*
Copyright (C) 2018 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program 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 Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WEATHERFORECAST_H
#define WEATHERFORECAST_H
#include <QExplicitlySharedDataPointer>
#include <QMetaType>
#include <cstdint>
class QDateTime;
class WeatherForecastPrivate;
/** Weather forecast data */
class WeatherForecast
{
Q_GADGET
public:
/** Weather symbol, aligned with the Breeze icon theme, not the data source symbols. */
enum SymbolType : uint8_t {
Unknown,
Clear,
LightClouds,
PartlyCloudy,
RainShowers,
LightRainShowers,
LightSnowShowers,
ThunderStormShowers,
// ^ have day and night variants
// v only universal variants
Clouds,
Fog,
Rain,
LightRain,
Hail,
Snow,
LightSnow,
ThunderStorm
};
Q_ENUM(SymbolType)
WeatherForecast();
WeatherForecast(const WeatherForecast&);
~WeatherForecast();
WeatherForecast& operator=(const WeatherForecast&);
bool isValid() const;
/** The time this data is valid for. */
QDateTime dateTime() const;
void setDateTime(const QDateTime &dt);
// TODO is this enough or do we need min/max ranges?
float temperature() const;
void setTemperature(float t);
SymbolType symbolType() const;
void setSymbolType(SymbolType type);
QString symbolIconName() const;
// TODO precipitation probability
/** Merge with @p other. */
void merge(WeatherForecast &other);
private:
QExplicitlySharedDataPointer<WeatherForecastPrivate> d;
};
Q_DECLARE_METATYPE(WeatherForecast)
#endif // WEATHERFORECAST_H
This diff is collapsed.
/*
Copyright (C) 2018 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program 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 Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WEATHERFORECASTMANAGER_H
#define WEATHERFORECASTMANAGER_H
#include <QObject>
#include <deque>
#include <vector>
class WeatherForecast;
struct WeatherTile;
class QNetworkAccessManager;
class QNetworkReply;
class QXmlStreamReader;
/** Access to weather forecast data based on geo coorinates. */
class WeatherForecastManager : public QObject
{
Q_OBJECT
public:
explicit WeatherForecastManager(QObject *parent = nullptr);
~WeatherForecastManager();
/** Monitor the specified location for weather forecasts. */
void monitorLocation(float latitude, float longitude);
// TODO unmonitor location(s)?
/** Get the forecast for the given time and location. */
Q_INVOKABLE QVariant forecast(float latitude, float longitude, const QDateTime &dt) const;
signals:
/** Updated when new forecast data has been retrieved. */
void forecastUpdated();
private:
void fetchTile(WeatherTile tile);
void fetchNext();
void tileDownloaded();
QString cachePath(WeatherTile tile) const;
void writeToCacheFile(QNetworkReply *reply) const;
void mergeForecasts(std::vector<WeatherForecast> &forecasts) const;
std::vector<WeatherForecast> parseForecast(QXmlStreamReader &reader) const;
WeatherForecast parseForecastElement(QXmlStreamReader &reader) const;
std::vector<WeatherTile> m_monitoredTiles;
std::deque<WeatherTile> m_pendingTiles;
QNetworkAccessManager *m_nam = nullptr;
QNetworkReply *m_pendingReply = nullptr;
};
#endif // WEATHERFORECASTMANAGER_H
/*
Copyright (C) 2018 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program 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 Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WEATHERTILE_H
#define WEATHERTILE_H
#include <QMetaType>
#include <cmath>
#include <cstdint>
/** Weather forecast data tile coordinates */
struct WeatherTile
{
// tile size in 1/nth of a degree
static const constexpr auto Size = 10.0;
inline constexpr WeatherTile() = default;
inline constexpr WeatherTile(float latitude, float longitude)
: x(uint16_t(std::round(latitude * WeatherTile::Size)))
, y(uint16_t(std::round(longitude * WeatherTile::Size)))
{}
inline constexpr bool operator<(WeatherTile other)
{
return std::tie(x, y) < std::tie(other.x, other.y);
}
inline constexpr bool operator==(WeatherTile other)
{
return x == other.x && y == other.y;
}
uint16_t x = 0;
uint16_t y = 0;
};
Q_DECLARE_METATYPE(WeatherTile)
#endif // WEATHERTILE_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment