Refactor models
This commit is contained in:
parent
8a05a47e40
commit
8269cb960f
@ -4,6 +4,9 @@ set(alligator_SRCS
|
|||||||
entryListModel.cpp
|
entryListModel.cpp
|
||||||
fetcher.cpp
|
fetcher.cpp
|
||||||
database.cpp
|
database.cpp
|
||||||
|
entry.cpp
|
||||||
|
feed.cpp
|
||||||
|
author.cpp
|
||||||
resources.qrc
|
resources.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
48
src/author.cpp
Normal file
48
src/author.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2020 Tobias Fella <fella@posteo.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "author.h"
|
||||||
|
|
||||||
|
Author::Author(QString name, QString email, QString url, QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_name(name)
|
||||||
|
, m_email(email)
|
||||||
|
, m_url(url)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Author::~Author()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Author::name() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Author::email() const
|
||||||
|
{
|
||||||
|
return m_email;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Author::url() const
|
||||||
|
{
|
||||||
|
return m_url;
|
||||||
|
}
|
48
src/author.h
Normal file
48
src/author.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2020 Tobias Fella <fella@posteo.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AUTHOR_H
|
||||||
|
#define AUTHOR_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class Author : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QString name READ name CONSTANT)
|
||||||
|
Q_PROPERTY(QString email READ email CONSTANT)
|
||||||
|
Q_PROPERTY(QString url READ url CONSTANT)
|
||||||
|
|
||||||
|
public:
|
||||||
|
Author(QString name, QString email, QString url, QObject *parent = nullptr);
|
||||||
|
~Author();
|
||||||
|
|
||||||
|
QString name() const;
|
||||||
|
QString email() const;
|
||||||
|
QString url() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_name;
|
||||||
|
QString m_email;
|
||||||
|
QString m_url;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AUTHOR_H
|
@ -151,5 +151,7 @@ void Database::addFeed(QString url)
|
|||||||
query.bindValue(QStringLiteral(":image"), QLatin1String(""));
|
query.bindValue(QStringLiteral(":image"), QLatin1String(""));
|
||||||
execute(query);
|
execute(query);
|
||||||
|
|
||||||
Fetcher::instance().fetch(QUrl(url));
|
Q_EMIT feedAdded(url);
|
||||||
|
|
||||||
|
Fetcher::instance().fetch(url);
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,10 @@
|
|||||||
|
|
||||||
#include <QSqlQuery>
|
#include <QSqlQuery>
|
||||||
|
|
||||||
class Database
|
class Database : public QObject
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static Database &instance()
|
static Database &instance()
|
||||||
{
|
{
|
||||||
@ -32,7 +34,10 @@ public:
|
|||||||
}
|
}
|
||||||
bool execute(QSqlQuery &query);
|
bool execute(QSqlQuery &query);
|
||||||
bool execute(QString query);
|
bool execute(QString query);
|
||||||
void addFeed(QString url);
|
Q_INVOKABLE void addFeed(QString url);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void feedAdded(QString url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Database();
|
Database();
|
||||||
|
72
src/entry.cpp
Normal file
72
src/entry.cpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2020 Tobias Fella <fella@posteo.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "entry.h"
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
Entry::Entry(QString title, QString content, QVector<Author *> authors, QDateTime created, QDateTime updated, QString link, QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_title(title)
|
||||||
|
, m_content(content)
|
||||||
|
, m_authors(authors)
|
||||||
|
, m_created(created)
|
||||||
|
, m_updated(updated)
|
||||||
|
, m_link(link)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry::~Entry()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Entry::title() const
|
||||||
|
{
|
||||||
|
return m_title;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Entry::content() const
|
||||||
|
{
|
||||||
|
return m_content;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<Author *> Entry::authors() const
|
||||||
|
{
|
||||||
|
return m_authors;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime Entry::created() const
|
||||||
|
{
|
||||||
|
return m_created;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime Entry::updated() const
|
||||||
|
{
|
||||||
|
return m_updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Entry::link() const
|
||||||
|
{
|
||||||
|
return m_link;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Entry::baseUrl() const
|
||||||
|
{
|
||||||
|
return QUrl(m_link).adjusted(QUrl::RemovePath).toString();
|
||||||
|
}
|
67
src/entry.h
Normal file
67
src/entry.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2020 Tobias Fella <fella@posteo.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ENTRY_H
|
||||||
|
#define ENTRY_H
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include "author.h"
|
||||||
|
#include "feed.h"
|
||||||
|
|
||||||
|
class Entry : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QString title READ title CONSTANT)
|
||||||
|
Q_PROPERTY(QString content READ content CONSTANT)
|
||||||
|
Q_PROPERTY(QVector<Author *> authors READ authors CONSTANT)
|
||||||
|
Q_PROPERTY(QDateTime created READ created CONSTANT)
|
||||||
|
Q_PROPERTY(QDateTime updated READ updated CONSTANT)
|
||||||
|
Q_PROPERTY(QString link READ link CONSTANT)
|
||||||
|
Q_PROPERTY(QString baseUrl READ baseUrl CONSTANT)
|
||||||
|
|
||||||
|
public:
|
||||||
|
Entry(QString title, QString content, QVector<Author *> authors, QDateTime created, QDateTime updated, QString link, QObject *parent = nullptr);
|
||||||
|
~Entry();
|
||||||
|
|
||||||
|
QString title() const;
|
||||||
|
QString content() const;
|
||||||
|
QVector<Author *> authors() const;
|
||||||
|
QDateTime created() const;
|
||||||
|
QDateTime updated() const;
|
||||||
|
QString link() const;
|
||||||
|
QString baseUrl() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Feed *m_feed;
|
||||||
|
QString m_title;
|
||||||
|
QString m_content;
|
||||||
|
QVector<Author *> m_authors;
|
||||||
|
QDateTime m_created;
|
||||||
|
QDateTime m_updated;
|
||||||
|
QString m_link;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ENTRY_H
|
@ -18,8 +18,8 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QAbstractListModel>
|
||||||
#include <QSqlQuery>
|
#include <QVariant>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
@ -27,84 +27,90 @@
|
|||||||
#include "fetcher.h"
|
#include "fetcher.h"
|
||||||
|
|
||||||
EntryListModel::EntryListModel(QObject *parent)
|
EntryListModel::EntryListModel(QObject *parent)
|
||||||
: QSqlTableModel(parent)
|
: QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
setTable(QStringLiteral("entries"));
|
connect(&Fetcher::instance(), &Fetcher::feedUpdated, this, [this](QString url) {
|
||||||
setSort(Updated, Qt::DescendingOrder);
|
if (m_feed->url() == url) {
|
||||||
setEditStrategy(OnFieldChange);
|
beginResetModel();
|
||||||
select();
|
for (auto &entry : m_entries) {
|
||||||
|
delete entry;
|
||||||
connect(&Fetcher::instance(), &Fetcher::updated, this, [this]() { select(); });
|
}
|
||||||
|
m_entries.clear();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
connect(&Fetcher::instance(), &Fetcher::feedDetailsUpdated, this, [this](QString url, QString name, QString image) {
|
||||||
|
if (m_feed->url() == url) {
|
||||||
|
m_feed->setName(name);
|
||||||
|
m_feed->setImage(image);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant EntryListModel::data(const QModelIndex &index, int role) const
|
QVariant EntryListModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (role == Enclosure) {
|
if (role != 0)
|
||||||
return enclosure(data(index, Id).toString());
|
return QVariant();
|
||||||
}
|
if (m_entries[index.row()] == nullptr)
|
||||||
if (role == Authors) {
|
loadEntry(index.row());
|
||||||
QSqlQuery query;
|
return QVariant::fromValue(m_entries[index.row()]);
|
||||||
query.prepare(QStringLiteral("SELECT name FROM Authors WHERE id=:id"));
|
|
||||||
query.bindValue(QStringLiteral(":id"), data(index, Id));
|
|
||||||
Database::instance().execute(query);
|
|
||||||
QStringList authors;
|
|
||||||
while (query.next()) {
|
|
||||||
authors += query.value(0).toString();
|
|
||||||
}
|
|
||||||
return authors;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (role == Updated || role == Created) {
|
|
||||||
QDateTime updated;
|
|
||||||
updated.setSecsSinceEpoch(QSqlTableModel::data(createIndex(index.row(), role), 0).toInt());
|
|
||||||
return updated;
|
|
||||||
}
|
|
||||||
return QSqlTableModel::data(createIndex(index.row(), role), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString EntryListModel::enclosure(QString id) const
|
|
||||||
{
|
|
||||||
QSqlQuery query;
|
|
||||||
query.prepare(QStringLiteral("SELECT url from Enclosures WHERE id=:id;"));
|
|
||||||
query.bindValue(QStringLiteral(":id"), id);
|
|
||||||
Database::instance().execute(query);
|
|
||||||
return query.next() ? query.value(0).toString() : QLatin1String("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray> EntryListModel::roleNames() const
|
QHash<int, QByteArray> EntryListModel::roleNames() const
|
||||||
{
|
{
|
||||||
QHash<int, QByteArray> roleNames;
|
QHash<int, QByteArray> roleNames;
|
||||||
roleNames[Feed] = "feed";
|
roleNames[0] = "entry";
|
||||||
roleNames[Id] = "id";
|
|
||||||
roleNames[Title] = "title";
|
|
||||||
roleNames[Content] = "content";
|
|
||||||
roleNames[Created] = "created";
|
|
||||||
roleNames[Updated] = "updated";
|
|
||||||
roleNames[Link] = "link";
|
|
||||||
roleNames[Authors] = "authors";
|
|
||||||
roleNames[Enclosure] = "enclosure";
|
|
||||||
return roleNames;
|
return roleNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntryListModel::setFeed(QString url)
|
int EntryListModel::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
m_feed = url;
|
Q_UNUSED(parent)
|
||||||
setFilter(QStringLiteral("feed ='%1'").arg(url));
|
QSqlQuery query;
|
||||||
select();
|
query.prepare(QStringLiteral("SELECT COUNT() FROM Entries WHERE feed=:feed;"));
|
||||||
emit feedChanged(url);
|
query.bindValue(QStringLiteral(":feed"), m_feed->url());
|
||||||
|
Database::instance().execute(query);
|
||||||
|
if (!query.next())
|
||||||
|
qWarning() << "Failed to query feed count";
|
||||||
|
return query.value(0).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EntryListModel::feed() const
|
void EntryListModel::loadEntry(int index) const
|
||||||
|
{
|
||||||
|
QSqlQuery entryQuery;
|
||||||
|
entryQuery.prepare(QStringLiteral("SELECT * FROM Entries WHERE feed=:feed ORDER BY updated DESC LIMIT 1 OFFSET :index;"));
|
||||||
|
entryQuery.bindValue(QStringLiteral(":feed"), m_feed->url());
|
||||||
|
entryQuery.bindValue(QStringLiteral(":index"), index);
|
||||||
|
Database::instance().execute(entryQuery);
|
||||||
|
if (!entryQuery.next())
|
||||||
|
qWarning() << "No element with index" << index << "found in feed" << m_feed->url();
|
||||||
|
|
||||||
|
QSqlQuery authorQuery;
|
||||||
|
authorQuery.prepare(QStringLiteral("SELECT * FROM Authors WHERE id=:id"));
|
||||||
|
authorQuery.bindValue(QStringLiteral(":id"), entryQuery.value(QStringLiteral("id")).toString());
|
||||||
|
Database::instance().execute(authorQuery);
|
||||||
|
QVector<Author *> authors;
|
||||||
|
while (authorQuery.next()) {
|
||||||
|
authors += new Author(authorQuery.value(QStringLiteral("name")).toString(), authorQuery.value(QStringLiteral("email")).toString(), authorQuery.value(QStringLiteral("uri")).toString(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime created;
|
||||||
|
created.setSecsSinceEpoch(entryQuery.value(QStringLiteral("created")).toInt());
|
||||||
|
|
||||||
|
QDateTime updated;
|
||||||
|
updated.setSecsSinceEpoch(entryQuery.value(QStringLiteral("updated")).toInt());
|
||||||
|
|
||||||
|
Entry *entry = new Entry(entryQuery.value(QStringLiteral("title")).toString(), entryQuery.value(QStringLiteral("content")).toString(), authors, created, updated, entryQuery.value(QStringLiteral("link")).toString(), nullptr);
|
||||||
|
m_entries[index] = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
Feed *EntryListModel::feed() const
|
||||||
{
|
{
|
||||||
return m_feed;
|
return m_feed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntryListModel::fetch()
|
void EntryListModel::setFeed(Feed *feed)
|
||||||
{
|
{
|
||||||
Fetcher::instance().fetch(QUrl(m_feed));
|
m_feed = feed;
|
||||||
}
|
emit feedChanged(feed);
|
||||||
|
|
||||||
QString EntryListModel::baseUrl(QString url)
|
|
||||||
{
|
|
||||||
return QUrl(url).adjusted(QUrl::RemovePath).toString();
|
|
||||||
}
|
}
|
||||||
|
@ -20,41 +20,35 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QHash>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QSqlTableModel>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
class EntryListModel : public QSqlTableModel
|
#include "entry.h"
|
||||||
|
|
||||||
|
class EntryListModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QString feed READ feed WRITE setFeed NOTIFY feedChanged)
|
|
||||||
|
Q_PROPERTY(Feed *feed READ feed WRITE setFeed NOTIFY feedChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum DataRole {
|
|
||||||
Feed = 0,
|
|
||||||
Id,
|
|
||||||
Title,
|
|
||||||
Content,
|
|
||||||
Created,
|
|
||||||
Updated,
|
|
||||||
Link,
|
|
||||||
Authors,
|
|
||||||
Enclosure,
|
|
||||||
};
|
|
||||||
explicit EntryListModel(QObject *parent = nullptr);
|
explicit EntryListModel(QObject *parent = nullptr);
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
|
|
||||||
Q_INVOKABLE void fetch();
|
Feed *feed() const;
|
||||||
Q_INVOKABLE QString baseUrl(QString url);
|
|
||||||
|
|
||||||
QString feed() const;
|
void setFeed(Feed *feed);
|
||||||
void setFeed(QString feed);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void feedChanged(QString feed);
|
void feedChanged(Feed *feed);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_feed;
|
void loadEntry(int index) const;
|
||||||
|
|
||||||
QString enclosure(QString id) const;
|
Feed *m_feed;
|
||||||
|
mutable QHash<int, Entry *> m_entries;
|
||||||
};
|
};
|
||||||
|
84
src/feed.cpp
Normal file
84
src/feed.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Tobias Fella <fella@posteo.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
#include "database.h"
|
||||||
|
#include "feed.h"
|
||||||
|
|
||||||
|
Feed::Feed(QString url, QString name, QString image, QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_url(url)
|
||||||
|
, m_name(name)
|
||||||
|
, m_image(image)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Feed::~Feed()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Feed::url() const
|
||||||
|
{
|
||||||
|
return m_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Feed::name() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Feed::image() const
|
||||||
|
{
|
||||||
|
return m_image;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Feed::setName(QString name)
|
||||||
|
{
|
||||||
|
m_name = name;
|
||||||
|
emit nameChanged(m_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Feed::setImage(QString image)
|
||||||
|
{
|
||||||
|
m_image = image;
|
||||||
|
emit imageChanged(m_image);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Feed::remove()
|
||||||
|
{
|
||||||
|
// Delete Authors
|
||||||
|
QSqlQuery query;
|
||||||
|
query.prepare(QStringLiteral("DELETE FROM Authors WHERE feed=:feed;"));
|
||||||
|
query.bindValue(QStringLiteral(":feed"), m_url);
|
||||||
|
Database::instance().execute(query);
|
||||||
|
|
||||||
|
// Delete Entries
|
||||||
|
query.prepare(QStringLiteral("DELETE FROM Entries WHERE feed=:feed;"));
|
||||||
|
query.bindValue(QStringLiteral(":feed"), m_url);
|
||||||
|
Database::instance().execute(query);
|
||||||
|
|
||||||
|
// TODO Delete Enclosures
|
||||||
|
|
||||||
|
// Delete Feed
|
||||||
|
query.prepare(QStringLiteral("DELETE FROM Feeds WHERE url=:url;"));
|
||||||
|
query.bindValue(QStringLiteral(":url"), m_url);
|
||||||
|
Database::instance().execute(query);
|
||||||
|
}
|
58
src/feed.h
Normal file
58
src/feed.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Tobias Fella <fella@posteo.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License or (at your option) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FEED_H
|
||||||
|
#define FEED_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class Feed : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QString url READ url CONSTANT)
|
||||||
|
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
||||||
|
Q_PROPERTY(QString image READ image WRITE setImage NOTIFY imageChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
Feed(QString url, QString name, QString image, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
~Feed();
|
||||||
|
|
||||||
|
QString url() const;
|
||||||
|
QString name() const;
|
||||||
|
QString image() const;
|
||||||
|
|
||||||
|
void setName(QString name);
|
||||||
|
void setImage(QString image);
|
||||||
|
|
||||||
|
void remove();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void nameChanged(QString &name);
|
||||||
|
void imageChanged(QString &image);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_url;
|
||||||
|
QString m_name;
|
||||||
|
QString m_image;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FEED_H
|
@ -20,62 +20,78 @@
|
|||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QModelIndex>
|
#include <QModelIndex>
|
||||||
#include <QSqlRecord>
|
#include <QSqlQuery>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
#include "feedListModel.h"
|
#include "feedListModel.h"
|
||||||
#include "fetcher.h"
|
#include "fetcher.h"
|
||||||
|
|
||||||
FeedListModel::FeedListModel(QObject *parent)
|
FeedListModel::FeedListModel(QObject *parent)
|
||||||
: QSqlTableModel(parent)
|
: QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
setTable(QStringLiteral("Feeds"));
|
connect(&Database::instance(), &Database::feedAdded, this, [this]() {
|
||||||
setSort(0, Qt::AscendingOrder);
|
beginInsertRows(QModelIndex(), rowCount(QModelIndex()) - 1, rowCount(QModelIndex()) - 1);
|
||||||
setEditStrategy(OnFieldChange);
|
endInsertRows();
|
||||||
select();
|
});
|
||||||
|
connect(&Fetcher::instance(), &Fetcher::feedDetailsUpdated, this, [this](QString url, QString name, QString image) {
|
||||||
connect(&Fetcher::instance(), &Fetcher::updated, this, [this]() { select(); });
|
for (int i = rowCount(QModelIndex()) - 1; i >= 0; i--) {
|
||||||
|
if (m_feeds[i]->url() == url) {
|
||||||
|
m_feeds[i]->setName(name);
|
||||||
|
m_feeds[i]->setImage(image);
|
||||||
|
Q_EMIT dataChanged(createIndex(i, 0), createIndex(i, 0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray> FeedListModel::roleNames() const
|
QHash<int, QByteArray> FeedListModel::roleNames() const
|
||||||
{
|
{
|
||||||
QHash<int, QByteArray> roleNames;
|
QHash<int, QByteArray> roleNames;
|
||||||
roleNames[Name] = "name";
|
roleNames[0] = "feed";
|
||||||
roleNames[Url] = "url";
|
|
||||||
roleNames[Image] = "image";
|
|
||||||
return roleNames;
|
return roleNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedListModel::addFeed(QString url)
|
int FeedListModel::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
Database::instance().addFeed(url);
|
Q_UNUSED(parent)
|
||||||
|
QSqlQuery query;
|
||||||
|
query.prepare(QStringLiteral("SELECT COUNT() FROM Feeds;"));
|
||||||
|
Database::instance().execute(query);
|
||||||
|
if (!query.next())
|
||||||
|
qWarning() << "Failed to query feed count";
|
||||||
|
return query.value(0).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant FeedListModel::data(const QModelIndex &index, int role) const
|
QVariant FeedListModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
return QSqlTableModel::data(createIndex(index.row(), role), 0);
|
if (role != 0)
|
||||||
|
return QVariant();
|
||||||
|
if (m_feeds[index.row()] == nullptr)
|
||||||
|
loadFeed(index.row());
|
||||||
|
return QVariant::fromValue(m_feeds[index.row()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FeedListModel::loadFeed(int index) const
|
||||||
|
{
|
||||||
|
QSqlQuery query;
|
||||||
|
query.prepare(QStringLiteral("SELECT * FROM Feeds LIMIT 1 OFFSET :index;"));
|
||||||
|
query.bindValue(QStringLiteral(":index"), index);
|
||||||
|
Database::instance().execute(query);
|
||||||
|
if (!query.next())
|
||||||
|
qWarning() << "Failed to lod feed" << index;
|
||||||
|
Feed *feed = new Feed(query.value(QStringLiteral("url")).toString(), query.value(QStringLiteral("name")).toString(), query.value(QStringLiteral("image")).toString(), nullptr);
|
||||||
|
m_feeds[index] = feed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedListModel::removeFeed(int index)
|
void FeedListModel::removeFeed(int index)
|
||||||
{
|
{
|
||||||
Fetcher::instance().removeImage(data(createIndex(index, 0), Image).toString());
|
Feed *feed = m_feeds[index];
|
||||||
QSqlQuery query;
|
beginRemoveRows(QModelIndex(), index, index);
|
||||||
query.prepare(QStringLiteral("DELETE FROM Authors WHERE feed=:feed;"));
|
m_feeds[index] = nullptr;
|
||||||
query.bindValue(QStringLiteral(":feed"), data(createIndex(index, 0), 1).toString());
|
endRemoveRows();
|
||||||
Database::instance().execute(query);
|
feed->remove();
|
||||||
|
delete feed;
|
||||||
query.prepare(QStringLiteral("DELETE FROM Entries WHERE feed=:feed;"));
|
|
||||||
query.bindValue(QStringLiteral(":feed"), data(createIndex(index, 0), 1).toString());
|
|
||||||
Database::instance().execute(query);
|
|
||||||
|
|
||||||
query.prepare(QStringLiteral("DELETE FROM Enclosures WHERE feed=:feed;"));
|
|
||||||
query.bindValue(QStringLiteral(":feed"), data(createIndex(index, 0), 1).toString());
|
|
||||||
Database::instance().execute(query);
|
|
||||||
|
|
||||||
// Workaround...
|
|
||||||
query.prepare(QStringLiteral("DELETE FROM Feeds WHERE url=:url;"));
|
|
||||||
query.bindValue(QStringLiteral(":url"), data(createIndex(index, 0), 1).toString());
|
|
||||||
Database::instance().execute(query);
|
|
||||||
select();
|
|
||||||
}
|
}
|
||||||
|
@ -20,27 +20,26 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QHash>
|
||||||
#include <QSqlTableModel>
|
#include <QSqlTableModel>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QVector>
|
|
||||||
|
|
||||||
//#include "feed.h"
|
#include "feed.h"
|
||||||
#include "fetcher.h"
|
|
||||||
|
|
||||||
class FeedListModel : public QSqlTableModel
|
class FeedListModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum DataRole {
|
|
||||||
Name = 0,
|
|
||||||
Url,
|
|
||||||
Image,
|
|
||||||
};
|
|
||||||
explicit FeedListModel(QObject *parent = nullptr);
|
explicit FeedListModel(QObject *parent = nullptr);
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
Q_INVOKABLE void addFeed(QString url);
|
|
||||||
Q_INVOKABLE void removeFeed(int index);
|
Q_INVOKABLE void removeFeed(int index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void loadFeed(int index) const;
|
||||||
|
|
||||||
|
mutable QHash<int, Feed *> m_feeds;
|
||||||
};
|
};
|
||||||
|
@ -38,27 +38,24 @@ Fetcher::Fetcher()
|
|||||||
manager->enableStrictTransportSecurityStore(true);
|
manager->enableStrictTransportSecurityStore(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fetcher::fetch(QUrl url)
|
void Fetcher::fetch(QString url)
|
||||||
{
|
{
|
||||||
qDebug() << "Starting to fetch" << url.toString();
|
qDebug() << "Starting to fetch" << url;
|
||||||
|
|
||||||
emit updated();
|
QNetworkRequest request((QUrl(url)));
|
||||||
|
|
||||||
QNetworkRequest request(url);
|
|
||||||
QNetworkReply *reply = manager->get(request);
|
QNetworkReply *reply = manager->get(request);
|
||||||
connect(reply, &QNetworkReply::finished, this, [this, url, reply]() {
|
connect(reply, &QNetworkReply::finished, this, [this, url, reply]() {
|
||||||
QByteArray data = reply->readAll();
|
QByteArray data = reply->readAll();
|
||||||
Syndication::DocumentSource *document = new Syndication::DocumentSource(data, url.toString());
|
Syndication::DocumentSource *document = new Syndication::DocumentSource(data, url);
|
||||||
Syndication::FeedPtr feed = Syndication::parserCollection()->parse(*document, QStringLiteral("Atom"));
|
Syndication::FeedPtr feed = Syndication::parserCollection()->parse(*document, QStringLiteral("Atom"));
|
||||||
|
|
||||||
processFeed(feed, url);
|
processFeed(feed, url);
|
||||||
|
|
||||||
emit updated();
|
|
||||||
delete reply;
|
delete reply;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fetcher::processFeed(Syndication::FeedPtr feed, QUrl url)
|
void Fetcher::processFeed(Syndication::FeedPtr feed, QString url)
|
||||||
{
|
{
|
||||||
if (feed.isNull())
|
if (feed.isNull())
|
||||||
return;
|
return;
|
||||||
@ -67,20 +64,25 @@ void Fetcher::processFeed(Syndication::FeedPtr feed, QUrl url)
|
|||||||
query.prepare(QStringLiteral("UPDATE Feeds SET name=:name, image=:image WHERE url=:url;"));
|
query.prepare(QStringLiteral("UPDATE Feeds SET name=:name, image=:image WHERE url=:url;"));
|
||||||
query.bindValue(QStringLiteral(":name"), feed->title());
|
query.bindValue(QStringLiteral(":name"), feed->title());
|
||||||
query.bindValue(QStringLiteral(":url"), url);
|
query.bindValue(QStringLiteral(":url"), url);
|
||||||
if (feed->image()->url().startsWith(QStringLiteral("/"))) {
|
QString image;
|
||||||
QString absolute = url.adjusted(QUrl::RemovePath).toString() + feed->image()->url();
|
if (feed->image()->url().startsWith(QStringLiteral("/")))
|
||||||
query.bindValue(QStringLiteral(":image"), absolute);
|
image = QUrl(url).adjusted(QUrl::RemovePath).toString() + feed->image()->url();
|
||||||
} else
|
else
|
||||||
query.bindValue(QStringLiteral(":image"), feed->image()->url());
|
image = feed->image()->url();
|
||||||
|
query.bindValue(QStringLiteral(":image"), image);
|
||||||
Database::instance().execute(query);
|
Database::instance().execute(query);
|
||||||
qDebug() << "Updated feed title:" << feed->title();
|
qDebug() << "Updated feed title:" << feed->title();
|
||||||
|
|
||||||
|
Q_EMIT feedDetailsUpdated(url, feed->title(), image);
|
||||||
|
|
||||||
for (const auto &entry : feed->items()) {
|
for (const auto &entry : feed->items()) {
|
||||||
processEntry(entry, url);
|
processEntry(entry, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Q_EMIT feedUpdated(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fetcher::processEntry(Syndication::ItemPtr entry, QUrl url)
|
void Fetcher::processEntry(Syndication::ItemPtr entry, QString url)
|
||||||
{
|
{
|
||||||
qDebug() << "Processing" << entry->title();
|
qDebug() << "Processing" << entry->title();
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
@ -116,11 +118,11 @@ void Fetcher::processEntry(Syndication::ItemPtr entry, QUrl url)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fetcher::processAuthor(Syndication::PersonPtr author, Syndication::ItemPtr entry, QUrl url)
|
void Fetcher::processAuthor(Syndication::PersonPtr author, Syndication::ItemPtr entry, QString url)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare(QStringLiteral("INSERT INTO Authors VALUES(:feed, :id, :name, :uri, :email);"));
|
query.prepare(QStringLiteral("INSERT INTO Authors VALUES(:feed, :id, :name, :uri, :email);"));
|
||||||
query.bindValue(QStringLiteral(":feed"), url.toString());
|
query.bindValue(QStringLiteral(":feed"), url);
|
||||||
query.bindValue(QStringLiteral(":id"), entry->id());
|
query.bindValue(QStringLiteral(":id"), entry->id());
|
||||||
query.bindValue(QStringLiteral(":name"), author->name());
|
query.bindValue(QStringLiteral(":name"), author->name());
|
||||||
query.bindValue(QStringLiteral(":uri"), author->uri());
|
query.bindValue(QStringLiteral(":uri"), author->uri());
|
||||||
@ -128,11 +130,11 @@ void Fetcher::processAuthor(Syndication::PersonPtr author, Syndication::ItemPtr
|
|||||||
Database::instance().execute(query);
|
Database::instance().execute(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fetcher::processEnclosure(Syndication::EnclosurePtr enclosure, Syndication::ItemPtr entry, QUrl feedUrl)
|
void Fetcher::processEnclosure(Syndication::EnclosurePtr enclosure, Syndication::ItemPtr entry, QString feedUrl)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare(QStringLiteral("INSERT INTO Enclosures VALUES (:feed, :id, :duration, :size, :title, :type, :url);"));
|
query.prepare(QStringLiteral("INSERT INTO Enclosures VALUES (:feed, :id, :duration, :size, :title, :type, :url);"));
|
||||||
query.bindValue(QStringLiteral(":feed"), feedUrl.toString());
|
query.bindValue(QStringLiteral(":feed"), feedUrl);
|
||||||
query.bindValue(QStringLiteral(":id"), entry->id());
|
query.bindValue(QStringLiteral(":id"), entry->id());
|
||||||
query.bindValue(QStringLiteral(":duration"), enclosure->duration());
|
query.bindValue(QStringLiteral(":duration"), enclosure->duration());
|
||||||
query.bindValue(QStringLiteral(":size"), enclosure->length());
|
query.bindValue(QStringLiteral(":size"), enclosure->length());
|
||||||
@ -165,7 +167,6 @@ void Fetcher::download(QString url)
|
|||||||
file.write(data);
|
file.write(data);
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
emit updated();
|
|
||||||
delete reply;
|
delete reply;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -34,23 +34,23 @@ public:
|
|||||||
static Fetcher _instance;
|
static Fetcher _instance;
|
||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
void fetch(QUrl);
|
Q_INVOKABLE void fetch(QString url);
|
||||||
Q_INVOKABLE QString image(QString);
|
Q_INVOKABLE QString image(QString);
|
||||||
void removeImage(QString);
|
void removeImage(QString);
|
||||||
Q_INVOKABLE void download(QString url);
|
Q_INVOKABLE void download(QString url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Fetcher();
|
Fetcher();
|
||||||
Fetcher(const Fetcher &);
|
|
||||||
|
|
||||||
QString filePath(QString);
|
QString filePath(QString);
|
||||||
void processFeed(Syndication::FeedPtr feed, QUrl url);
|
void processFeed(Syndication::FeedPtr feed, QString url);
|
||||||
void processEntry(Syndication::ItemPtr entry, QUrl url);
|
void processEntry(Syndication::ItemPtr entry, QString url);
|
||||||
void processAuthor(Syndication::PersonPtr author, Syndication::ItemPtr entry, QUrl url);
|
void processAuthor(Syndication::PersonPtr author, Syndication::ItemPtr entry, QString url);
|
||||||
void processEnclosure(Syndication::EnclosurePtr enclosure, Syndication::ItemPtr entry, QUrl feedUrl);
|
void processEnclosure(Syndication::EnclosurePtr enclosure, Syndication::ItemPtr entry, QString feedUrl);
|
||||||
|
|
||||||
QNetworkAccessManager *manager;
|
QNetworkAccessManager *manager;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void updated();
|
void feedUpdated(QString url);
|
||||||
|
void feedDetailsUpdated(QString url, QString name, QString image);
|
||||||
};
|
};
|
||||||
|
@ -61,6 +61,10 @@ int main(int argc, char *argv[])
|
|||||||
engine->setObjectOwnership(&Fetcher::instance(), QQmlEngine::CppOwnership);
|
engine->setObjectOwnership(&Fetcher::instance(), QQmlEngine::CppOwnership);
|
||||||
return &Fetcher::instance();
|
return &Fetcher::instance();
|
||||||
});
|
});
|
||||||
|
qmlRegisterSingletonType<Database>("org.kde.alligator", 1, 0, "Database", [](QQmlEngine *engine, QJSEngine *) -> QObject * {
|
||||||
|
engine->setObjectOwnership(&Database::instance(), QQmlEngine::CppOwnership);
|
||||||
|
return &Database::instance();
|
||||||
|
});
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
|
engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
|
||||||
|
@ -29,13 +29,11 @@ import org.kde.alligator 1.0
|
|||||||
Kirigami.ScrollablePage {
|
Kirigami.ScrollablePage {
|
||||||
id: page
|
id: page
|
||||||
|
|
||||||
property var name
|
property var feed
|
||||||
property var url
|
|
||||||
property var image
|
|
||||||
|
|
||||||
title: name
|
title: feed.title
|
||||||
|
|
||||||
property var all: page.url === "all"
|
//property bool all: feed
|
||||||
|
|
||||||
contextualActions: [
|
contextualActions: [
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
@ -48,11 +46,7 @@ Kirigami.ScrollablePage {
|
|||||||
actions.main: Kirigami.Action {
|
actions.main: Kirigami.Action {
|
||||||
iconName: "view-refresh"
|
iconName: "view-refresh"
|
||||||
text: i18n("Refresh Feed")
|
text: i18n("Refresh Feed")
|
||||||
onTriggered: entryListModel.fetch()
|
onTriggered: Fetcher.fetch(page.feed.url)
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
entryListModel.fetch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Kirigami.PlaceholderMessage {
|
Kirigami.PlaceholderMessage {
|
||||||
@ -69,7 +63,7 @@ Kirigami.ScrollablePage {
|
|||||||
visible: count !== 0
|
visible: count !== 0
|
||||||
model: EntryListModel {
|
model: EntryListModel {
|
||||||
id: entryListModel
|
id: entryListModel
|
||||||
feed: page.url
|
feed: page.feed
|
||||||
}
|
}
|
||||||
|
|
||||||
header: RowLayout {
|
header: RowLayout {
|
||||||
@ -77,13 +71,12 @@ Kirigami.ScrollablePage {
|
|||||||
height: root.height * 0.2
|
height: root.height * 0.2
|
||||||
visible: !all
|
visible: !all
|
||||||
Kirigami.Icon {
|
Kirigami.Icon {
|
||||||
source: Fetcher.image(page.image)
|
source: Fetcher.image(page.feed.image)
|
||||||
width: height
|
width: height
|
||||||
height: parent.height
|
height: parent.height
|
||||||
Component.onCompleted: console.log("Height: " + page.height)
|
|
||||||
}
|
}
|
||||||
Kirigami.Heading {
|
Kirigami.Heading {
|
||||||
text: page.name
|
text: page.feed.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,14 +86,14 @@ Kirigami.ScrollablePage {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
Controls.Label {
|
Controls.Label {
|
||||||
text: model.title
|
text: model.entry.title
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
opacity: 1
|
opacity: 1
|
||||||
}
|
}
|
||||||
Controls.Label {
|
Controls.Label {
|
||||||
id: subtitleItem
|
id: subtitleItem
|
||||||
text: model.updated.toLocaleString(Qt.locale(), Locale.ShortFormat) + (model.authors.length === 0 ? "" : " " + i18nc("by <author(s)>", "by") + " " + model.authors.join(", "))
|
text: model.entry.updated.toLocaleString(Qt.locale(), Locale.ShortFormat) + (model.entry.authors.length === 0 ? "" : " " + i18nc("by <author(s)>", "by") + " " + model.entry.authors[0].name)
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
font: Kirigami.Theme.smallFont
|
font: Kirigami.Theme.smallFont
|
||||||
@ -110,8 +103,7 @@ Kirigami.ScrollablePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
model.read = true;
|
pageStack.push("qrc:/EntryPage.qml", {"entry": model.entry})
|
||||||
pageStack.push("qrc:/EntryPage.qml", {"data": model, "baseUrl": entryListModel.baseUrl(model.link)})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,15 +28,16 @@ import org.kde.alligator 1.0
|
|||||||
|
|
||||||
Kirigami.ScrollablePage {
|
Kirigami.ScrollablePage {
|
||||||
id: page
|
id: page
|
||||||
property QtObject data
|
|
||||||
property alias baseUrl: label.baseUrl
|
|
||||||
|
|
||||||
title: data.title
|
property QtObject entry
|
||||||
|
|
||||||
|
title: entry.title
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Controls.Label {
|
Controls.Label {
|
||||||
id: label
|
id: label
|
||||||
text: page.data.content
|
baseUrl: page.entry.baseUrl
|
||||||
|
text: page.entry.content
|
||||||
textFormat: Text.RichText
|
textFormat: Text.RichText
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
@ -58,7 +58,7 @@ Kirigami.ScrollablePage {
|
|||||||
text: i18n("Add Feed")
|
text: i18n("Add Feed")
|
||||||
enabled: urlField.text
|
enabled: urlField.text
|
||||||
onClicked: {
|
onClicked: {
|
||||||
feedListModel.addFeed(urlField.text)
|
Database.addFeed(urlField.text)
|
||||||
addSheet.close()
|
addSheet.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,6 +82,7 @@ Kirigami.ScrollablePage {
|
|||||||
id: feedListModel
|
id: feedListModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
header:
|
header:
|
||||||
Kirigami.AbstractListItem {
|
Kirigami.AbstractListItem {
|
||||||
Controls.Label {
|
Controls.Label {
|
||||||
@ -95,6 +96,7 @@ Kirigami.ScrollablePage {
|
|||||||
pageStack.push("qrc:/EntryListPage.qml")
|
pageStack.push("qrc:/EntryListPage.qml")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
delegate: Kirigami.SwipeListItem {
|
delegate: Kirigami.SwipeListItem {
|
||||||
height: Kirigami.Units.gridUnit*2
|
height: Kirigami.Units.gridUnit*2
|
||||||
@ -102,13 +104,13 @@ Kirigami.ScrollablePage {
|
|||||||
Item {
|
Item {
|
||||||
Kirigami.Icon {
|
Kirigami.Icon {
|
||||||
id: icon
|
id: icon
|
||||||
source: Fetcher.image(model.image)
|
source: Fetcher.image(model.feed.image)
|
||||||
width: height
|
width: height
|
||||||
height: parent.height
|
height: parent.height
|
||||||
}
|
}
|
||||||
|
|
||||||
Controls.Label {
|
Controls.Label {
|
||||||
text: model.name
|
text: model.feed.name
|
||||||
height: parent.height
|
height: parent.height
|
||||||
anchors.left: icon.right
|
anchors.left: icon.right
|
||||||
leftPadding: 0.5*Kirigami.Units.gridUnit
|
leftPadding: 0.5*Kirigami.Units.gridUnit
|
||||||
@ -119,7 +121,7 @@ Kirigami.ScrollablePage {
|
|||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
icon.name: "delete"
|
icon.name: "delete"
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if(pageStack.depth > 1 && model.url === lastFeed)
|
if(pageStack.depth > 1 && model.feed.url === lastFeed)
|
||||||
pageStack.pop()
|
pageStack.pop()
|
||||||
feedListModel.removeFeed(index)
|
feedListModel.removeFeed(index)
|
||||||
}
|
}
|
||||||
@ -128,8 +130,8 @@ Kirigami.ScrollablePage {
|
|||||||
]
|
]
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
lastFeed = model.url
|
lastFeed = model.feed.url
|
||||||
pageStack.push("qrc:/EntryListPage.qml", {"name": name, "url": url, "image": image})
|
pageStack.push("qrc:/EntryListPage.qml", {"feed": model.feed})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user