ui: Show news sent with update check on start screen

* News are passed as JSON string, containing an array of news items.
* Each news item has version and content (html).
* Items can be filtered by min/max version, OS and license. The first item that fits is used.
* Items can be important, which highlights the news box.
* News are not shown if older than 5 days.

fortune cookie message = You will be financially successful in case your actions are well planned.
This commit is contained in:
Eberhard Graether
2018-10-21 13:49:06 +02:00
parent 518f15d490
commit 6a6bd0fca8
17 changed files with 463 additions and 102 deletions
+227
View File
@@ -0,0 +1,227 @@
#include "QtNewsWidget.h"
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QVBoxLayout>
#include <QStyle>
#include "ApplicationSettings.h"
#include "LicenseChecker.h"
#include "logging.h"
#include "QtTextEdit.h"
#include "TimeStamp.h"
#include "utilityApp.h"
#include "Version.h"
QtNewsWidget::QtNewsWidget(QWidget* parent)
: QWidget(parent)
{
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
m_text = new QtTextEdit();
m_text->setObjectName("textField");
m_text->setReadOnly(true);
m_text->setTabStopWidth(8 * m_text->fontMetrics().width('9'));
m_text->setViewportMargins(6, 4, 16, 4);
m_text->setOpenExternalLinks(true);
layout->addWidget(m_text);
QString placeholder = "No news available";
if (!ApplicationSettings::getInstance()->getAutomaticUpdateCheck())
{
placeholder += "\n(Enable update check)";
}
m_text->setPlaceholderText(placeholder);
updateNews();
}
/*
syntax:
[
{
// required
"version": 1,
"content": "<b>Hello World!</b>",
// optional
"conditions":
{
"license": ["test", "private", "commercial"],
"os": ["windows", "macOS", "linux"],
"min_version": "2017.2.0",
"max_version": "2018.4.2",
}
// optional
"flags":
{
"important": true
}
}
]
*/
void QtNewsWidget::updateNews()
{
const int supportedNewsItemVersion = 1;
resetFlags();
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
std::string newsRaw = appSettings->getUpdateNews();
if (!newsRaw.size())
{
setNews("");
return;
}
if (TimeStamp::now().deltaHours(appSettings->getLastUpdateCheck()) >= 120)
{
LOG_INFO_STREAM(<< "Ignore news string, because older than 5 days.");
setNews("");
return;
}
LOG_INFO_STREAM(<< "Process news string: " << newsRaw);
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(QString::fromStdString(newsRaw).toUtf8(), &error);
if (doc.isNull() || !doc.isArray())
{
LOG_ERROR_STREAM(<< "News string couldn't be parsed as JSON: " << error.errorString().toStdString()
<< "\nJSON: " << newsRaw);
setNews("");
return;
}
size_t itemNum = 0;
for (QJsonValueRef value : doc.array())
{
itemNum++;
QJsonObject newsItem = value.toObject();
int version = newsItem.value("version").toInt();
if (version > supportedNewsItemVersion)
{
LOG_INFO_STREAM(<< "News item " << itemNum << " version " << version << " is not supported.");
continue;
}
if (!checkConditions(newsItem.value("conditions").toObject()))
{
LOG_INFO_STREAM(<< "News item " << itemNum << " conditions failed.");
continue;
}
processFlags(newsItem.value("flags").toObject());
setNews(newsItem.value("content").toString());
return;
}
setNews("");
}
void QtNewsWidget::resetFlags()
{
setImportant(false);
}
void QtNewsWidget::setNews(const QString& news)
{
m_text->setHtml(news);
}
void QtNewsWidget::setImportant(bool important)
{
m_text->setProperty("important", important);
m_text->style()->unpolish(m_text);
m_text->style()->polish(m_text);
}
bool QtNewsWidget::checkConditions(const QJsonObject& conditions) const
{
if (conditions.isEmpty())
{
return true;
}
// min_version
{
QString minVersionString = conditions.value("min_version").toString();
if (!minVersionString.isEmpty())
{
Version minVersion = Version::fromString(minVersionString.toStdString());
if (minVersion.isValid() && minVersion > Version::getApplicationVersion())
{
LOG_INFO_STREAM(<< "Failed condition min_version.");
return false;
}
}
}
// max_version
{
QString maxVersionString = conditions.value("max_version").toString();
if (!maxVersionString.isEmpty())
{
Version maxVersion = Version::fromString(maxVersionString.toStdString());
if (maxVersion.isValid() && maxVersion < Version::getApplicationVersion())
{
LOG_INFO_STREAM(<< "Failed condition max_version.");
return false;
}
}
}
// license
{
QJsonArray licenseStrings = conditions.value("license").toArray();
if (!licenseStrings.isEmpty())
{
QString licenseString = QString::fromStdString(LicenseChecker::getCurrentLicenseTypeString());
if (!licenseStrings.contains(QJsonValue(licenseString)))
{
LOG_INFO_STREAM(<< "Failed condition license.");
return false;
}
}
}
// OS
{
QJsonArray osStrings = conditions.value("os").toArray();
if (!osStrings.isEmpty())
{
QString osString = QString::fromStdString(utility::getOsTypeString());
if (!osStrings.contains(QJsonValue(osString)))
{
LOG_INFO_STREAM(<< "Failed condition os.");
return false;
}
}
}
return true;
}
void QtNewsWidget::processFlags(const QJsonObject& flags)
{
if (flags.isEmpty())
{
return;
}
// important
{
bool important = flags.value("important").toBool();
if (important)
{
LOG_INFO_STREAM(<< "Flag important enabled.");
setImportant(true);
}
}
}