diff --git a/translations/weatherplugin_de.ts b/translations/weatherplugin_de.ts
new file mode 100644
index 0000000..18961a2
--- /dev/null
+++ b/translations/weatherplugin_de.ts
@@ -0,0 +1,42 @@
+
+
+
+
+ WeatherWidget
+
+
+ Loading...
+ Lade...
+
+
+
+ Request failed
+ Anfrage fehlgeschlagen
+
+
+
+ Parsing failed
+ Parsen fehlgeschlagen
+
+
+
+ Not an json obj
+ Kein json obj
+
+
+
+ No weather found
+ Kein weather gefunden
+
+
+
+ No main found
+ Kein main gefunden
+
+
+
+ %0 (%1°C)
+ %0 (%1°C)
+
+
+
diff --git a/translations/weatherplugin_en.ts b/translations/weatherplugin_en.ts
new file mode 100644
index 0000000..1c9d0aa
--- /dev/null
+++ b/translations/weatherplugin_en.ts
@@ -0,0 +1,42 @@
+
+
+
+
+ WeatherWidget
+
+
+ Loading...
+
+
+
+
+ Request failed
+
+
+
+
+ Parsing failed
+
+
+
+
+ Not an json obj
+
+
+
+
+ No weather found
+
+
+
+
+ No main found
+
+
+
+
+ %0 (%1°C)
+
+
+
+
diff --git a/weatherplugin.cpp b/weatherplugin.cpp
new file mode 100644
index 0000000..a09feee
--- /dev/null
+++ b/weatherplugin.cpp
@@ -0,0 +1,42 @@
+#include "weatherplugin.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include "mainwindow.h"
+
+#include "weatherwidget.h"
+#include "weathersettingswidget.h"
+
+WeatherPlugin::WeatherPlugin(QObject *parent) :
+ ZeiterfassungPlugin(parent)
+{
+ qDebug() << "called";
+
+ static auto dir = QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(QStringLiteral("translations"));
+
+ if(m_translator.load(QLocale(), QStringLiteral("weatherplugin"), QStringLiteral("_"), dir))
+ {
+ if(!QCoreApplication::installTranslator(&m_translator))
+ {
+ qWarning() << "could not install translation weatherplugin";
+ }
+ }
+ else
+ {
+ qWarning() << "could not load translation weatherplugin";
+ }
+}
+
+void WeatherPlugin::attachTo(MainWindow &mainWindow)
+{
+ mainWindow.statusBar()->addWidget(new WeatherWidget(mainWindow));
+}
+
+SettingsWidget *WeatherPlugin::settingsWidget(ZeiterfassungSettings &settings, QWidget *parent) const
+{
+ return new WeatherSettingsWidget(settings, parent);
+}
diff --git a/weatherplugin.h b/weatherplugin.h
new file mode 100644
index 0000000..f4fd64c
--- /dev/null
+++ b/weatherplugin.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include
+#include
+
+#include "zeiterfassungplugin.h"
+
+class SettingsWidget;
+class ZeiterfassungSettings;
+
+class Q_DECL_EXPORT WeatherPlugin : public ZeiterfassungPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "dbsoftware.zeiterfassung.plugin/1.0" FILE "weatherplugin.json")
+ Q_INTERFACES(ZeiterfassungPlugin)
+
+public:
+ explicit WeatherPlugin(QObject *parent = Q_NULLPTR);
+
+ // ZeiterfassungPlugin interface
+ void attachTo(MainWindow &mainWindow) Q_DECL_OVERRIDE;
+
+ SettingsWidget *settingsWidget(ZeiterfassungSettings &settings, QWidget *parent = Q_NULLPTR) const Q_DECL_OVERRIDE;
+
+private:
+ QTranslator m_translator;
+};
diff --git a/weatherplugin.json b/weatherplugin.json
new file mode 100644
index 0000000..e69de29
diff --git a/weatherplugin.pro b/weatherplugin.pro
new file mode 100644
index 0000000..4ef451c
--- /dev/null
+++ b/weatherplugin.pro
@@ -0,0 +1,26 @@
+QT += core network gui widgets
+
+DBLIBS += zeiterfassungcore zeiterfassunggui
+
+TARGET = weatherplugin
+
+HEADERS += weatherplugin.h \
+ weathersettings.h \
+ weathersettingswidget.h \
+ weatherwidget.h
+
+SOURCES += weatherplugin.cpp \
+ weathersettings.cpp \
+ weathersettingswidget.cpp \
+ weatherwidget.cpp
+
+FORMS +=
+
+RESOURCES +=
+
+TRANSLATIONS += translations/weatherplugin_en.ts \
+ translations/weatherplugin_de.ts
+
+OTHER_FILES += weatherplugin.json
+
+include(../plugin.pri)
diff --git a/weathersettings.cpp b/weathersettings.cpp
new file mode 100644
index 0000000..71332df
--- /dev/null
+++ b/weathersettings.cpp
@@ -0,0 +1,42 @@
+#include "weathersettings.h"
+
+#include "zeiterfassungsettings.h"
+
+const QString WeatherSettings::m_url("WeatherPlugin/url");
+const QUrl WeatherSettings::m_defaultUrl(QStringLiteral("http://api.openweathermap.org/data/2.5/weather?q=Graz,AT&units=metric&APPID=40f6c892c6162680c6c9235169dc9f83"));
+
+WeatherSettings::WeatherSettings(ZeiterfassungSettings &settings, QObject *parent) :
+ QObject(parent),
+ m_settings(settings)
+{
+
+}
+
+QUrl WeatherSettings::url() const
+{
+ return m_settings.value(m_url, m_defaultUrl).toUrl();
+}
+
+bool WeatherSettings::setUrl(const QUrl &url)
+{
+ if(this->url() == url)
+ return true;
+
+ if(url == m_defaultUrl)
+ m_settings.remove(m_url);
+ else
+ m_settings.setValue(m_url, url);
+
+ m_settings.sync();
+
+ const auto success = m_settings.status() == QSettings::NoError;
+ if(success)
+ Q_EMIT urlChanged(url);
+ else
+ {
+ Q_EMIT m_settings.saveErrorOccured();
+ Q_EMIT saveErrorOccured();
+ }
+
+ return success;
+}
diff --git a/weathersettings.h b/weathersettings.h
new file mode 100644
index 0000000..aa9fb2f
--- /dev/null
+++ b/weathersettings.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include
+#include
+
+class ZeiterfassungSettings;
+
+class WeatherSettings : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged)
+
+public:
+ WeatherSettings(ZeiterfassungSettings &settings, QObject *parent = Q_NULLPTR);
+
+ QUrl url() const;
+ bool setUrl(const QUrl &url);
+
+Q_SIGNALS:
+ void saveErrorOccured();
+
+ void urlChanged(const QUrl &url);
+
+private:
+ ZeiterfassungSettings &m_settings;
+
+ static const QString m_url;
+ static const QUrl m_defaultUrl;
+};
diff --git a/weathersettingswidget.cpp b/weathersettingswidget.cpp
new file mode 100644
index 0000000..35f3cb5
--- /dev/null
+++ b/weathersettingswidget.cpp
@@ -0,0 +1,32 @@
+#include "weathersettingswidget.h"
+
+#include
+#include
+
+WeatherSettingsWidget::WeatherSettingsWidget(ZeiterfassungSettings &settings, QWidget *parent) :
+ SettingsWidget(parent),
+ m_settings(settings)
+{
+ auto layout = new QFormLayout(this);
+ layout->setMargin(0);
+
+ m_lineEdit = new QLineEdit(m_settings.url().toString(), this);
+ layout->addRow(tr("Weather API:"), m_lineEdit);
+
+ setLayout(layout);
+}
+
+bool WeatherSettingsWidget::isValid(QString &message) const
+{
+ auto valid = QUrl::fromUserInput(m_lineEdit->text()).isValid();
+
+ if(!valid)
+ message = tr("The weather api url is invalid!");
+
+ return valid;
+}
+
+bool WeatherSettingsWidget::apply()
+{
+ return m_settings.setUrl(QUrl::fromUserInput(m_lineEdit->text()));
+}
diff --git a/weathersettingswidget.h b/weathersettingswidget.h
new file mode 100644
index 0000000..7936f48
--- /dev/null
+++ b/weathersettingswidget.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include
+
+#include "settingswidget.h"
+
+#include "weathersettings.h"
+
+class QLineEdit;
+
+class ZeiterfassungSettings;
+
+class WeatherSettingsWidget : public SettingsWidget
+{
+ Q_OBJECT
+
+public:
+ explicit WeatherSettingsWidget(ZeiterfassungSettings &settings, QWidget *parent = Q_NULLPTR);
+
+ bool isValid(QString &message) const Q_DECL_OVERRIDE;
+
+public Q_SLOTS:
+ virtual bool apply() Q_DECL_OVERRIDE;
+
+private:
+ WeatherSettings m_settings;
+
+ QLineEdit *m_lineEdit;
+};
diff --git a/weatherwidget.cpp b/weatherwidget.cpp
new file mode 100644
index 0000000..9d62b09
--- /dev/null
+++ b/weatherwidget.cpp
@@ -0,0 +1,92 @@
+#include "weatherwidget.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "mainwindow.h"
+#include "zeiterfassungsettings.h"
+#include "zeiterfassungapi.h"
+
+#include "weathersettings.h"
+
+WeatherWidget::WeatherWidget(MainWindow &mainWindow) :
+ QLabel(&mainWindow),
+ m_mainWindow(mainWindow)
+{
+ setFrameShape(QFrame::Panel);
+ setFrameShadow(QFrame::Sunken);
+
+ connect(&m_mainWindow, &MainWindow::refreshEverything, this, &WeatherWidget::refresh);
+
+ refresh();
+}
+
+void WeatherWidget::refresh()
+{
+ setText(tr("Loading..."));
+
+ auto url = WeatherSettings(m_mainWindow.settings()).url();
+
+ m_reply = std::unique_ptr(m_mainWindow.erfassung().manager()->get(QNetworkRequest(url)));
+ connect(m_reply.get(), &QNetworkReply::finished, this, &WeatherWidget::finished);
+}
+
+void WeatherWidget::finished()
+{
+ if(m_reply->error() != QNetworkReply::NoError)
+ {
+ qWarning() << m_reply->errorString();
+ setText(tr("Request failed"));
+ goto after;
+ }
+
+ {
+ QJsonParseError error;
+
+ auto document = QJsonDocument::fromJson(m_reply->readAll(), &error);
+ if(error.error != QJsonParseError::NoError)
+ {
+ qWarning() << error.errorString();
+ setText(tr("Parsing failed"));
+ goto after;
+ }
+
+ if(!document.isObject())
+ {
+ setText(tr("Not an json obj"));
+ goto after;
+ }
+
+ auto obj = document.object();
+
+ if(!obj.contains(QStringLiteral("weather")))
+ {
+ qWarning() << "no weather" << obj;
+ setText(tr("No weather found"));
+ goto after;
+ }
+
+ if(!obj.contains(QStringLiteral("main")))
+ {
+ qWarning() << "no main" << obj;
+ setText(tr("No main found"));
+ goto after;
+ }
+
+ auto weaterObj = obj.value(QStringLiteral("weather")).toArray();
+ auto mainObj = obj.value(QStringLiteral("main")).toObject();
+
+ setText(tr("%0 (%1°C)").arg(weaterObj.first().toObject().value(QStringLiteral("main")).toString())
+ .arg(mainObj.value(QStringLiteral("temp")).toDouble()));
+ }
+
+ after:
+ m_reply = Q_NULLPTR;
+}
diff --git a/weatherwidget.h b/weatherwidget.h
new file mode 100644
index 0000000..8a3a2f7
--- /dev/null
+++ b/weatherwidget.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include
+
+#include
+#include
+
+class MainWindow;
+
+class WeatherWidget : public QLabel
+{
+ Q_OBJECT
+
+public:
+ explicit WeatherWidget(MainWindow &mainWindow);
+
+private Q_SLOTS:
+ void refresh();
+ void finished();
+
+private:
+ MainWindow &m_mainWindow;
+
+ std::unique_ptr m_reply;
+};