diff --git a/src/database.cpp b/src/database.cpp index 99236a35..d0f22ba0 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -62,6 +62,8 @@ bool Database::migrate() TRUE_OR_RETURN(migrateTo5()); if (dbversion < 6) TRUE_OR_RETURN(migrateTo6()); + if (dbversion < 7) + TRUE_OR_RETURN(migrateTo7()); return true; } @@ -151,6 +153,16 @@ bool Database::migrateTo6() return true; } +bool Database::migrateTo7() +{ + qDebug() << "Migrating database to version 7"; + TRUE_OR_RETURN(transaction()); + TRUE_OR_RETURN(execute(QStringLiteral("ALTER TABLE Entries ADD COLUMN favorite BOOL DEFAULT 0;"))); + TRUE_OR_RETURN(execute(QStringLiteral("PRAGMA user_version = 7;"))); + TRUE_OR_RETURN(commit()); + return true; +} + bool Database::execute(const QString &query, const QString &connectionName) { QSqlQuery q(connectionName); diff --git a/src/database.h b/src/database.h index 5cd745c4..a0952d21 100644 --- a/src/database.h +++ b/src/database.h @@ -42,6 +42,7 @@ private: bool migrateTo4(); bool migrateTo5(); bool migrateTo6(); + bool migrateTo7(); void cleanup(); void setWalMode(); diff --git a/src/datamanager.cpp b/src/datamanager.cpp index 6502cc90..3e5a0cab 100644 --- a/src/datamanager.cpp +++ b/src/datamanager.cpp @@ -185,6 +185,17 @@ int DataManager::newEntryCount(const Feed *feed) const return query.value(0).toInt(); } +int DataManager::favoriteEntryCount(const Feed *feed) const +{ + QSqlQuery query; + query.prepare(QStringLiteral("SELECT COUNT (id) FROM Entries where feed=:feed AND favorite=1;")); + query.bindValue(QStringLiteral(":feed"), feed->url()); + Database::instance().execute(query); + if (!query.next()) + return -1; + return query.value(0).toInt(); +} + void DataManager::removeFeed(Feed *feed) { QList feeds; @@ -661,6 +672,22 @@ void DataManager::bulkMarkNew(bool state, QStringList list) Q_EMIT bulkNewStatusActionFinished(); } +void DataManager::bulkMarkFavoriteByIndex(bool state, QModelIndexList list) +{ + bulkMarkFavorite(state, getIdsFromModelIndexList(list)); +} + +void DataManager::bulkMarkFavorite(bool state, QStringList list) +{ + Database::instance().transaction(); + for (QString id : list) { + getEntry(id)->setFavoriteInternal(state); + } + Database::instance().commit(); + + Q_EMIT bulkFavoriteStatusActionFinished(); +} + void DataManager::bulkQueueStatusByIndex(bool state, QModelIndexList list) { bulkQueueStatus(state, getIdsFromModelIndexList(list)); diff --git a/src/datamanager.h b/src/datamanager.h index e0988854..c810f634 100644 --- a/src/datamanager.h +++ b/src/datamanager.h @@ -37,6 +37,7 @@ public: int entryCount(const int feed_index) const; int entryCount(const Feed *feed) const; int newEntryCount(const Feed *feed) const; + int favoriteEntryCount(const Feed *feed) const; Q_INVOKABLE void addFeed(const QString &url); void addFeed(const QString &url, const bool fetch); void addFeeds(const QStringList &urls); @@ -67,12 +68,14 @@ public: Q_INVOKABLE void bulkMarkRead(bool state, QStringList list); Q_INVOKABLE void bulkMarkNew(bool state, QStringList list); + Q_INVOKABLE void bulkMarkFavorite(bool state, QStringList list); Q_INVOKABLE void bulkQueueStatus(bool state, QStringList list); Q_INVOKABLE void bulkDownloadEnclosures(QStringList list); Q_INVOKABLE void bulkDeleteEnclosures(QStringList list); Q_INVOKABLE void bulkMarkReadByIndex(bool state, QModelIndexList list); Q_INVOKABLE void bulkMarkNewByIndex(bool state, QModelIndexList list); + Q_INVOKABLE void bulkMarkFavoriteByIndex(bool state, QModelIndexList list); Q_INVOKABLE void bulkQueueStatusByIndex(bool state, QModelIndexList list); Q_INVOKABLE void bulkDownloadEnclosuresByIndex(QModelIndexList list); Q_INVOKABLE void bulkDeleteEnclosuresByIndex(QModelIndexList list); @@ -87,9 +90,11 @@ Q_SIGNALS: void unreadEntryCountChanged(const QString &url); void newEntryCountChanged(const QString &url); + void favoriteEntryCountChanged(const QString &url); void bulkReadStatusActionFinished(); void bulkNewStatusActionFinished(); + void bulkFavoriteStatusActionFinished(); // this will relay the AudioManager::playbackRateChanged signal; this is // required to avoid a dependency loop on startup diff --git a/src/entry.cpp b/src/entry.cpp index 7bb3633b..7a801698 100644 --- a/src/entry.cpp +++ b/src/entry.cpp @@ -72,6 +72,10 @@ void Entry::updateFromDb(bool emitSignals) m_new = entryQuery.value(QStringLiteral("new")).toBool(); Q_EMIT newChanged(m_new); } + if (m_favorite != entryQuery.value(QStringLiteral("favorite")).toBool()) { + m_favorite = entryQuery.value(QStringLiteral("favorite")).toBool(); + Q_EMIT favoriteChanged(m_favorite); + } setHasEnclosure(entryQuery.value(QStringLiteral("hasEnclosure")).toBool(), emitSignals); setImage(entryQuery.value(QStringLiteral("image")).toString(), emitSignals); @@ -172,6 +176,11 @@ bool Entry::getNew() const return m_new; } +bool Entry::favorite() const +{ + return m_favorite; +} + QString Entry::baseUrl() const { return QUrl(m_link).adjusted(QUrl::RemovePath).toString(); @@ -340,6 +349,34 @@ void Entry::setNewInternal(bool state) } } +void Entry::setFavorite(bool favorite) +{ + if (favorite != m_favorite) { + // Making a detour through DataManager to make bulk operations more + // performant. DataManager will call setFavoriteInternal on every item to + // be marked new/not new. So implement features there. + DataManager::instance().bulkMarkFavorite(favorite, QStringList(m_id)); + } +} + +void Entry::setFavoriteInternal(bool favorite) +{ + if (favorite != m_favorite) { + // Make sure that operations done here can be wrapped inside an sqlite + // transaction. I.e. no calls that trigger a SELECT operation. + m_favorite = favorite; + Q_EMIT favoriteChanged(m_favorite); + + QSqlQuery query; + query.prepare(QStringLiteral("UPDATE Entries SET favorite=:favorite WHERE id=:id;")); + query.bindValue(QStringLiteral(":id"), m_id); + query.bindValue(QStringLiteral(":favorite"), m_favorite); + Database::instance().execute(query); + + Q_EMIT DataManager::instance().favoriteEntryCountChanged(m_feed->url()); + } +} + QString Entry::adjustedContent(int width, int fontSize) { QString ret(m_content); diff --git a/src/entry.h b/src/entry.h index 95fd1fe3..5378a560 100644 --- a/src/entry.h +++ b/src/entry.h @@ -32,6 +32,7 @@ class Entry : public QObject Q_PROPERTY(QString baseUrl READ baseUrl NOTIFY baseUrlChanged) Q_PROPERTY(bool read READ read WRITE setRead NOTIFY readChanged) Q_PROPERTY(bool new READ getNew WRITE setNew NOTIFY newChanged) + Q_PROPERTY(bool favorite READ favorite WRITE setFavorite NOTIFY favoriteChanged) Q_PROPERTY(Enclosure *enclosure READ enclosure CONSTANT) Q_PROPERTY(bool hasEnclosure READ hasEnclosure NOTIFY hasEnclosureChanged) Q_PROPERTY(QString image READ image NOTIFY imageChanged) @@ -51,6 +52,7 @@ public: QString link() const; bool read() const; bool getNew() const; + bool favorite() const; Enclosure *enclosure() const; bool hasEnclosure() const; QString image() const; @@ -62,12 +64,14 @@ public: void setRead(bool read); void setNew(bool state); + void setFavorite(bool favorite); void setQueueStatus(bool status); Q_INVOKABLE QString adjustedContent(int width, int fontSize); void setNewInternal(bool state); void setReadInternal(bool read); + void setFavoriteInternal(bool favorite); void setQueueStatusInternal(bool state); Q_SIGNALS: @@ -80,6 +84,7 @@ Q_SIGNALS: void baseUrlChanged(const QString &baseUrl); void readChanged(bool read); void newChanged(bool state); + void favoriteChanged(bool favorite); void hasEnclosureChanged(bool hasEnclosure); void imageChanged(const QString &url); void cachedImageChanged(const QString &imagePath); @@ -106,6 +111,7 @@ private: QString m_link; bool m_read; bool m_new; + bool m_favorite; Enclosure *m_enclosure = nullptr; QString m_image; bool m_hasenclosure = false; diff --git a/src/feed.cpp b/src/feed.cpp index c4da2fdd..79672000 100644 --- a/src/feed.cpp +++ b/src/feed.cpp @@ -215,6 +215,11 @@ int Feed::newEntryCount() const return DataManager::instance().newEntryCount(this); } +int Feed::favoriteEntryCount() const +{ + return DataManager::instance().favoriteEntryCount(this); +} + bool Feed::refreshing() const { return m_refreshing; diff --git a/src/feed.h b/src/feed.h index ac8a1732..58f3520b 100644 --- a/src/feed.h +++ b/src/feed.h @@ -35,6 +35,7 @@ class Feed : public QObject Q_PROPERTY(int entryCount READ entryCount NOTIFY entryCountChanged) Q_PROPERTY(int unreadEntryCount READ unreadEntryCount WRITE setUnreadEntryCount NOTIFY unreadEntryCountChanged) Q_PROPERTY(int newEntryCount READ newEntryCount NOTIFY newEntryCountChanged) + Q_PROPERTY(int favoriteEntryCount READ favoriteEntryCount NOTIFY favoriteEntryCountChanged) Q_PROPERTY(int errorId READ errorId WRITE setErrorId NOTIFY errorIdChanged) Q_PROPERTY(QString errorString READ errorString WRITE setErrorString NOTIFY errorStringChanged) Q_PROPERTY(EntriesProxyModel *entries MEMBER m_entries CONSTANT) @@ -61,6 +62,7 @@ public: int entryCount() const; int unreadEntryCount() const; int newEntryCount() const; + int favoriteEntryCount() const; bool read() const; int errorId() const; QString errorString() const; @@ -97,6 +99,7 @@ Q_SIGNALS: void entryCountChanged(); void unreadEntryCountChanged(); void newEntryCountChanged(); + void favoriteEntryCountChanged(); void errorIdChanged(int &errorId); void errorStringChanged(const QString &errorString); diff --git a/src/models/abstractepisodemodel.cpp b/src/models/abstractepisodemodel.cpp index cabcb877..0fe9f5e1 100644 --- a/src/models/abstractepisodemodel.cpp +++ b/src/models/abstractepisodemodel.cpp @@ -19,6 +19,7 @@ QHash AbstractEpisodeModel::roleNames() const {IdRole, "id"}, {ReadRole, "read"}, {NewRole, "new"}, + {FavoriteRole, "favorite"}, {ContentRole, "content"}, {FeedNameRole, "feedname"}, }; diff --git a/src/models/abstractepisodemodel.h b/src/models/abstractepisodemodel.h index a84825fc..e92ecaa7 100644 --- a/src/models/abstractepisodemodel.h +++ b/src/models/abstractepisodemodel.h @@ -22,6 +22,7 @@ public: IdRole, ReadRole, NewRole, + FavoriteRole, ContentRole, FeedNameRole, }; diff --git a/src/models/abstractepisodeproxymodel.cpp b/src/models/abstractepisodeproxymodel.cpp index c006fd33..a1806d0c 100644 --- a/src/models/abstractepisodeproxymodel.cpp +++ b/src/models/abstractepisodeproxymodel.cpp @@ -40,6 +40,12 @@ bool AbstractEpisodeProxyModel::filterAcceptsRow(int sourceRow, const QModelInde case NotNewFilter: accepted = !sourceModel()->data(index, AbstractEpisodeModel::Roles::NewRole).value(); break; + case FavoriteFilter: + accepted = sourceModel()->data(index, AbstractEpisodeModel::Roles::FavoriteRole).value(); + break; + case NotFavoriteFilter: + accepted = !sourceModel()->data(index, AbstractEpisodeModel::Roles::FavoriteRole).value(); + break; default: accepted = true; break; @@ -94,6 +100,7 @@ void AbstractEpisodeProxyModel::setFilterType(FilterType type) if (type != m_currentFilter) { disconnect(&DataManager::instance(), &DataManager::bulkReadStatusActionFinished, this, nullptr); disconnect(&DataManager::instance(), &DataManager::bulkNewStatusActionFinished, this, nullptr); + disconnect(&DataManager::instance(), &DataManager::bulkFavoriteStatusActionFinished, this, nullptr); beginResetModel(); m_currentFilter = type; @@ -113,6 +120,12 @@ void AbstractEpisodeProxyModel::setFilterType(FilterType type) dynamic_cast(sourceModel())->updateInternalState(); endResetModel(); }); + } else if (type == FavoriteFilter || type == NotFavoriteFilter) { + connect(&DataManager::instance(), &DataManager::bulkFavoriteStatusActionFinished, this, [this]() { + beginResetModel(); + dynamic_cast(sourceModel())->updateInternalState(); + endResetModel(); + }); } Q_EMIT filterTypeChanged(); @@ -152,6 +165,10 @@ QString AbstractEpisodeProxyModel::getFilterName(FilterType type) const return i18nc("@label:chooser Choice of filter for episode list", "Episodes marked as \"New\""); case FilterType::NotNewFilter: return i18nc("@label:chooser Choice of filter for episode list", "Episodes not marked as \"New\""); + case FilterType::FavoriteFilter: + return i18nc("@label:chooser Choice of filter for episode list", "Episodes marked as Favorite"); + case FilterType::NotFavoriteFilter: + return i18nc("@label:chooser Choice of filter for episode list", "Episodes not marked as Favorite"); default: return QString(); } diff --git a/src/models/abstractepisodeproxymodel.h b/src/models/abstractepisodeproxymodel.h index 6b93a9f2..bb50d838 100644 --- a/src/models/abstractepisodeproxymodel.h +++ b/src/models/abstractepisodeproxymodel.h @@ -25,6 +25,8 @@ public: NotReadFilter, NewFilter, NotNewFilter, + FavoriteFilter, + NotFavoriteFilter, }; Q_ENUM(FilterType) diff --git a/src/models/downloadmodel.cpp b/src/models/downloadmodel.cpp index 10769eb5..da8b8a43 100644 --- a/src/models/downloadmodel.cpp +++ b/src/models/downloadmodel.cpp @@ -38,6 +38,7 @@ QHash DownloadModel::roleNames() const {EpisodeModel::Roles::IdRole, "id"}, {EpisodeModel::Roles::ReadRole, "read"}, {EpisodeModel::Roles::NewRole, "new"}, + {EpisodeModel::Roles::FavoriteRole, "favorite"}, }; } diff --git a/src/models/entriesmodel.cpp b/src/models/entriesmodel.cpp index 8d22f6bf..ee73b442 100644 --- a/src/models/entriesmodel.cpp +++ b/src/models/entriesmodel.cpp @@ -42,6 +42,8 @@ QVariant EntriesModel::data(const QModelIndex &index, int role) const return QVariant::fromValue(entry->read()); case AbstractEpisodeModel::Roles::NewRole: return QVariant::fromValue(entry->getNew()); + case AbstractEpisodeModel::Roles::FavoriteRole: + return QVariant::fromValue(entry->favorite()); case AbstractEpisodeModel::Roles::ContentRole: return QVariant::fromValue(entry->content()); case AbstractEpisodeModel::Roles::FeedNameRole: diff --git a/src/models/episodemodel.cpp b/src/models/episodemodel.cpp index 8e39ecc1..6f3db14e 100644 --- a/src/models/episodemodel.cpp +++ b/src/models/episodemodel.cpp @@ -41,6 +41,8 @@ QVariant EpisodeModel::data(const QModelIndex &index, int role) const return QVariant::fromValue(m_read[index.row()]); case AbstractEpisodeModel::Roles::NewRole: return QVariant::fromValue(m_new[index.row()]); + case AbstractEpisodeModel::Roles::FavoriteRole: + return QVariant::fromValue(m_favorite[index.row()]); case AbstractEpisodeModel::Roles::ContentRole: return QVariant::fromValue(m_contents[index.row()]); case AbstractEpisodeModel::Roles::FeedNameRole: @@ -61,17 +63,19 @@ void EpisodeModel::updateInternalState() m_entryIds.clear(); m_read.clear(); m_new.clear(); + m_favorite.clear(); m_titles.clear(); m_contents.clear(); m_feedNames.clear(); QSqlQuery query; - query.prepare(QStringLiteral("SELECT id, read, new, title, content, feed FROM Entries ORDER BY updated DESC;")); + query.prepare(QStringLiteral("SELECT id, read, new, favorite, title, content, feed FROM Entries ORDER BY updated DESC;")); Database::instance().execute(query); while (query.next()) { m_entryIds += query.value(QStringLiteral("id")).toString(); m_read += query.value(QStringLiteral("read")).toBool(); m_new += query.value(QStringLiteral("new")).toBool(); + m_favorite += query.value(QStringLiteral("favorite")).toBool(); m_titles += query.value(QStringLiteral("title")).toString(); m_contents += query.value(QStringLiteral("content")).toString(); m_feedNames += DataManager::instance().getFeed(query.value(QStringLiteral("feed")).toString())->name(); diff --git a/src/models/episodemodel.h b/src/models/episodemodel.h index dfd080d5..13930627 100644 --- a/src/models/episodemodel.h +++ b/src/models/episodemodel.h @@ -35,6 +35,7 @@ private: QStringList m_entryIds; QVector m_read; QVector m_new; + QVector m_favorite; QStringList m_titles; QStringList m_contents; QStringList m_feedNames; diff --git a/src/qml/EntryPage.qml b/src/qml/EntryPage.qml index 474c8474..46f0c2df 100644 --- a/src/qml/EntryPage.qml +++ b/src/qml/EntryPage.qml @@ -206,6 +206,14 @@ Kirigami.ScrollablePage { entry.new = !entry.new } }, + Kirigami.Action { + text: entry.favorite ? i18nc("@action:intoolbar Button to remove the \"favorite\" property of a podcast episode", "Remove from Favorites") : i18nc("@action:intoolbar Button to add a podcast episode as favorite", "Add to Favorites") + icon.name: !entry.favorite ? "starred-symbolic" : "non-starred-symbolic" + displayHint: Kirigami.DisplayHint.AlwaysHide + onTriggered: { + entry.favorite = !entry.favorite + } + }, Kirigami.Action { text: i18nc("@action:intoolbar Button to open the podcast URL in browser", "Open Podcast") displayHint: Kirigami.DisplayHint.AlwaysHide diff --git a/src/qml/GenericEntryDelegate.qml b/src/qml/GenericEntryDelegate.qml index 8d878760..4b8a6714 100644 --- a/src/qml/GenericEntryDelegate.qml +++ b/src/qml/GenericEntryDelegate.qml @@ -180,6 +180,13 @@ Kirigami.SwipeListItem { visible: entry ? entry.new : false opacity: 0.7 } + Kirigami.Icon { + Layout.maximumHeight: 0.8 * supertitle.implicitHeight + Layout.maximumWidth: 0.8 * supertitle.implicitHeight + source: "starred-symbolic" + visible: entry ? (entry.favorite) : false + opacity: 0.7 + } Kirigami.Icon { Layout.maximumHeight: 0.8 * supertitle.implicitHeight Layout.maximumWidth: 0.8 * supertitle.implicitHeight @@ -189,7 +196,7 @@ Kirigami.SwipeListItem { } Controls.Label { id: supertitle - text: entry ? ((!isQueue && entry.queueStatus ? "· " : "") + entry.updated.toLocaleDateString(Qt.locale(), Locale.NarrowFormat) + (entry.enclosure ? ( entry.enclosure.size !== 0 ? " · " + entry.enclosure.formattedSize : "") : "" )) : "" + text: entry ? (((!isQueue && entry.queueStatus) || entry.favorite ? "· " : "") + entry.updated.toLocaleDateString(Qt.locale(), Locale.NarrowFormat) + (entry.enclosure ? ( entry.enclosure.size !== 0 ? " · " + entry.enclosure.formattedSize : "") : "" )) : "" Layout.fillWidth: true elide: Text.ElideRight font: Kirigami.Theme.smallFont diff --git a/src/qml/GenericEntryListView.qml b/src/qml/GenericEntryListView.qml index a2702ca5..4064244f 100644 --- a/src/qml/GenericEntryListView.qml +++ b/src/qml/GenericEntryListView.qml @@ -193,6 +193,24 @@ ListView { } } + property var markFavoriteAction: Kirigami.Action { + text: i18nc("@action:intoolbar Button to add a podcast episode as favorite", "Add to Favorites") + icon.name: "starred-symbolic" + visible: listView.selectionModel.hasSelection && (singleSelectedEntry ? !singleSelectedEntry.favorite : true) + onTriggered: { + DataManager.bulkMarkFavoriteByIndex(true, selectionForContextMenu); + } + } + + property var markNotFavoriteAction: Kirigami.Action { + text: i18nc("@action:intoolbar Button to remove the \"favorite\" property of a podcast episode", "Remove from Favorites") + icon.name: "non-starred-symbolic" + visible: listView.selectionModel.hasSelection && (singleSelectedEntry ? singleSelectedEntry.favorite : true) + onTriggered: { + DataManager.bulkMarkFavoriteByIndex(false, selectionForContextMenu); + } + } + property var downloadEnclosureAction: Kirigami.Action { text: i18n("Download") icon.name: "download" @@ -231,6 +249,8 @@ ListView { markNotPlayedAction, markNewAction, markNotNewAction, + markFavoriteAction, + markNotFavoriteAction, downloadEnclosureAction, deleteEnclosureAction, streamAction, @@ -270,6 +290,16 @@ ListView { visible: singleSelectedEntry ? singleSelectedEntry.new : true height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style } + Controls.MenuItem { + action: listView.markFavoriteAction + visible: singleSelectedEntry ? !singleSelectedEntry.favorite : true + height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style + } + Controls.MenuItem { + action: listView.markNotFavoriteAction + visible: singleSelectedEntry ? singleSelectedEntry.favorite : true + height: visible ? implicitHeight : 0 // workaround for qqc2-breeze-style + } Controls.MenuItem { action: listView.downloadEnclosureAction visible: singleSelectedEntry ? (singleSelectedEntry.hasEnclosure ? singleSelectedEntry.enclosure.status !== Enclosure.Downloaded : false) : true diff --git a/src/qml/SearchFilterBar.qml b/src/qml/SearchFilterBar.qml index fa58f425..2802b943 100644 --- a/src/qml/SearchFilterBar.qml +++ b/src/qml/SearchFilterBar.qml @@ -113,7 +113,9 @@ Controls.Control { AbstractEpisodeProxyModel.ReadFilter, AbstractEpisodeProxyModel.NotReadFilter, AbstractEpisodeProxyModel.NewFilter, - AbstractEpisodeProxyModel.NotNewFilter] + AbstractEpisodeProxyModel.NotNewFilter, + AbstractEpisodeProxyModel.FavoriteFilter, + AbstractEpisodeProxyModel.NotFavoriteFilter] for (var i in filterList) { filterModel.append({"name": proxyModel.getFilterName(filterList[i]), "filterType": filterList[i]}); diff --git a/src/updatefeedjob.cpp b/src/updatefeedjob.cpp index 033f11dc..4814c839 100644 --- a/src/updatefeedjob.cpp +++ b/src/updatefeedjob.cpp @@ -490,7 +490,7 @@ void UpdateFeedJob::writeToDatabase() // new entries writeQuery.prepare( - QStringLiteral("INSERT INTO Entries VALUES (:feed, :id, :title, :content, :created, :updated, :link, :read, :new, :hasEnclosure, :image);")); + QStringLiteral("INSERT INTO Entries VALUES (:feed, :id, :title, :content, :created, :updated, :link, :read, :new, :hasEnclosure, :image, :favorite);")); for (const EntryDetails &entryDetails : m_newEntries) { writeQuery.bindValue(QStringLiteral(":feed"), entryDetails.feed); writeQuery.bindValue(QStringLiteral(":id"), entryDetails.id); @@ -503,6 +503,7 @@ void UpdateFeedJob::writeToDatabase() writeQuery.bindValue(QStringLiteral(":read"), entryDetails.read); writeQuery.bindValue(QStringLiteral(":new"), entryDetails.isNew); writeQuery.bindValue(QStringLiteral(":image"), entryDetails.image); + writeQuery.bindValue(QStringLiteral(":favorite"), false); Database::execute(writeQuery); }