diff --git a/images/lunch-meal.png b/images/lunch-meal.png new file mode 100644 index 0000000..7c83e54 Binary files /dev/null and b/images/lunch-meal.png differ diff --git a/lunchmealdialog.cpp b/lunchmealdialog.cpp new file mode 100644 index 0000000..2bed534 --- /dev/null +++ b/lunchmealdialog.cpp @@ -0,0 +1,20 @@ +#include "lunchmealdialog.h" +#include "ui_lunchmealdialog.h" + +#include +#include + +LunchMealDialog::LunchMealDialog(const QDate &date, const QString &content, QWidget *parent) : + ZeiterfassungDialog(parent), + ui(new Ui::LunchMealDialog) +{ + ui->setupUi(this); + + ui->labelTitle->setText(tr("Lunch meal for %0").arg(QLocale().toString(date))); + ui->labelLunchMeal->setText(content); +} + +LunchMealDialog::~LunchMealDialog() +{ + delete ui; +} diff --git a/lunchmealdialog.h b/lunchmealdialog.h new file mode 100644 index 0000000..f20ceb8 --- /dev/null +++ b/lunchmealdialog.h @@ -0,0 +1,21 @@ +#pragma once + +#include "zeiterfassungdialog.h" + +class QDate; + +class StripsWidget; + +namespace Ui { class LunchMealDialog; } + +class LunchMealDialog : public ZeiterfassungDialog +{ + Q_OBJECT + +public: + explicit LunchMealDialog(const QDate &date, const QString &content, QWidget *parent = Q_NULLPTR); + ~LunchMealDialog(); + +private: + Ui::LunchMealDialog *ui; +}; diff --git a/lunchmealdialog.ui b/lunchmealdialog.ui new file mode 100644 index 0000000..ab5ffa7 --- /dev/null +++ b/lunchmealdialog.ui @@ -0,0 +1,88 @@ + + + LunchMealDialog + + + + 0 + 0 + 400 + 300 + + + + Lunch meal + + + + + + + 16 + 75 + true + + + + Lunch meal for + + + + + + + Loading... + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + LunchMealDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + LunchMealDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/lunchmealplugin.cpp b/lunchmealplugin.cpp new file mode 100644 index 0000000..a7414d8 --- /dev/null +++ b/lunchmealplugin.cpp @@ -0,0 +1,44 @@ +#include "lunchmealplugin.h" + +#include +#include +#include +#include +#include + +#include "mainwindow.h" +#include "stripswidget.h" + +#include "lunchmealwidget.h" +#include "lunchmealsettingswidget.h" + +LunchMealPlugin::LunchMealPlugin(QObject *parent) : + ZeiterfassungPlugin(parent) +{ + qDebug() << "called"; + + static auto dir = QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(QStringLiteral("translations")); + + if(m_translator.load(QLocale(), QStringLiteral("lunchmealplugin"), QStringLiteral("_"), dir)) + { + if(!QCoreApplication::installTranslator(&m_translator)) + { + qWarning() << "could not install translation lunchmealplugin"; + } + } + else + { + qWarning() << "could not load translation lunchmealplugin"; + } +} + +void LunchMealPlugin::attachTo(MainWindow &mainWindow) +{ + for(auto stripsWidget : mainWindow.stripsWidgets()) + stripsWidget->headerLayout()->addWidget(new LunchMealWidget(*stripsWidget)); +} + +SettingsWidget *LunchMealPlugin::settingsWidget(ZeiterfassungSettings &settings, QWidget *parent) const +{ + return new LunchMealSettingsWidget(settings, parent); +} diff --git a/lunchmealplugin.h b/lunchmealplugin.h new file mode 100644 index 0000000..d74a61a --- /dev/null +++ b/lunchmealplugin.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#include "zeiterfassungplugin.h" + +class MainWindow; + +class Q_DECL_EXPORT LunchMealPlugin : public ZeiterfassungPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "dbsoftware.zeiterfassung.plugin/1.0" FILE "lunchmealplugin.json") + Q_INTERFACES(ZeiterfassungPlugin) + +public: + explicit LunchMealPlugin(QObject *parent = Q_NULLPTR); + + // ZeiterfassungPlugin interface + void attachTo(MainWindow &mainWindow) Q_DECL_OVERRIDE; + + virtual SettingsWidget *settingsWidget(ZeiterfassungSettings &settings, QWidget *parent = Q_NULLPTR) const Q_DECL_OVERRIDE; + +private: + QTranslator m_translator; +}; diff --git a/lunchmealplugin.json b/lunchmealplugin.json new file mode 100644 index 0000000..e69de29 diff --git a/lunchmealplugin.pro b/lunchmealplugin.pro new file mode 100644 index 0000000..df81538 --- /dev/null +++ b/lunchmealplugin.pro @@ -0,0 +1,28 @@ +QT += core network gui widgets + +DBLIBS += zeiterfassungcore zeiterfassunggui + +TARGET = lunchmealplugin + +HEADERS += lunchmealdialog.h \ + lunchmealsettings.h \ + lunchmealsettingswidget.h \ + lunchmealplugin.h \ + lunchmealwidget.h + +SOURCES += lunchmealdialog.cpp \ + lunchmealsettings.cpp \ + lunchmealsettingswidget.cpp \ + lunchmealplugin.cpp \ + lunchmealwidget.cpp + +FORMS += lunchmealdialog.ui + +RESOURCES += lunchmealplugin_resources.qrc + +TRANSLATIONS += translations/lunchmealplugin_en.ts \ + translations/lunchmealplugin_de.ts + +OTHER_FILES += lunchmealplugin.json + +include(../plugin.pri) diff --git a/lunchmealplugin_resources.qrc b/lunchmealplugin_resources.qrc new file mode 100644 index 0000000..ca3c14e --- /dev/null +++ b/lunchmealplugin_resources.qrc @@ -0,0 +1,5 @@ + + + images/lunch-meal.png + + diff --git a/lunchmealsettings.cpp b/lunchmealsettings.cpp new file mode 100644 index 0000000..3703770 --- /dev/null +++ b/lunchmealsettings.cpp @@ -0,0 +1,73 @@ +#include "lunchmealsettings.h" + +#include "zeiterfassungsettings.h" + +const QString LunchMealSettings::m_url("LunchMealPlugin/url"); +const QString LunchMealSettings::m_dateFormat("LunchMealPlugin/dateFormat"); +const QString LunchMealSettings::m_defaultUrl("https://brunner.ninja/lunch/%0.txt"); +const QString LunchMealSettings::m_defaultDateFormat("yyyy-MM-dd"); + +LunchMealSettings::LunchMealSettings(ZeiterfassungSettings &settings, QObject *parent) : + QObject(parent), + m_settings(settings) +{ + +} + +QString LunchMealSettings::url() const +{ + return m_settings.value(m_url, m_defaultUrl).toString(); +} + +bool LunchMealSettings::setUrl(const QString &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; +} + +QString LunchMealSettings::dateFormat() const +{ + return m_settings.value(m_dateFormat, m_defaultDateFormat).toString(); +} + +bool LunchMealSettings::setDateFormat(const QString &dateFormat) +{ + if(this->dateFormat() == dateFormat) + return true; + + if(dateFormat == m_defaultDateFormat) + m_settings.remove(m_dateFormat); + else + m_settings.setValue(m_dateFormat, dateFormat); + + m_settings.sync(); + + const auto success = m_settings.status() == QSettings::NoError; + if(success) + Q_EMIT dateFormatChanged(dateFormat); + else + { + Q_EMIT m_settings.saveErrorOccured(); + Q_EMIT saveErrorOccured(); + } + + return success; +} diff --git a/lunchmealsettings.h b/lunchmealsettings.h new file mode 100644 index 0000000..6c8eec5 --- /dev/null +++ b/lunchmealsettings.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +class ZeiterfassungSettings; + +class LunchMealSettings : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged) + Q_PROPERTY(QString dateFormat READ dateFormat WRITE setDateFormat NOTIFY dateFormatChanged) + +public: + LunchMealSettings(ZeiterfassungSettings &settings, QObject *parent = Q_NULLPTR); + + // no QString becuase placeholder %0 encodes wrong in urls! + QString url() const; + bool setUrl(const QString &url); + + QString dateFormat() const; + bool setDateFormat(const QString &dateFormat); + +Q_SIGNALS: + void saveErrorOccured(); + + void urlChanged(const QString &url); + void dateFormatChanged(const QString &dateFormat); + +private: + ZeiterfassungSettings &m_settings; + + static const QString m_url; + static const QString m_dateFormat; + static const QString m_defaultUrl; + static const QString m_defaultDateFormat; +}; diff --git a/lunchmealsettingswidget.cpp b/lunchmealsettingswidget.cpp new file mode 100644 index 0000000..6f5754b --- /dev/null +++ b/lunchmealsettingswidget.cpp @@ -0,0 +1,36 @@ +#include "lunchmealsettingswidget.h" + +#include +#include + +LunchMealSettingsWidget::LunchMealSettingsWidget(ZeiterfassungSettings &settings, QWidget *parent) : + SettingsWidget(parent), + m_settings(settings) +{ + auto layout = new QFormLayout(this); + layout->setMargin(0); + + m_lineEditUrl = new QLineEdit(m_settings.url(), this); + layout->addRow(tr("Lunch meal API:"), m_lineEditUrl); + + m_lineEditDateFormat = new QLineEdit(m_settings.dateFormat(), this); + layout->addRow(tr("Lunch meal date format:"), m_lineEditDateFormat); + + setLayout(layout); +} + +bool LunchMealSettingsWidget::isValid(QString &message) const +{ + auto valid = QUrl::fromUserInput(m_lineEditUrl->text()).isValid(); + + if(!valid) + message = tr("The lunch meal api url is invalid!"); + + return valid; +} + +bool LunchMealSettingsWidget::apply() +{ + return m_settings.setUrl(m_lineEditUrl->text()) && + m_settings.setDateFormat(m_lineEditDateFormat->text()); +} diff --git a/lunchmealsettingswidget.h b/lunchmealsettingswidget.h new file mode 100644 index 0000000..779125d --- /dev/null +++ b/lunchmealsettingswidget.h @@ -0,0 +1,26 @@ +#pragma once + +#include "settingswidget.h" + +#include "lunchmealsettings.h" + +class QLineEdit; + +class LunchMealSettingsWidget : public SettingsWidget +{ + Q_OBJECT + +public: + explicit LunchMealSettingsWidget(ZeiterfassungSettings &settings, QWidget *parent = Q_NULLPTR); + + virtual bool isValid(QString &message) const Q_DECL_OVERRIDE; + +public Q_SLOTS: + virtual bool apply() Q_DECL_OVERRIDE; + +private: + LunchMealSettings m_settings; + + QLineEdit *m_lineEditUrl; + QLineEdit *m_lineEditDateFormat; +}; diff --git a/lunchmealwidget.cpp b/lunchmealwidget.cpp new file mode 100644 index 0000000..b5dd611 --- /dev/null +++ b/lunchmealwidget.cpp @@ -0,0 +1,67 @@ +#include "lunchmealwidget.h" + +#include +#include +#include +#include +#include +#include + +#include "stripswidget.h" +#include "mainwindow.h" +#include "zeiterfassungapi.h" + +#include "lunchmealdialog.h" +#include "lunchmealsettings.h" + +LunchMealWidget::LunchMealWidget(StripsWidget &stripsWidget) : + QToolButton(&stripsWidget), + m_stripsWidget(stripsWidget) +{ + setIcon(QIcon(QStringLiteral(":/zeiterfassung/plugins/lunchmealplugin/images/lunch-meal.png"))); + setText(tr("Lunch meal")); + + connect(this, &QAbstractButton::pressed, this, &LunchMealWidget::pressedSlot); + + connect(&m_stripsWidget, &StripsWidget::dateChanged, this, &LunchMealWidget::dateChanged); + dateChanged(m_stripsWidget.date()); +} + +void LunchMealWidget::pressedSlot() +{ + LunchMealDialog dialog(m_stripsWidget.date(), m_content, this); + dialog.exec(); +} + +void LunchMealWidget::dateChanged(const QDate &date) +{ + setEnabled(false); + setVisible(false); + + LunchMealSettings settings(m_stripsWidget.mainWindow().settings()); + + auto url = QUrl(settings.url().arg(date.toString(settings.dateFormat()))); + m_reply = std::unique_ptr(m_stripsWidget.mainWindow().erfassung().manager()->get(QNetworkRequest(url))); + connect(m_reply.get(), &QNetworkReply::finished, this, &LunchMealWidget::finished); +} + +void LunchMealWidget::finished() +{ + if(m_reply->error() != QNetworkReply::NoError && + m_reply->error() != QNetworkReply::ContentNotFoundError) + { + QMessageBox::warning(&m_stripsWidget.mainWindow(), tr("Could not load lunch meal!"), + tr("Could not load lunch meal!") % "\n\n" % m_reply->errorString()); + goto after; + } + + if(m_reply->error() == QNetworkReply::NoError) + { + setEnabled(true); + setVisible(true); + m_content = m_reply->readAll(); + } + + after: + m_reply = Q_NULLPTR; +} diff --git a/lunchmealwidget.h b/lunchmealwidget.h new file mode 100644 index 0000000..a3a9f77 --- /dev/null +++ b/lunchmealwidget.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include +#include + +class StripsWidget; + +class LunchMealWidget : public QToolButton +{ + Q_OBJECT + +public: + explicit LunchMealWidget(StripsWidget &stripsWidget); + +private Q_SLOTS: + void pressedSlot(); + void dateChanged(const QDate &date); + void finished(); + +private: + StripsWidget &m_stripsWidget; + std::unique_ptr m_reply; + QString m_content; +}; diff --git a/translations/lunchmealplugin_de.ts b/translations/lunchmealplugin_de.ts new file mode 100644 index 0000000..ee5c573 --- /dev/null +++ b/translations/lunchmealplugin_de.ts @@ -0,0 +1,41 @@ + + + + + LunchMealDialog + + + Lunch meal + Mittagsmenü + + + + Loading... + Lade... + + + + Lunch meal for %0 + Mittagsmenü vom %0 + + + + dd.MM.yyyy + dd.MM.yyyy + + + + LunchMealWidget + + + Lunch meal + Mittagsmenü + + + + + Could not load lunch meal! + + + + diff --git a/translations/lunchmealplugin_en.ts b/translations/lunchmealplugin_en.ts new file mode 100644 index 0000000..3044d95 --- /dev/null +++ b/translations/lunchmealplugin_en.ts @@ -0,0 +1,41 @@ + + + + + LunchMealDialog + + + Lunch meal + + + + + Loading... + + + + + Lunch meal for %0 + + + + + dd.MM.yyyy + + + + + LunchMealWidget + + + Lunch meal + + + + + + Could not load lunch meal! + + + +