mirror of https://github.com/KDE/kasts.git
port models to QSqlTableModel
This commit is contained in:
parent
ff7c03a32c
commit
eb8d24e28a
|
@ -3,8 +3,6 @@ set(alligator_SRCS
|
||||||
feedListModel.cpp
|
feedListModel.cpp
|
||||||
entryListModel.cpp
|
entryListModel.cpp
|
||||||
fetcher.cpp
|
fetcher.cpp
|
||||||
feed.cpp
|
|
||||||
entry.cpp
|
|
||||||
database.cpp
|
database.cpp
|
||||||
resources.qrc
|
resources.qrc
|
||||||
)
|
)
|
||||||
|
|
|
@ -46,12 +46,12 @@ Database::Database()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Database::migrate() {
|
bool Database::migrate() {
|
||||||
qDebug() << "Migrating database";
|
|
||||||
if(version() < 1) TRUE_OR_RETURN(migrateTo1());
|
if(version() < 1) TRUE_OR_RETURN(migrateTo1());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Database::migrateTo1() {
|
bool Database::migrateTo1() {
|
||||||
|
qDebug() << "Migrating database to version 1";
|
||||||
QSqlQuery query(QSqlDatabase::database());
|
QSqlQuery query(QSqlDatabase::database());
|
||||||
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Feeds (name TEXT, url TEXT, image TEXT);")));
|
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Feeds (name TEXT, url TEXT, image TEXT);")));
|
||||||
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Entries (feed TEXT, id TEXT UNIQUE, title TEXT, content TEXT, created INTEGER, updated INTEGER);")));
|
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Entries (feed TEXT, id TEXT UNIQUE, title TEXT, content TEXT, created INTEGER, updated INTEGER);")));
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
/**
|
|
||||||
* 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"
|
|
||||||
|
|
||||||
Entry::Entry(const QString title, const QString content, const int updated, const bool bookmark, const bool read)
|
|
||||||
: m_title(title)
|
|
||||||
, m_content(content)
|
|
||||||
, m_updated(updated)
|
|
||||||
, m_bookmark(bookmark)
|
|
||||||
, m_read(read)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Entry::Entry(const Entry &other)
|
|
||||||
: m_title(other.title())
|
|
||||||
, m_content(other.content())
|
|
||||||
, m_updated(other.updated())
|
|
||||||
, m_bookmark(other.isBookmark())
|
|
||||||
, m_read(other.isRead())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Entry::isRead() const
|
|
||||||
{
|
|
||||||
return m_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Entry::isBookmark() const
|
|
||||||
{
|
|
||||||
return m_bookmark;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Entry::title() const
|
|
||||||
{
|
|
||||||
return m_title;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Entry::content() const
|
|
||||||
{
|
|
||||||
return m_content;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Entry::updated() const
|
|
||||||
{
|
|
||||||
return m_updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Entry::setRead(bool read)
|
|
||||||
{
|
|
||||||
m_read = read;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Entry::setBookmark(bool bookmark)
|
|
||||||
{
|
|
||||||
m_bookmark = bookmark;
|
|
||||||
}
|
|
46
src/entry.h
46
src/entry.h
|
@ -1,46 +0,0 @@
|
||||||
/**
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
class Entry
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Entry(const Entry &);
|
|
||||||
Entry(const QString title, const QString content, const int updated, const bool bookmark, const bool read);
|
|
||||||
|
|
||||||
QString title() const;
|
|
||||||
QString content() const;
|
|
||||||
int updated() const;
|
|
||||||
bool isBookmark() const;
|
|
||||||
bool isRead() const;
|
|
||||||
|
|
||||||
void setRead(bool read);
|
|
||||||
void setBookmark(bool bookmark);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_title;
|
|
||||||
QString m_content;
|
|
||||||
int m_updated;
|
|
||||||
bool m_bookmark;
|
|
||||||
bool m_read;
|
|
||||||
};
|
|
|
@ -26,87 +26,49 @@
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
|
||||||
EntryListModel::EntryListModel(QObject *parent)
|
EntryListModel::EntryListModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QSqlTableModel(parent)
|
||||||
{
|
{
|
||||||
|
setTable("entries");
|
||||||
|
setSort(Updated, Qt::DescendingOrder);
|
||||||
|
setEditStrategy(OnFieldChange);
|
||||||
|
select();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant EntryListModel::data(const QModelIndex &index, int role) const
|
QVariant EntryListModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (role == Title)
|
if(role == Updated || role == Created) {
|
||||||
return m_entries[index.row()].title();
|
|
||||||
if (role == Content)
|
|
||||||
return m_entries[index.row()].content();
|
|
||||||
if (role == Updated) {
|
|
||||||
QDateTime updated;
|
QDateTime updated;
|
||||||
updated.setSecsSinceEpoch(m_entries[index.row()].updated());
|
updated.setSecsSinceEpoch(QSqlQueryModel::data(createIndex(index.row(), role), 0).toInt());
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
if (role == Bookmark)
|
return QSqlQueryModel::data(createIndex(index.row(), role), 0);
|
||||||
return m_entries[index.row()].isBookmark();
|
}
|
||||||
if (role == Read)
|
|
||||||
return m_entries[index.row()].isRead();
|
|
||||||
|
|
||||||
return QStringLiteral("DEADBEEF");
|
|
||||||
}
|
|
||||||
int EntryListModel::rowCount(const QModelIndex &index) const
|
|
||||||
{
|
|
||||||
return m_entries.size();
|
|
||||||
}
|
|
||||||
QHash<int, QByteArray> EntryListModel::roleNames() const
|
QHash<int, QByteArray> EntryListModel::roleNames() const
|
||||||
{
|
{
|
||||||
QHash<int, QByteArray> roleNames;
|
QHash<int, QByteArray> roleNames;
|
||||||
|
roleNames[Feed] = "feed";
|
||||||
|
roleNames[Id] = "id";
|
||||||
roleNames[Title] = "title";
|
roleNames[Title] = "title";
|
||||||
roleNames[Content] = "content";
|
roleNames[Content] = "content";
|
||||||
|
roleNames[Created] = "created";
|
||||||
roleNames[Updated] = "updated";
|
roleNames[Updated] = "updated";
|
||||||
roleNames[Bookmark] = "bookmark";
|
|
||||||
roleNames[Read] = "read";
|
|
||||||
|
|
||||||
return roleNames;
|
return roleNames;
|
||||||
}
|
}
|
||||||
bool EntryListModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
||||||
|
void EntryListModel::setFeed(QString url)
|
||||||
{
|
{
|
||||||
if (role == Bookmark) {
|
m_feed = url;
|
||||||
m_entries[index.row()].setBookmark(value.toBool());
|
setFilter(QStringLiteral("feed ='%1'").arg(url));
|
||||||
} else if (role == Read) {
|
select();
|
||||||
m_entries[index.row()].setRead(value.toBool());
|
|
||||||
}
|
|
||||||
emit dataChanged(index, index, QVector<int>({role}));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntryListModel::fetch()
|
QString EntryListModel::feed() const
|
||||||
{
|
|
||||||
connect(&Fetcher::instance(), &Fetcher::finished, this, &EntryListModel::update);
|
|
||||||
if(m_feed.url().compare("all") != 0)
|
|
||||||
Fetcher::instance().fetch(m_feed.url());
|
|
||||||
else
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntryListModel::update() {
|
|
||||||
beginResetModel();
|
|
||||||
QSqlQuery query;
|
|
||||||
if(m_feed.url().compare("all") == 0) {
|
|
||||||
query.prepare(QStringLiteral("SELECT id, title, content, updated FROM Entries ORDER BY updated DESC;"));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
query.prepare(QStringLiteral("SELECT id, title, content, updated FROM Entries WHERE feed=:feed ORDER BY updated DESC;"));
|
|
||||||
query.bindValue(QStringLiteral(":feed"), m_feed.url());
|
|
||||||
}
|
|
||||||
Database::instance().execute(query);
|
|
||||||
while (query.next()) {
|
|
||||||
m_entries.append(Entry(query.value(1).toString(), query.value(2).toString(), query.value(3).toInt(), false, false));
|
|
||||||
}
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
Feed EntryListModel::feed()
|
|
||||||
{
|
{
|
||||||
return m_feed;
|
return m_feed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntryListModel::setFeed(Feed feed)
|
void EntryListModel::fetch()
|
||||||
{
|
{
|
||||||
m_feed = feed;
|
Fetcher::instance().fetch(m_feed);
|
||||||
emit feedChanged(feed);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,41 +20,32 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QSqlTableModel>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
#include "entry.h"
|
class EntryListModel : public QSqlTableModel
|
||||||
#include "feed.h"
|
|
||||||
|
|
||||||
class EntryListModel : public QAbstractListModel
|
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(Feed feed READ feed WRITE setFeed NOTIFY feedChanged)
|
Q_PROPERTY(QString feed READ feed WRITE setFeed)
|
||||||
public:
|
public:
|
||||||
enum DataRole {
|
enum DataRole {
|
||||||
Title = Qt::UserRole + 1,
|
Feed = 0,
|
||||||
|
Id,
|
||||||
|
Title,
|
||||||
Content,
|
Content,
|
||||||
|
Created,
|
||||||
Updated,
|
Updated,
|
||||||
Bookmark,
|
|
||||||
Read,
|
|
||||||
};
|
};
|
||||||
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;
|
||||||
int rowCount(const QModelIndex &index) const override;
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
|
||||||
|
|
||||||
Feed feed();
|
|
||||||
void setFeed(Feed feed);
|
|
||||||
|
|
||||||
Q_INVOKABLE void fetch();
|
Q_INVOKABLE void fetch();
|
||||||
|
|
||||||
Q_SIGNALS:
|
QString feed() const;
|
||||||
void feedChanged(Feed);
|
void setFeed(QString feed);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector<Entry> m_entries;
|
QString m_feed;
|
||||||
Feed m_feed;
|
|
||||||
|
|
||||||
void update();
|
|
||||||
};
|
};
|
||||||
|
|
79
src/feed.cpp
79
src/feed.cpp
|
@ -1,79 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 "feed.h"
|
|
||||||
|
|
||||||
Feed::Feed()
|
|
||||||
: m_url(QStringLiteral(""))
|
|
||||||
, m_name(QStringLiteral(""))
|
|
||||||
, m_image(QStringLiteral(""))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
Feed::Feed(const QString url)
|
|
||||||
: m_url(url)
|
|
||||||
, m_name(url)
|
|
||||||
, m_image(QStringLiteral(""))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Feed::Feed(const QString url, const QString name, const QString image)
|
|
||||||
: m_url(url)
|
|
||||||
, m_name(name)
|
|
||||||
, m_image(image)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Feed::Feed(const Feed &other)
|
|
||||||
: m_url(other.url())
|
|
||||||
, m_name(other.name())
|
|
||||||
, m_image(other.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Feed::setImage(QString image)
|
|
||||||
{
|
|
||||||
m_image = image;
|
|
||||||
}
|
|
53
src/feed.h
53
src/feed.h
|
@ -1,53 +0,0 @@
|
||||||
/**
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
class Feed
|
|
||||||
{
|
|
||||||
Q_GADGET
|
|
||||||
Q_PROPERTY(QString url READ url)
|
|
||||||
Q_PROPERTY(QString name READ name WRITE setName)
|
|
||||||
Q_PROPERTY(QString image READ image WRITE setImage)
|
|
||||||
public:
|
|
||||||
Feed();
|
|
||||||
Feed(const QString url);
|
|
||||||
Feed(const QString url, const QString name, const QString image);
|
|
||||||
Feed(const Feed &other);
|
|
||||||
~Feed();
|
|
||||||
|
|
||||||
QString name() const;
|
|
||||||
QString url() const;
|
|
||||||
QString image() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_url;
|
|
||||||
QString m_name;
|
|
||||||
QString m_image;
|
|
||||||
|
|
||||||
void setName(QString);
|
|
||||||
void setImage(QString);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Feed);
|
|
|
@ -19,86 +19,77 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QSqlRecord>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QModelIndex>
|
||||||
|
#include <QSqlError>
|
||||||
|
|
||||||
#include "feedListModel.h"
|
#include "feedListModel.h"
|
||||||
#include "fetcher.h"
|
#include "fetcher.h"
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
|
||||||
FeedListModel::FeedListModel(QObject *parent)
|
FeedListModel::FeedListModel(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QSqlTableModel(parent)
|
||||||
{
|
{
|
||||||
QSqlQuery query;
|
setTable("Feeds");
|
||||||
query.prepare(QStringLiteral("SELECT name, url, image FROM Feeds"));
|
setSort(0, Qt::AscendingOrder);
|
||||||
Database::instance().execute(query);
|
setEditStrategy(OnFieldChange);
|
||||||
beginInsertRows(QModelIndex(), 0, query.size());
|
select();
|
||||||
while (query.next()) {
|
|
||||||
feeds += Feed(query.value(1).toString(), query.value(0).toString(), query.value(2).toString());
|
|
||||||
}
|
|
||||||
endInsertRows();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray> FeedListModel::roleNames() const
|
QHash<int, QByteArray> FeedListModel::roleNames() const
|
||||||
{
|
{
|
||||||
QHash<int, QByteArray> roleNames;
|
QHash<int, QByteArray> roleNames;
|
||||||
roleNames[FeedRole] = "feed";
|
roleNames[Name] = "name";
|
||||||
|
roleNames[Url] = "url";
|
||||||
|
roleNames[Image] = "image";
|
||||||
return roleNames;
|
return roleNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant FeedListModel::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (role == FeedRole) {
|
|
||||||
return QVariant::fromValue(feeds[index.row()]);
|
|
||||||
}
|
|
||||||
return QStringLiteral("DEADBEEF");
|
|
||||||
}
|
|
||||||
int FeedListModel::rowCount(const QModelIndex &index) const
|
|
||||||
{
|
|
||||||
return feeds.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FeedListModel::addFeed(QString url)
|
void FeedListModel::addFeed(QString url)
|
||||||
{
|
{
|
||||||
|
qDebug() << "Adding feed";
|
||||||
|
if(feedExists(url)) {
|
||||||
|
qDebug() << "Feed already exists";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qDebug() << "Feed does not yet exist";
|
||||||
|
|
||||||
|
QSqlRecord rec = record();
|
||||||
|
rec.setValue(0, url);
|
||||||
|
rec.setValue(1, url);
|
||||||
|
rec.setValue(2, "");
|
||||||
|
|
||||||
|
insertRecord(-1, rec);
|
||||||
|
|
||||||
|
connect(&Fetcher::instance(), &Fetcher::updated, this, [this]() {
|
||||||
|
select();
|
||||||
|
|
||||||
|
disconnect(&Fetcher::instance(), &Fetcher::updated, nullptr, nullptr);
|
||||||
|
});
|
||||||
|
Fetcher::instance().fetch(QUrl(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant FeedListModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
return QSqlTableModel::data(createIndex(index.row(), role), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FeedListModel::feedExists(QString url) {
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare(QStringLiteral("SELECT COUNT (url) FROM Feeds WHERE url=:url;"));
|
query.prepare(QStringLiteral("SELECT COUNT (url) FROM Feeds WHERE url=:url;"));
|
||||||
query.bindValue(QStringLiteral(":url"), url);
|
query.bindValue(QStringLiteral(":url"), url);
|
||||||
Database::instance().execute(query);
|
Database::instance().execute(query);
|
||||||
query.next();
|
query.next();
|
||||||
if(query.value(0).toInt() != 0) return;
|
return query.value(0).toInt() != 0;
|
||||||
connect(&Fetcher::instance(), &Fetcher::finished, this, [this, url]() {
|
|
||||||
QSqlQuery query;
|
|
||||||
query.prepare(QStringLiteral("SELECT name, image FROM Feeds WHERE url=:url;"));
|
|
||||||
query.bindValue(QStringLiteral(":url"), url);
|
|
||||||
Database::instance().execute(query);
|
|
||||||
query.next();
|
|
||||||
for(int i = 0; i < feeds.length(); i++) {
|
|
||||||
if(feeds[i].url() == url) {
|
|
||||||
feeds.removeAt(i);
|
|
||||||
feeds.insert(i, Feed(url, query.value(0).toString(), query.value(1).toString()));
|
|
||||||
emit dataChanged(index(i), index(i));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Fetcher::instance().fetch(QUrl(url));
|
|
||||||
beginInsertRows(QModelIndex(), feeds.size(), feeds.size());
|
|
||||||
feeds.append(Feed(url));
|
|
||||||
endInsertRows();
|
|
||||||
|
|
||||||
query.prepare(QStringLiteral("INSERT INTO Feeds VALUES (:url, :name, '');"));
|
|
||||||
query.bindValue(QStringLiteral(":url"), url);
|
|
||||||
query.bindValue(QStringLiteral(":name"), url);
|
|
||||||
Database::instance().execute(query);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeedListModel::removeFeed(int index)
|
void FeedListModel::removeFeed(int index)
|
||||||
{
|
{
|
||||||
Feed toRemove = feeds[index];
|
//Workaround...
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
query.prepare(QStringLiteral("DELETE FROM Feeds WHERE name=:name AND url=url;"));
|
query.prepare("DELETE FROM Feeds WHERE url=:url");
|
||||||
query.bindValue(QStringLiteral(":url"), toRemove.url());
|
query.bindValue(":url", data(createIndex(index, 0), 1).toString());
|
||||||
query.bindValue(QStringLiteral(":name"), toRemove.name());
|
|
||||||
Database::instance().execute(query);
|
Database::instance().execute(query);
|
||||||
beginRemoveRows(QModelIndex(), index, index);
|
select();
|
||||||
feeds.remove(index);
|
|
||||||
endRemoveRows();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,29 +20,30 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QSqlTableModel>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
#include "feed.h"
|
//#include "feed.h"
|
||||||
#include "fetcher.h"
|
#include "fetcher.h"
|
||||||
|
|
||||||
class FeedListModel : public QAbstractListModel
|
class FeedListModel : public QSqlTableModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum DataRole {
|
enum DataRole {
|
||||||
FeedRole = Qt::UserRole + 1,
|
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;
|
||||||
int rowCount(const QModelIndex &index) const override;
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
Q_INVOKABLE void addFeed(QString url);
|
Q_INVOKABLE void addFeed(QString url);
|
||||||
Q_INVOKABLE void removeFeed(int index);
|
Q_INVOKABLE void removeFeed(int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector<Feed> feeds;
|
bool feedExists(QString url);
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,6 +31,7 @@ Fetcher::Fetcher() {
|
||||||
|
|
||||||
void Fetcher::fetch(QUrl url)
|
void Fetcher::fetch(QUrl url)
|
||||||
{
|
{
|
||||||
|
qDebug() << "Starting to fetch" << url.toString();
|
||||||
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
|
||||||
manager->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
|
manager->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||||
manager->setStrictTransportSecurityEnabled(true);
|
manager->setStrictTransportSecurityEnabled(true);
|
||||||
|
@ -47,7 +48,15 @@ void Fetcher::fetch(QUrl url)
|
||||||
|
|
||||||
QSqlQuery query;
|
QSqlQuery query;
|
||||||
|
|
||||||
|
query.prepare(QStringLiteral("UPDATE Feeds SET name=:name, image=:image WHERE url=:url;"));
|
||||||
|
query.bindValue(QStringLiteral(":name"), feed->title());
|
||||||
|
query.bindValue(QStringLiteral(":url"), url.toString());
|
||||||
|
query.bindValue(QStringLiteral(":image"), feed->image()->url());
|
||||||
|
Database::instance().execute(query);
|
||||||
|
qDebug() << "Updated feed title:" << feed->title();
|
||||||
|
|
||||||
for (const auto &entry : feed->items()) {
|
for (const auto &entry : feed->items()) {
|
||||||
|
qDebug() << "Processing" << entry->title();
|
||||||
query.prepare(QStringLiteral("SELECT COUNT (id) FROM Entries WHERE id=:id;"));
|
query.prepare(QStringLiteral("SELECT COUNT (id) FROM Entries WHERE id=:id;"));
|
||||||
query.bindValue(QStringLiteral(":id"), entry->id());
|
query.bindValue(QStringLiteral(":id"), entry->id());
|
||||||
Database::instance().execute(query);
|
Database::instance().execute(query);
|
||||||
|
@ -72,13 +81,9 @@ void Fetcher::fetch(QUrl url)
|
||||||
query.bindValue(QStringLiteral(":email"), author->email());
|
query.bindValue(QStringLiteral(":email"), author->email());
|
||||||
Database::instance().execute(query);
|
Database::instance().execute(query);
|
||||||
}
|
}
|
||||||
query.prepare(QStringLiteral("UPDATE Feeds SET name=:name, image=:image WHERE url=:url;"));
|
|
||||||
query.bindValue(QStringLiteral(":name"), feed->title());
|
|
||||||
query.bindValue(QStringLiteral(":url"), url.toString());
|
|
||||||
query.bindValue(QStringLiteral(":image"), feed->image()->url());
|
|
||||||
Database::instance().execute(query);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit updated();
|
||||||
delete reply;
|
delete reply;
|
||||||
emit finished();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,5 +39,5 @@ private:
|
||||||
Fetcher(const Fetcher &);
|
Fetcher(const Fetcher &);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void finished();
|
void updated();
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,7 +43,6 @@ Q_DECL_EXPORT int main(int argc, char *argv[])
|
||||||
|
|
||||||
qmlRegisterType<FeedListModel>("org.kde.alligator", 1, 0, "FeedListModel");
|
qmlRegisterType<FeedListModel>("org.kde.alligator", 1, 0, "FeedListModel");
|
||||||
qmlRegisterType<EntryListModel>("org.kde.alligator", 1, 0, "EntryListModel");
|
qmlRegisterType<EntryListModel>("org.kde.alligator", 1, 0, "EntryListModel");
|
||||||
qRegisterMetaType<Feed>();
|
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
|
|
||||||
|
|
|
@ -28,17 +28,19 @@ import org.kde.alligator 1.0
|
||||||
|
|
||||||
Kirigami.ScrollablePage {
|
Kirigami.ScrollablePage {
|
||||||
id: page
|
id: page
|
||||||
property var feed
|
|
||||||
|
property var data
|
||||||
|
|
||||||
|
property var all: page.data.url === "all"
|
||||||
|
|
||||||
contextualActions: [
|
contextualActions: [
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
text: i18n("Details")
|
text: i18n("Details")
|
||||||
visible: feed.url != "all"
|
visible: !all
|
||||||
onTriggered: ;//pageStack.push("qrc:/qml/FeedDetailsPage.qml", {"modelData": atomModel})
|
onTriggered: ;//pageStack.push("qrc:/qml/FeedDetailsPage.qml", {"modelData": atomModel})
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
entryListModel.fetch();
|
entryListModel.fetch();
|
||||||
}
|
}
|
||||||
|
@ -46,27 +48,28 @@ Kirigami.ScrollablePage {
|
||||||
ListView {
|
ListView {
|
||||||
model: EntryListModel {
|
model: EntryListModel {
|
||||||
id: entryListModel
|
id: entryListModel
|
||||||
feed: page.feed
|
feed: page.data.url
|
||||||
}
|
}
|
||||||
|
|
||||||
header: RowLayout {
|
header: RowLayout {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: page.height * 0.2
|
height: page.height * 0.2
|
||||||
|
visible: !all
|
||||||
Image {
|
Image {
|
||||||
source: feed.image
|
source: page.data.image
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
sourceSize.width: 0
|
sourceSize.width: 0
|
||||||
sourceSize.height: parent.height
|
sourceSize.height: parent.height
|
||||||
}
|
}
|
||||||
Kirigami.Heading {
|
Kirigami.Heading {
|
||||||
text: feed.name
|
text: page.data.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: Kirigami.SwipeListItem {
|
delegate: Kirigami.SwipeListItem {
|
||||||
Controls.Label {
|
Controls.Label {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: model.title + " - " + model.updated
|
text: model.title + " - " + model.updated.toLocaleString(Qt.locale(), Locale.ShortFormat)
|
||||||
textFormat: Text.RichText
|
textFormat: Text.RichText
|
||||||
color: model.read ? Kirigami.Theme.disabledTextColor : Kirigami.Theme.textColor
|
color: model.read ? Kirigami.Theme.disabledTextColor : Kirigami.Theme.textColor
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,13 +86,13 @@ Kirigami.ScrollablePage {
|
||||||
Item {
|
Item {
|
||||||
Kirigami.Icon {
|
Kirigami.Icon {
|
||||||
id: icon
|
id: icon
|
||||||
source: model.feed.image
|
source: model.image
|
||||||
width: height
|
width: height
|
||||||
height: parent.height
|
height: parent.height
|
||||||
}
|
}
|
||||||
|
|
||||||
Controls.Label {
|
Controls.Label {
|
||||||
text: model.feed.name
|
text: model.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
|
||||||
|
@ -107,7 +107,7 @@ Kirigami.ScrollablePage {
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
onClicked: pageStack.push("qrc:/EntryListPage.qml", {"feed": feed})
|
onClicked: pageStack.push("qrc:/EntryListPage.qml", {"data": model})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue