Add ErrorModel, just a placholder GUI for now

This commit is contained in:
Bart De Vries 2021-04-22 17:05:33 +02:00
parent 51db7ea1cf
commit 5a0972372b
15 changed files with 240 additions and 13 deletions

View File

@ -15,6 +15,8 @@ add_executable(alligator
datamanager.cpp
audiomanager.cpp
powermanagementinterface.cpp
errorlogmodel.cpp
error.h
mpris2/mpris2.cpp
mpris2/mediaplayer2.cpp
mpris2/mediaplayer2player.cpp

View File

@ -52,6 +52,7 @@ bool Database::migrateTo1()
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Authors (feed TEXT, id TEXT, name TEXT, uri TEXT, email TEXT);")));
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Enclosures (feed TEXT, id TEXT, duration INTEGER, size INTEGER, title TEXT, type TEXT, url TEXT, playposition INTEGER, downloaded BOOL);"))); //, filename TEXT);")));
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Queue (listnr INTEGER, feed TEXT, id TEXT, playing BOOL);")));
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Errors (url TEXT, id TEXT, code INTEGER, string TEXT, date INTEGER);")));
TRUE_OR_RETURN(execute(QStringLiteral("PRAGMA user_version = 1;")));
return true;
}

View File

@ -17,6 +17,7 @@
#include "entry.h"
#include "fetcher.h"
#include "downloadprogressmodel.h"
#include "errorlogmodel.h"
Enclosure::Enclosure(Entry *entry)
: QObject(entry)
@ -27,6 +28,7 @@ Enclosure::Enclosure(Entry *entry)
Q_EMIT downloadStatusChanged(m_entry, m_status);
});
connect(this, &Enclosure::downloadStatusChanged, &DownloadProgressModel::instance(), &DownloadProgressModel::monitorDownloadProgress);
connect(this,&Enclosure::downloadError, &ErrorLogModel::instance(), &ErrorLogModel::monitorErrorMessages);
QSqlQuery query;
query.prepare(QStringLiteral("SELECT * FROM Enclosures WHERE id=:id"));
@ -105,6 +107,7 @@ void Enclosure::download()
if(downloadJob->error() != QNetworkReply::OperationCanceledError) {
m_entry->feed()->setErrorId(downloadJob->error());
m_entry->feed()->setErrorString(downloadJob->errorString());
Q_EMIT downloadError(m_entry->feed()->url(), m_entry->id(), downloadJob->error(), downloadJob->errorString());
}
}
disconnect(this, &Enclosure::cancelDownload, this, nullptr);

View File

@ -5,8 +5,7 @@
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#ifndef ENCLOSURE_H
#define ENCLOSURE_H
#pragma once
#include <QDebug>
#include <QObject>
@ -60,6 +59,7 @@ Q_SIGNALS:
void durationChanged();
void sizeChanged();
void downloadStatusChanged(Entry* entry, Status status);
void downloadError(const QString &url, const QString &id, const int errorId, const QString &errorString);
private:
@ -76,5 +76,3 @@ private:
double m_downloadProgress = 0;
Status m_status;
};
#endif // ENCLOSURE_H

38
src/error.h Normal file
View File

@ -0,0 +1,38 @@
/**
* SPDX-FileCopyrightText: 2021 Bart De Vries <bart@mogwai.be>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include <QObject>
#include <QString>
#include <QDateTime>
class Error : public QObject
{
Q_OBJECT
Q_PROPERTY(QString url MEMBER url CONSTANT)
Q_PROPERTY(QString id MEMBER id CONSTANT)
Q_PROPERTY(int code MEMBER code CONSTANT)
Q_PROPERTY(QString string MEMBER string CONSTANT)
Q_PROPERTY(QDateTime date MEMBER date CONSTANT)
public:
Error(const QString url, const QString id, const int code, const QString string, const QDateTime date): QObject(nullptr)
{
this->url = url;
this->id = id;
this->code = code;
this->string = string;
this->date = date;
};
QString url;
QString id;
int code;
QString string;
QDateTime date;
};

81
src/errorlogmodel.cpp Normal file
View File

@ -0,0 +1,81 @@
/**
* SPDX-FileCopyrightText: 2021 Bart De Vries <bart@mogwai.be>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "errorlogmodel.h"
#include <QSqlQuery>
#include "fetcher.h"
#include "database.h"
ErrorLogModel::ErrorLogModel()
: QAbstractListModel(nullptr)
{
connect(&Fetcher::instance(), &Fetcher::error, this, &ErrorLogModel::monitorErrorMessages);
QSqlQuery query;
query.prepare(QStringLiteral("SELECT * FROM Errors ORDER BY date DESC;"));
Database::instance().execute(query);
while (query.next()) {
Error* error = new Error(query.value(QStringLiteral("url")).toString(), query.value(QStringLiteral("id")).toString(), query.value(QStringLiteral("code")).toInt(), query.value(QStringLiteral("string")).toString(), QDateTime::fromSecsSinceEpoch(query.value(QStringLiteral("date")).toInt()));
m_errors += error;
}
}
QVariant ErrorLogModel::data(const QModelIndex &index, int role) const
{
if (role != 0)
return QVariant();
return QVariant::fromValue(m_errors[index.row()]);
}
QHash<int, QByteArray> ErrorLogModel::roleNames() const
{
QHash<int, QByteArray> roleNames;
roleNames[0] = "error";
return roleNames;
}
int ErrorLogModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_errors.count();
}
void ErrorLogModel::monitorErrorMessages(const QString &url, const QString& id, const int errorCode, const QString& errorString)
{
qDebug() << "Error happened:" << url << id << errorCode << errorString;
Error* error = new Error(url, id, errorCode, errorString, QDateTime::currentDateTime());
beginInsertRows(QModelIndex(), 0, 0);
m_errors.prepend(error);
endInsertRows();
// Also add error to database
QSqlQuery query;
query.prepare(QStringLiteral("INSERT INTO Errors VALUES (:url, :id, :code, :string, :date);"));
query.bindValue(QStringLiteral(":url"), error->url);
query.bindValue(QStringLiteral(":id"), error->id);
query.bindValue(QStringLiteral(":code"), error->code);
query.bindValue(QStringLiteral(":string"), error->string);
query.bindValue(QStringLiteral(":date"), error->date.toSecsSinceEpoch());
Database::instance().execute(query);
}
void ErrorLogModel::clearAll()
{
beginResetModel();
for (auto& error : m_errors) {
delete error;
}
m_errors.clear();
endResetModel();
// Also clear errors from database
QSqlQuery query;
query.prepare(QStringLiteral("DELETE FROM Errors;"));
Database::instance().execute(query);
}

41
src/errorlogmodel.h Normal file
View File

@ -0,0 +1,41 @@
/**
* SPDX-FileCopyrightText: 2021 Bart De Vries <bart@mogwai.be>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#pragma once
#include <QAbstractListModel>
#include <QHash>
#include <QObject>
#include <QVariant>
#include <QDateTime>
#include "error.h"
class ErrorLogModel : public QAbstractListModel
{
Q_OBJECT
public:
static ErrorLogModel &instance()
{
static ErrorLogModel _instance;
return _instance;
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex &parent) const override;
Q_INVOKABLE void clearAll();
public Q_SLOTS:
void monitorErrorMessages(const QString &url, const QString &id, const int errorCode, const QString &errorString);
private:
explicit ErrorLogModel();
QList<Error*> m_errors;
};

View File

@ -58,7 +58,8 @@ Feed::Feed(QString const feedurl)
setErrorString(QLatin1String(""));
}
});
connect(&Fetcher::instance(), &Fetcher::error, this, [this](const QString &url, int errorId, const QString &errorString) {
connect(&Fetcher::instance(), &Fetcher::error, this, [this](const QString &url, const QString &id, int errorId, const QString &errorString) {
Q_UNUSED(id)
if(url == m_url) {
setErrorId(errorId);
setErrorString(errorString);

View File

@ -5,8 +5,7 @@
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#ifndef FEED_H
#define FEED_H
#pragma once
#include <QDateTime>
#include <QObject>
@ -116,5 +115,3 @@ private:
bool m_refreshing = false;
};
#endif // FEED_H

View File

@ -49,7 +49,7 @@ void Fetcher::fetch(const QString &url)
if(reply->error()) {
qWarning() << "Error fetching feed";
qWarning() << reply->errorString();
Q_EMIT error(url, reply->error(), reply->errorString());
Q_EMIT error(url, QStringLiteral(""), reply->error(), reply->errorString());
} else {
QByteArray data = reply->readAll();
Syndication::DocumentSource *document = new Syndication::DocumentSource(data, url);
@ -341,6 +341,7 @@ QString Fetcher::image(const QString& url) const
QNetworkReply *Fetcher::download(const QString &url, const QString &filePath) const
{
QNetworkRequest request((QUrl(url)));
request.setTransferTimeout();
QNetworkReply *reply = get(request);
connect(reply, &QNetworkReply::finished, this, [=]() {
if (reply->isOpen()) {

View File

@ -42,7 +42,7 @@ Q_SIGNALS:
void feedUpdated(const QString &url);
void feedDetailsUpdated(const QString &url, const QString &name, const QString &image, const QString &link, const QString &description, const QDateTime &lastUpdated);
void feedUpdateFinished(const QString &url);
void error(const QString &url, QNetworkReply::NetworkError errorId, const QString &errorString);
void error(const QString &url, const QString &id, const int errorId, const QString &errorString);
void entryAdded(const QString &feedurl, const QString &id);
void downloadFinished(QString url) const;

View File

@ -31,6 +31,7 @@
#include "queuemodel.h"
#include "episodemodel.h"
#include "downloadprogressmodel.h"
#include "errorlogmodel.h"
#include "datamanager.h"
#include "audiomanager.h"
#include "mpris2/mpris2.h"
@ -76,6 +77,10 @@ int main(int argc, char *argv[])
engine->setObjectOwnership(&DownloadProgressModel::instance(), QQmlEngine::CppOwnership);
return &DownloadProgressModel::instance();
});
qmlRegisterSingletonType<ErrorLogModel>("org.kde.alligator", 1, 0, "ErrorLogModel", [](QQmlEngine *engine, QJSEngine *) -> QObject * {
engine->setObjectOwnership(&ErrorLogModel::instance(), QQmlEngine::CppOwnership);
return &ErrorLogModel::instance();
});
qmlRegisterType<AudioManager>("org.kde.alligator", 1, 0, "AudioManager");
qmlRegisterType<Mpris2>("org.kde.alligator", 1, 0, "Mpris2");
@ -102,10 +107,9 @@ int main(int argc, char *argv[])
QObject::connect(&app, &QCoreApplication::aboutToQuit, SettingsManager::self(), &SettingsManager::save);
Database::instance();
DataManager::instance();
DownloadProgressModel::instance();
ErrorLogModel::instance();
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));

View File

@ -51,6 +51,11 @@ Kirigami.Page {
height: tabBarHeight
text: i18n("Completed")
}
Controls.TabButton {
width: parent.parent.width/parent.count
height: tabBarHeight
text: i18n("Errors")
}
}
}
@ -68,5 +73,9 @@ Kirigami.Page {
title: i18n("Completed")
episodeType: EpisodeModel.Downloaded
}
ErrorListPage {
title: i18n("Errors")
}
}
}

50
src/qml/ErrorListPage.qml Normal file
View File

@ -0,0 +1,50 @@
/**
* SPDX-FileCopyrightText: 2021 Bart De Vries <bart@mogwai.be>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick 2.14
import QtQuick.Controls 2.14 as Controls
import QtQuick.Layouts 1.14
import QtGraphicalEffects 1.15
import QtMultimedia 5.15
import org.kde.kirigami 2.15 as Kirigami
import org.kde.alligator 1.0
Kirigami.ScrollablePage {
Kirigami.PlaceholderMessage {
visible: errorList.count === 0
width: Kirigami.Units.gridUnit * 20
anchors.centerIn: parent
text: i18n("No errors logged")
}
Component {
id: errorListDelegate
Controls.Label {
text: error.string + error.date + error.string
}
}
ListView {
anchors.fill: parent
id: errorList
visible: count !== 0
model: ErrorLogModel
delegate: Kirigami.DelegateRecycler {
width: errorList.width
sourceComponent: errorListDelegate
}
}
actions.main: Kirigami.Action {
text: i18n("Clear all errors")
iconName: "edit-clear-all"
onTriggered: ErrorLogModel.clearAll()
}
}

View File

@ -14,6 +14,7 @@
<file alias="FooterBar.qml">qml/FooterBar.qml</file>
<file alias="QueuePage.qml">qml/QueuePage.qml</file>
<file alias="EpisodeListPage.qml">qml/EpisodeListPage.qml</file>
<file alias="ErrorListPage.qml">qml/ErrorListPage.qml</file>
<file alias="EpisodeSwipePage.qml">qml/EpisodeSwipePage.qml</file>
<file alias="DownloadSwipePage.qml">qml/DownloadSwipePage.qml</file>
<file alias="GenericListHeader.qml">qml/GenericListHeader.qml</file>