diff --git a/src/database.cpp b/src/database.cpp index 1d179174..f10499c4 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -119,86 +119,3 @@ void Database::cleanup() // TODO: also delete enclosures and authors(?) } } - -bool Database::feedExists(const QString &url) -{ - QSqlQuery query; - query.prepare(QStringLiteral("SELECT COUNT (url) FROM Feeds WHERE url=:url;")); - query.bindValue(QStringLiteral(":url"), url); - Database::instance().execute(query); - query.next(); - return query.value(0).toInt() != 0; -} - -void Database::addFeed(const QString &url) -{ - qDebug() << "Adding feed"; - if (feedExists(url)) { - qDebug() << "Feed already exists"; - return; - } - qDebug() << "Feed does not yet exist"; - - QUrl urlFromInput = QUrl::fromUserInput(url); - QSqlQuery query; - query.prepare(QStringLiteral("INSERT INTO Feeds VALUES (:name, :url, :image, :link, :description, :deleteAfterCount, :deleteAfterType, :subscribed, :lastUpdated, :notify);")); - query.bindValue(QStringLiteral(":name"), urlFromInput.toString()); - query.bindValue(QStringLiteral(":url"), urlFromInput.toString()); - query.bindValue(QStringLiteral(":image"), QLatin1String("")); - query.bindValue(QStringLiteral(":link"), QLatin1String("")); - query.bindValue(QStringLiteral(":description"), QLatin1String("")); - query.bindValue(QStringLiteral(":deleteAfterCount"), 0); - query.bindValue(QStringLiteral(":deleteAfterType"), 0); - query.bindValue(QStringLiteral(":subscribed"), QDateTime::currentDateTime().toSecsSinceEpoch()); - query.bindValue(QStringLiteral(":lastUpdated"), 0); - query.bindValue(QStringLiteral(":notify"), false); - execute(query); - - Q_EMIT feedAdded(urlFromInput.toString()); - - Fetcher::instance().fetch(urlFromInput.toString()); -} - -void Database::importFeeds(const QString &path) -{ - QUrl url(path); - QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString()); - - file.open(QIODevice::ReadOnly); - - QXmlStreamReader xmlReader(&file); - while(!xmlReader.atEnd()) { - xmlReader.readNext(); - if(xmlReader.tokenType() == 4 && xmlReader.attributes().hasAttribute(QStringLiteral("xmlUrl"))) { - addFeed(xmlReader.attributes().value(QStringLiteral("xmlUrl")).toString()); - } - } - Fetcher::instance().fetchAll(); -} - -void Database::exportFeeds(const QString &path) -{ - QUrl url(path); - QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString()); - file.open(QIODevice::WriteOnly); - - QXmlStreamWriter xmlWriter(&file); - xmlWriter.setAutoFormatting(true); - xmlWriter.writeStartDocument(QStringLiteral("1.0")); - xmlWriter.writeStartElement(QStringLiteral("opml")); - xmlWriter.writeEmptyElement(QStringLiteral("head")); - xmlWriter.writeStartElement(QStringLiteral("body")); - xmlWriter.writeAttribute(QStringLiteral("version"), QStringLiteral("1.0")); - QSqlQuery query; - query.prepare(QStringLiteral("SELECT url, name FROM Feeds;")); - execute(query); - while(query.next()) { - xmlWriter.writeEmptyElement(QStringLiteral("outline")); - xmlWriter.writeAttribute(QStringLiteral("xmlUrl"), query.value(0).toString()); - xmlWriter.writeAttribute(QStringLiteral("title"), query.value(1).toString()); - } - xmlWriter.writeEndElement(); - xmlWriter.writeEndElement(); - xmlWriter.writeEndDocument(); - -} diff --git a/src/database.h b/src/database.h index 216bbc8c..9370132d 100644 --- a/src/database.h +++ b/src/database.h @@ -20,12 +20,6 @@ public: } bool execute(QSqlQuery &query); bool execute(const QString &query); - Q_INVOKABLE void addFeed(const QString &url); - Q_INVOKABLE void importFeeds(const QString &path); - Q_INVOKABLE void exportFeeds(const QString &path); - -Q_SIGNALS: - void feedAdded(const QString &url); private: Database(); @@ -34,5 +28,4 @@ private: bool migrate(); bool migrateTo1(); void cleanup(); - bool feedExists(const QString &url); }; diff --git a/src/datamanager.cpp b/src/datamanager.cpp index 5de1b2db..17039eff 100644 --- a/src/datamanager.cpp +++ b/src/datamanager.cpp @@ -4,16 +4,36 @@ * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL */ - +#include +#include +#include +#include +#include +#include +#include +#include #include "datamanager.h" #include "fetcher.h" #include "database.h" - DataManager::DataManager() { + // connect signals to lambda slots + connect(&Fetcher::instance(), &Fetcher::feedDetailsUpdated, this, [this](const QString &url, const QString &name, const QString &image, const QString &link, const QString &description, const QDateTime &lastUpdated) { + m_feeds[url]->setName(name); + m_feeds[url]->setImage(image); + m_feeds[url]->setLink(link); + m_feeds[url]->setDescription(description); + m_feeds[url]->setLastUpdated(lastUpdated); + // TODO: signal feedmodel: Q_EMIT dataChanged(createIndex(i, 0), createIndex(i, 0)); + }); + connect(&Fetcher::instance(), &Fetcher::feedUpdated, this, [this](const QString &url) { + // TODO: make DataManager rescan entries + Q_EMIT feedEntriesUpdated(url); + }); + // Only read unique feedurls and entry ids from the database. - // The feed and entry datastructres will be loaded lazily. + // The feed and entry datastructures will be loaded lazily. QSqlQuery query; query.prepare(QStringLiteral("SELECT url FROM Feeds;")); Database::instance().execute(query); @@ -28,8 +48,8 @@ DataManager::DataManager() Database::instance().execute(query); while (query.next()) { m_entrymap[feedurl] += query.value(QStringLiteral("id")).toString(); + qDebug() << m_entrymap[feedurl]; } - qDebug() << m_entrymap[feedurl]; } qDebug() << m_entrymap; } @@ -46,7 +66,195 @@ Feed* DataManager::getFeed(QString const feedurl) const return m_feeds[feedurl]; } -void DataManager::loadFeed(QString const feedurl) const + +Entry* DataManager::getEntry(int const feed_index, int const entry_index) const +{ + return getEntry(m_entrymap[m_feedmap[feed_index]][entry_index]); +} + +Entry* DataManager::getEntry(const Feed* feed, int const entry_index) const +{ + return getEntry(m_entrymap[feed->url()][entry_index]); +} + +Entry* DataManager::getEntry(QString id) const +{ + if (m_entries[id] == nullptr) + loadEntry(id); + return m_entries[id]; +} + +int DataManager::feedCount() const +{ + return m_feedmap.count(); +} + +int DataManager::entryCount(const int feed_index) const +{ + return m_entrymap[m_feedmap[feed_index]].count(); +} + +int DataManager::entryCount(const Feed* feed) const +{ + return m_entrymap[feed->url()].count(); +} + +int DataManager::unreadEntryCount(const Feed* feed) const +{ + QSqlQuery query; + query.prepare(QStringLiteral("SELECT COUNT (id) FROM Entries where feed=:feed AND read=0;")); + query.bindValue(QStringLiteral(":feed"), feed->url()); + Database::instance().execute(query); + if (!query.next()) + return -1; + return query.value(0).toInt(); +} + +void DataManager::removeFeed(const Feed* feed) +{ + removeFeed(m_feedmap.indexOf(feed->url())); +} + +void DataManager::removeFeed(const int &index) +{ + // Get feed pointer + Feed* feed = m_feeds[m_feedmap[index]]; + + // First delete everything from the database + + // Delete Authors + QSqlQuery query; + query.prepare(QStringLiteral("DELETE FROM Authors WHERE feed=:feed;")); + query.bindValue(QStringLiteral(":feed"), feed->url()); + Database::instance().execute(query); + + // Delete Entries + query.prepare(QStringLiteral("DELETE FROM Entries WHERE feed=:feed;")); + query.bindValue(QStringLiteral(":feed"), feed->url()); + Database::instance().execute(query); + + // Delete Enclosures + query.prepare(QStringLiteral("DELETE FROM Enclosures WHERE feed=:feed;")); + query.bindValue(QStringLiteral(":feed"), feed->url()); + Database::instance().execute(query); + + // Delete Feed + query.prepare(QStringLiteral("DELETE FROM Feeds WHERE url=:url;")); + query.bindValue(QStringLiteral(":url"), feed->url()); + Database::instance().execute(query); + + // Then delete the instances and mappings + for (auto& id : m_entrymap[feed->url()]) { + delete m_entries[id]; // delete pointer + m_entries.remove(id); // delete the hash key + } + m_entrymap.remove(feed->url()); // remove all the entry mappings belonging to the feed + + delete feed; // remove the pointer + m_feeds.remove(m_feedmap[index]); // remove from m_feeds + m_feedmap.removeAt(index); // remove from m_feedmap + Q_EMIT(feedRemoved(index)); +} + +void DataManager::addFeed(const QString &url) +{ + qDebug() << "Adding feed"; + if (feedExists(url)) { + qDebug() << "Feed already exists"; + return; + } + qDebug() << "Feed does not yet exist"; + + QUrl urlFromInput = QUrl::fromUserInput(url); + QSqlQuery query; + query.prepare(QStringLiteral("INSERT INTO Feeds VALUES (:name, :url, :image, :link, :description, :deleteAfterCount, :deleteAfterType, :subscribed, :lastUpdated, :notify);")); + query.bindValue(QStringLiteral(":name"), urlFromInput.toString()); + query.bindValue(QStringLiteral(":url"), urlFromInput.toString()); + query.bindValue(QStringLiteral(":image"), QLatin1String("")); + query.bindValue(QStringLiteral(":link"), QLatin1String("")); + query.bindValue(QStringLiteral(":description"), QLatin1String("")); + query.bindValue(QStringLiteral(":deleteAfterCount"), 0); + query.bindValue(QStringLiteral(":deleteAfterType"), 0); + query.bindValue(QStringLiteral(":subscribed"), QDateTime::currentDateTime().toSecsSinceEpoch()); + query.bindValue(QStringLiteral(":lastUpdated"), 0); + query.bindValue(QStringLiteral(":notify"), false); + Database::instance().execute(query); + + m_feeds[urlFromInput.toString()] = new Feed(urlFromInput.toString()); + m_feedmap.append(urlFromInput.toString()); + + Q_EMIT feedAdded(urlFromInput.toString()); + + Fetcher::instance().fetch(urlFromInput.toString()); +} + +void DataManager::importFeeds(const QString &path) +{ + QUrl url(path); + QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString()); + + file.open(QIODevice::ReadOnly); + + QXmlStreamReader xmlReader(&file); + while(!xmlReader.atEnd()) { + xmlReader.readNext(); + if(xmlReader.tokenType() == 4 && xmlReader.attributes().hasAttribute(QStringLiteral("xmlUrl"))) { + addFeed(xmlReader.attributes().value(QStringLiteral("xmlUrl")).toString()); + } + } + Fetcher::instance().fetchAll(); +} + +void DataManager::exportFeeds(const QString &path) +{ + QUrl url(path); + QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString()); + file.open(QIODevice::WriteOnly); + + QXmlStreamWriter xmlWriter(&file); + xmlWriter.setAutoFormatting(true); + xmlWriter.writeStartDocument(QStringLiteral("1.0")); + xmlWriter.writeStartElement(QStringLiteral("opml")); + xmlWriter.writeEmptyElement(QStringLiteral("head")); + xmlWriter.writeStartElement(QStringLiteral("body")); + xmlWriter.writeAttribute(QStringLiteral("version"), QStringLiteral("1.0")); + QSqlQuery query; + query.prepare(QStringLiteral("SELECT url, name FROM Feeds;")); + Database::instance().execute(query); + while(query.next()) { + xmlWriter.writeEmptyElement(QStringLiteral("outline")); + xmlWriter.writeAttribute(QStringLiteral("xmlUrl"), query.value(0).toString()); + xmlWriter.writeAttribute(QStringLiteral("title"), query.value(1).toString()); + } + xmlWriter.writeEndElement(); + xmlWriter.writeEndElement(); + xmlWriter.writeEndDocument(); + +} + +void DataManager::loadFeed(const QString feedurl) const { m_feeds[feedurl] = new Feed(feedurl); } + +void DataManager::loadEntry(const QString id) const +{ + // First find the feed that this entry belongs to + Feed* feed = nullptr; + QHashIterator i(m_entrymap); + while (i.hasNext()) { + i.next(); + if (i.value().contains(id)) + feed = getFeed(i.key()); + } + if (feed == nullptr) { + qDebug() << "Failed to find feed belonging to entry" << id; + return; + } + m_entries[id] = new Entry(feed, id); +} + +bool DataManager::feedExists(const QString &url) +{ + return m_feeds.contains(url); +} diff --git a/src/datamanager.h b/src/datamanager.h index 0c6b290c..fa8fa07c 100644 --- a/src/datamanager.h +++ b/src/datamanager.h @@ -22,13 +22,39 @@ public: Feed* getFeed(int const index) const; Feed* getFeed(QString const feedurl) const; + Entry* getEntry(int const feed_index, int const entry_index) const; + Entry* getEntry(const Feed* feed, int const entry_index) const; + Entry* getEntry(const QString id) const; + int feedCount() const; + int entryCount(const int feed_index) const; + int entryCount(const Feed* feed) const; + int unreadEntryCount(const Feed* feed) const; + Q_INVOKABLE void addFeed(const QString &url); + Q_INVOKABLE void removeFeed(const Feed* feed); + Q_INVOKABLE void removeFeed(const int &index); + + //Q_INVOKABLE void addEntry(const QString &url); + //Q_INVOKABLE void removeEntry(const QString &url); + //Q_INVOKABLE void removeEntry(const Feed* feed, const int &index); + + Q_INVOKABLE void importFeeds(const QString &path); + Q_INVOKABLE void exportFeeds(const QString &path); + +Q_SIGNALS: + void feedAdded(const QString &url); + void feedRemoved(const int &index); + void entryAdded(const QString &id); + void entryRemoved(const Feed*, const int &index); + void feedEntriesUpdated(const QString &url); private: DataManager(); void loadFeed(QString feedurl) const; + void loadEntry(QString id) const; + bool feedExists(const QString &url); - QVector m_feedmap; + QStringList m_feedmap; mutable QHash m_feeds; - QHash > m_entrymap; + QHash m_entrymap; mutable QHash m_entries; }; diff --git a/src/entriesmodel.cpp b/src/entriesmodel.cpp index 352682b6..29e3a42e 100644 --- a/src/entriesmodel.cpp +++ b/src/entriesmodel.cpp @@ -9,6 +9,7 @@ #include #include "database.h" +#include "datamanager.h" #include "entriesmodel.h" #include "fetcher.h" @@ -16,30 +17,20 @@ EntriesModel::EntriesModel(Feed *feed) : QAbstractListModel(feed) , m_feed(feed) { - connect(&Fetcher::instance(), &Fetcher::feedUpdated, this, [this](const QString &url) { + connect(&DataManager::instance(), &DataManager::feedEntriesUpdated, this, [this](const QString &url) { if (m_feed->url() == url) { beginResetModel(); - for (auto &entry : m_entries) { - delete entry; - } - m_entries.clear(); + // TODO: make sure to pop the entrylistpage if it's the active one endResetModel(); } }); } -EntriesModel::~EntriesModel() -{ - qDeleteAll(m_entries); -} - QVariant EntriesModel::data(const QModelIndex &index, int role) const { if (role != 0) return QVariant(); - if (m_entries[index.row()] == nullptr) - loadEntry(index.row()); - return QVariant::fromValue(m_entries[index.row()]); + return QVariant::fromValue(DataManager::instance().getEntry(m_feed, index.row())); } QHash EntriesModel::roleNames() const @@ -52,18 +43,7 @@ QHash EntriesModel::roleNames() const int EntriesModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) - QSqlQuery query; - query.prepare(QStringLiteral("SELECT COUNT() FROM Entries WHERE feed=:feed;")); - 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(); -} - -void EntriesModel::loadEntry(int index) const -{ - m_entries[index] = new Entry(m_feed, index); + return DataManager::instance().entryCount(m_feed); } Feed *EntriesModel::feed() const diff --git a/src/entriesmodel.h b/src/entriesmodel.h index 2dadc70b..9f110800 100644 --- a/src/entriesmodel.h +++ b/src/entriesmodel.h @@ -22,7 +22,6 @@ class EntriesModel : public QAbstractListModel public: explicit EntriesModel(Feed *feed); - ~EntriesModel() override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QHash roleNames() const override; int rowCount(const QModelIndex &parent) const override; @@ -30,8 +29,5 @@ public: Feed *feed() const; private: - void loadEntry(int index) const; - Feed *m_feed; - mutable QHash m_entries; }; diff --git a/src/entry.cpp b/src/entry.cpp index ac9ba681..97c3b741 100644 --- a/src/entry.cpp +++ b/src/entry.cpp @@ -47,6 +47,41 @@ Entry::Entry(Feed *feed, int index) } } +Entry::Entry(Feed *feed, QString id) + : QObject(nullptr) + , m_feed(feed) +{ + QSqlQuery entryQuery; + entryQuery.prepare(QStringLiteral("SELECT * FROM Entries WHERE feed=:feed AND id=:id;")); + entryQuery.bindValue(QStringLiteral(":feed"), m_feed->url()); + entryQuery.bindValue(QStringLiteral(":id"), id); + Database::instance().execute(entryQuery); + if (!entryQuery.next()) + qWarning() << "No element with index" << id << "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); + + while (authorQuery.next()) { + m_authors += new Author(authorQuery.value(QStringLiteral("name")).toString(), authorQuery.value(QStringLiteral("email")).toString(), authorQuery.value(QStringLiteral("uri")).toString(), nullptr); + } + + m_created.setSecsSinceEpoch(entryQuery.value(QStringLiteral("created")).toInt()); + m_updated.setSecsSinceEpoch(entryQuery.value(QStringLiteral("updated")).toInt()); + + m_id = entryQuery.value(QStringLiteral("id")).toString(); + m_title = entryQuery.value(QStringLiteral("title")).toString(); + m_content = entryQuery.value(QStringLiteral("content")).toString(); + m_link = entryQuery.value(QStringLiteral("link")).toString(); + m_read = entryQuery.value(QStringLiteral("read")).toBool(); + + if (entryQuery.value(QStringLiteral("hasEnclosure")).toBool()) { + m_enclosure = new Enclosure(this); + } +} + Entry::~Entry() { qDeleteAll(m_authors); diff --git a/src/entry.h b/src/entry.h index ff87628f..edfacff9 100644 --- a/src/entry.h +++ b/src/entry.h @@ -35,6 +35,7 @@ class Entry : public QObject public: Entry(Feed *feed, int index); + Entry(Feed *feed, QString id); ~Entry(); QString id() const; diff --git a/src/feed.cpp b/src/feed.cpp index 1dc4ce26..482056a3 100644 --- a/src/feed.cpp +++ b/src/feed.cpp @@ -7,6 +7,7 @@ #include #include "database.h" +#include "datamanager.h" #include "entriesmodel.h" #include "feed.h" #include "fetcher.h" @@ -78,6 +79,73 @@ Feed::Feed(int index) m_entries = new EntriesModel(this); } +Feed::Feed(QString const feedurl) + : QObject(nullptr) +{ + + QSqlQuery query; + query.prepare(QStringLiteral("SELECT * FROM Feeds WHERE url=:feedurl;")); + query.bindValue(QStringLiteral(":feedurl"), feedurl); + Database::instance().execute(query); + if (!query.next()) + qWarning() << "Failed to load feed" << feedurl; + + QSqlQuery authorQuery; + authorQuery.prepare(QStringLiteral("SELECT * FROM Authors WHERE id='' AND feed=:feed")); + authorQuery.bindValue(QStringLiteral(":feed"), feedurl); + Database::instance().execute(authorQuery); + while (authorQuery.next()) { + m_authors += new Author(authorQuery.value(QStringLiteral("name")).toString(), authorQuery.value(QStringLiteral("email")).toString(), authorQuery.value(QStringLiteral("uri")).toString(), nullptr); + } + + m_subscribed.setSecsSinceEpoch(query.value(QStringLiteral("subscribed")).toInt()); + + m_lastUpdated.setSecsSinceEpoch(query.value(QStringLiteral("lastUpdated")).toInt()); + + m_url = query.value(QStringLiteral("url")).toString(); + m_name = query.value(QStringLiteral("name")).toString(); + m_image = query.value(QStringLiteral("image")).toString(); + m_link = query.value(QStringLiteral("link")).toString(); + m_description = query.value(QStringLiteral("description")).toString(); + m_deleteAfterCount = query.value(QStringLiteral("deleteAfterCount")).toInt(); + m_deleteAfterType = query.value(QStringLiteral("deleteAfterType")).toInt(); + m_notify = query.value(QStringLiteral("notify")).toBool(); + + m_errorId = 0; + m_errorString = QLatin1String(""); + + connect(&Fetcher::instance(), &Fetcher::startedFetchingFeed, this, [this](const QString &url) { + if (url == m_url) { + m_errorId = 0; + m_errorString = QLatin1String(""); + setRefreshing(true); + } + }); + connect(&Fetcher::instance(), &Fetcher::feedUpdated, this, [this](const QString &url) { + if (url == m_url) { + setRefreshing(false); + Q_EMIT entryCountChanged(); + Q_EMIT unreadEntryCountChanged(); + setErrorId(0); + setErrorString(QLatin1String("")); + } + }); + connect(&Fetcher::instance(), &Fetcher::error, this, [this](const QString &url, int errorId, const QString &errorString) { + if(url == m_url) { + setErrorId(errorId); + setErrorString(errorString); + setRefreshing(false); + } + }); + + connect(&Fetcher::instance(), &Fetcher::downloadFinished, this, [this](QString url) { + if(url == m_image) + Q_EMIT imageChanged(url); + }); + + m_entries = new EntriesModel(this); +} + Feed::~Feed() { } @@ -139,24 +207,12 @@ bool Feed::notify() const int Feed::entryCount() const { - QSqlQuery query; - query.prepare(QStringLiteral("SELECT COUNT (id) FROM Entries where feed=:feed;")); - query.bindValue(QStringLiteral(":feed"), m_url); - Database::instance().execute(query); - if (!query.next()) - return -1; - return query.value(0).toInt(); + return DataManager::instance().entryCount(this); } int Feed::unreadEntryCount() const { - QSqlQuery query; - query.prepare(QStringLiteral("SELECT COUNT (id) FROM Entries where feed=:feed AND read=0;")); - query.bindValue(QStringLiteral(":feed"), m_url); - Database::instance().execute(query); - if (!query.next()) - return -1; - return query.value(0).toInt(); + return DataManager::instance().unreadEntryCount(this); } bool Feed::refreshing() const @@ -250,24 +306,3 @@ void Feed::refresh() { Fetcher::instance().fetch(m_url); } - -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); -} diff --git a/src/feed.h b/src/feed.h index 9ee6269c..523ceed0 100644 --- a/src/feed.h +++ b/src/feed.h @@ -38,6 +38,7 @@ class Feed : public QObject public: Feed(int index); + Feed(QString const feedurl); ~Feed(); @@ -74,7 +75,6 @@ public: void setErrorString(const QString &errorString); Q_INVOKABLE void refresh(); - void remove(); Q_SIGNALS: void nameChanged(const QString &name); diff --git a/src/feedsmodel.cpp b/src/feedsmodel.cpp index 01b19f06..76ac8e89 100644 --- a/src/feedsmodel.cpp +++ b/src/feedsmodel.cpp @@ -11,28 +11,20 @@ #include #include "database.h" +#include "datamanager.h" #include "feedsmodel.h" #include "fetcher.h" FeedsModel::FeedsModel(QObject *parent) : QAbstractListModel(parent) { - connect(&Database::instance(), &Database::feedAdded, this, [this]() { + connect(&DataManager::instance(), &DataManager::feedAdded, this, [this]() { beginInsertRows(QModelIndex(), rowCount(QModelIndex()) - 1, rowCount(QModelIndex()) - 1); endInsertRows(); }); - connect(&Fetcher::instance(), &Fetcher::feedDetailsUpdated, this, [this](const QString &url, const QString &name, const QString &image, const QString &link, const QString &description, const QDateTime &lastUpdated) { - for (int i = 0; i < m_feeds.length(); i++) { - if (m_feeds[i]->url() == url) { - m_feeds[i]->setName(name); - m_feeds[i]->setImage(image); - m_feeds[i]->setLink(link); - m_feeds[i]->setDescription(description); - m_feeds[i]->setLastUpdated(lastUpdated); - Q_EMIT dataChanged(createIndex(i, 0), createIndex(i, 0)); - break; - } - } + connect(&DataManager::instance(), &DataManager::feedRemoved, this, [this](const int &index) { + beginRemoveRows(QModelIndex(), index, index); + endRemoveRows(); }); } @@ -45,41 +37,25 @@ QHash FeedsModel::roleNames() const int FeedsModel::rowCount(const QModelIndex &parent) const { - 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(); + Q_UNUSED(parent); + return DataManager::instance().feedCount(); } QVariant FeedsModel::data(const QModelIndex &index, int role) const { if (role != 0) return QVariant(); - if (m_feeds.length() <= index.row()) - loadFeed(index.row()); - return QVariant::fromValue(m_feeds[index.row()]); -} - -void FeedsModel::loadFeed(int index) const -{ - m_feeds += new Feed(index); + return QVariant::fromValue(DataManager::instance().getFeed(index.row())); } void FeedsModel::removeFeed(int index) { - m_feeds[index]->remove(); - delete m_feeds[index]; - beginRemoveRows(QModelIndex(), index, index); - m_feeds.removeAt(index); - endRemoveRows(); + DataManager::instance().removeFeed(index); } void FeedsModel::refreshAll() { - for (auto &feed : m_feeds) { - feed->refresh(); - } +// for (auto &feed : m_feeds) { +// feed->refresh(); +// } } diff --git a/src/feedsmodel.h b/src/feedsmodel.h index 026aa3fe..ae6ab4ea 100644 --- a/src/feedsmodel.h +++ b/src/feedsmodel.h @@ -24,9 +24,4 @@ public: int rowCount(const QModelIndex &parent) const override; Q_INVOKABLE void removeFeed(int index); Q_INVOKABLE void refreshAll(); - -private: - void loadFeed(int index) const; - - mutable QVector m_feeds; }; diff --git a/src/main.cpp b/src/main.cpp index 3f2cfc4d..c837a795 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -89,6 +89,8 @@ int main(int argc, char *argv[]) Database::instance(); DataManager::instance(); + //qDebug() << DataManager::instance().getFeed(0)->name(); + //qDebug() << DataManager::instance().getEntry(0, 0)->title(); engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); diff --git a/src/qml/AddFeedSheet.qml b/src/qml/AddFeedSheet.qml index 4fee50bb..e7128359 100644 --- a/src/qml/AddFeedSheet.qml +++ b/src/qml/AddFeedSheet.qml @@ -34,8 +34,8 @@ Kirigami.OverlaySheet { text: i18n("Add Feed") enabled: urlField.text onClicked: { - Database.addFeed(urlField.text) + DataManager.addFeed(urlField.text) addSheet.close() } } -} \ No newline at end of file +} diff --git a/src/qml/FeedListPage.qml b/src/qml/FeedListPage.qml index 94c72aa2..f920732f 100644 --- a/src/qml/FeedListPage.qml +++ b/src/qml/FeedListPage.qml @@ -81,7 +81,7 @@ Kirigami.ScrollablePage { title: i18n("Import Feeds") folder: StandardPaths.writableLocation(StandardPaths.HomeLocation) nameFilters: [i18n("All Files (*)"), i18n("XML Files (*.xml)"), i18n("OPML Files (*.opml)")] - onAccepted: Database.importFeeds(file) + onAccepted: DataManager.importFeeds(file) } FileDialog { @@ -89,7 +89,7 @@ Kirigami.ScrollablePage { title: i18n("Export Feeds") folder: StandardPaths.writableLocation(StandardPaths.HomeLocation) nameFilters: [i18n("All Files")] - onAccepted: Database.exportFeeds(file) + onAccepted: DataManager.exportFeeds(file) fileMode: FileDialog.SaveFile } }