diff --git a/resources/sql.qrc b/resources/sql.qrc index 632398b4d..b2b3b136b 100644 --- a/resources/sql.qrc +++ b/resources/sql.qrc @@ -2,8 +2,10 @@ sql/db_init_mysql.sql sql/db_update_mysql_1_2.sql + sql/db_update_mysql_2_3.sql sql/db_init_sqlite.sql sql/db_update_sqlite_1_2.sql + sql/db_update_sqlite_2_3.sql \ No newline at end of file diff --git a/resources/sql/db_init_sqlite.sql b/resources/sql/db_init_sqlite.sql index 867eb8ab8..c6d1b4590 100644 --- a/resources/sql/db_init_sqlite.sql +++ b/resources/sql/db_init_sqlite.sql @@ -40,7 +40,7 @@ CREATE TABLE Feeds ( category INTEGER NOT NULL CHECK (category >= -1), /* Physical category ID, also root feeds contain -1 here. */ source TEXT, update_type INTEGER NOT NULL CHECK (update_type >= 0), - update_interval INTEGER NOT NULL DEFAULT 15 CHECK (update_interval >= 1), + update_interval INTEGER NOT NULL DEFAULT 900 CHECK (update_interval >= 1), is_off INTEGER NOT NULL DEFAULT 0 CHECK (is_off >= 0 AND is_off <= 1), open_articles INTEGER NOT NULL DEFAULT 0 CHECK (open_articles >= 0 AND open_articles <= 1), account_id INTEGER NOT NULL, diff --git a/src/librssguard/core/feeddownloader.cpp b/src/librssguard/core/feeddownloader.cpp index 09d71b61c..234b01b36 100644 --- a/src/librssguard/core/feeddownloader.cpp +++ b/src/librssguard/core/feeddownloader.cpp @@ -69,6 +69,8 @@ void FeedDownloader::updateFeeds(const QList& feeds) { m_feedsOriginalCount = m_feeds.size(); m_feedsUpdated = 0; + const QDateTime update_time = QDateTime::currentDateTimeUtc(); + if (feeds.isEmpty()) { qDebugNN << LOGSEC_FEEDDOWNLOADER << "No feeds to update in worker thread, aborting update."; } @@ -157,6 +159,8 @@ void FeedDownloader::updateFeeds(const QList& feeds) { else { updateOneFeed(n_r, n_f, stated_messages.value(n_r).value(n_f->customId()), tagged_messages.value(n_r)); } + + n_f->setLastUpdated(QDateTime::currentDateTimeUtc()); } } diff --git a/src/librssguard/core/feedsmodel.cpp b/src/librssguard/core/feedsmodel.cpp index 2f119bfa2..7e55ca47b 100644 --- a/src/librssguard/core/feedsmodel.cpp +++ b/src/librssguard/core/feedsmodel.cpp @@ -260,18 +260,8 @@ QList FeedsModel::feedsForScheduledUpdate(bool auto_update_now) { case Feed::AutoUpdateType::SpecificAutoUpdate: default: - int remaining_interval = feed->autoUpdateRemainingInterval(); - - if (--remaining_interval <= 0) { - // Interval of this feed passed, include this feed in the output list - // and reset the interval. + if (feed->lastUpdated().addSecs(feed->autoUpdateInterval()) < QDateTime::currentDateTimeUtc()) { feeds_for_update.append(feed); - feed->setAutoUpdateRemainingInterval(feed->autoUpdateInitialInterval()); - } - else { - // Interval did not pass, set new decremented interval and do NOT - // include this feed in the output list. - feed->setAutoUpdateRemainingInterval(remaining_interval); } break; diff --git a/src/librssguard/database/databasequeries.cpp b/src/librssguard/database/databasequeries.cpp index f83aa101c..120da5085 100644 --- a/src/librssguard/database/databasequeries.cpp +++ b/src/librssguard/database/databasequeries.cpp @@ -2068,7 +2068,7 @@ void DatabaseQueries::createOverwriteFeed(const QSqlDatabase& db, Feed* feed, in q.bindValue(QSL(":category"), new_parent_id); q.bindValue(QSL(":source"), feed->source()); q.bindValue(QSL(":update_type"), int(feed->autoUpdateType())); - q.bindValue(QSL(":update_interval"), feed->autoUpdateInitialInterval()); + q.bindValue(QSL(":update_interval"), feed->autoUpdateInterval()); q.bindValue(QSL(":account_id"), account_id); q.bindValue(QSL(":custom_id"), feed->customId()); q.bindValue(QSL(":id"), feed->id()); diff --git a/src/librssguard/database/databasequeries.h b/src/librssguard/database/databasequeries.h index eebe91204..014aba460 100644 --- a/src/librssguard/database/databasequeries.h +++ b/src/librssguard/database/databasequeries.h @@ -304,7 +304,7 @@ Assignment DatabaseQueries::getFeeds(const QSqlDatabase& db, feed->setCreationDate(TextFactory::parseDateTime(query.value(FDS_DB_DCREATED_INDEX).value())); feed->setIcon(qApp->icons()->fromByteArray(query.value(FDS_DB_ICON_INDEX).toByteArray())); feed->setAutoUpdateType(static_cast(query.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); - feed->setAutoUpdateInitialInterval(query.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); + feed->setAutoUpdateInterval(query.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); feed->setIsSwitchedOff(query.value(FDS_DB_IS_OFF_INDEX).toBool()); feed->setOpenArticlesDirectly(query.value(FDS_DB_OPEN_ARTICLES_INDEX).toBool()); diff --git a/src/librssguard/definitions/definitions.h b/src/librssguard/definitions/definitions.h index 4a7dd2cd2..46b773ed9 100644 --- a/src/librssguard/definitions/definitions.h +++ b/src/librssguard/definitions/definitions.h @@ -73,9 +73,9 @@ #define FEEDS_VIEW_COLUMN_COUNT 2 #define DEFAULT_DAYS_TO_DELETE_MSG 14 #define ELLIPSIS_LENGTH 3 -#define DEFAULT_AUTO_UPDATE_INTERVAL 15 -#define AUTO_UPDATE_INTERVAL 60000 -#define STARTUP_UPDATE_DELAY 15.0 // In seconds. +#define DEFAULT_AUTO_UPDATE_INTERVAL 900 // In seconds. +#define AUTO_UPDATE_INTERVAL 10 // In seconds. +#define STARTUP_UPDATE_DELAY 15.0 // In seconds. #define TIMEZONE_OFFSET_LIMIT 6 #define CHANGE_EVENT_DELAY 250 #define FLAG_ICON_SUBFOLDER "flags" @@ -370,6 +370,7 @@ #endif #define NONQUOTE_W_SPACE_DOT(x) " " << (x) << "." +#define NONQUOTE_W_SPACE(x) " " << (x) << " " #define QUOTE_W_SPACE_DOT(x) " '" << (x) << "'." #define QUOTE_W_SPACE_COMMA(x) " '" << (x) << "'," #define QUOTE_W_SPACE(x) " '" << (x) << "' " diff --git a/src/librssguard/gui/settings/settingsfeedsmessages.cpp b/src/librssguard/gui/settings/settingsfeedsmessages.cpp index bdc743949..785c94ecc 100644 --- a/src/librssguard/gui/settings/settingsfeedsmessages.cpp +++ b/src/librssguard/gui/settings/settingsfeedsmessages.cpp @@ -20,6 +20,7 @@ SettingsFeedsMessages::SettingsFeedsMessages(Settings* settings, QWidget* parent : SettingsPanel(settings, parent), m_ui(new Ui::SettingsFeedsMessages) { m_ui->setupUi(this); + m_ui->m_spinAutoUpdateInterval->setMode(TimeSpinBox::Mode::MinutesSeconds); m_ui->m_spinStartupUpdateDelay->setMode(TimeSpinBox::Mode::MinutesSeconds); initializeMessageDateFormats(); diff --git a/src/librssguard/miscellaneous/feedreader.cpp b/src/librssguard/miscellaneous/feedreader.cpp index e3a045559..73f4c04ff 100644 --- a/src/librssguard/miscellaneous/feedreader.cpp +++ b/src/librssguard/miscellaneous/feedreader.cpp @@ -27,25 +27,26 @@ #include FeedReader::FeedReader(QObject* parent) - : QObject(parent), - m_autoUpdateTimer(new QTimer(this)), m_feedDownloader(nullptr) { + : QObject(parent), m_autoUpdateTimer(new QTimer(this)), m_feedDownloader(nullptr) { m_feedsModel = new FeedsModel(this); m_feedsProxyModel = new FeedsProxyModel(m_feedsModel, this); m_messagesModel = new MessagesModel(this); m_messagesProxyModel = new MessagesProxyModel(m_messagesModel, this); - connect(m_autoUpdateTimer, &QTimer::timeout, this, &FeedReader::executeNextAutoUpdate); updateAutoUpdateStatus(); initializeFeedDownloader(); if (qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::FeedsUpdateOnStartup)).toBool()) { - qDebugNN << LOGSEC_CORE - << "Requesting update for all feeds on application startup."; + qDebugNN << LOGSEC_CORE << "Requesting update for all feeds on application startup."; QTimer::singleShot(qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::FeedsUpdateStartupDelay)).toDouble() * 1000, this, [this]() { - updateFeeds(m_feedsModel->rootItem()->getSubAutoFetchingEnabledFeeds()); - }); + updateFeeds(m_feedsModel->rootItem()->getSubAutoFetchingEnabledFeeds()); + connect(m_autoUpdateTimer, &QTimer::timeout, this, &FeedReader::executeNextAutoUpdate); + }); + } + else { + connect(m_autoUpdateTimer, &QTimer::timeout, this, &FeedReader::executeNextAutoUpdate); } } @@ -85,20 +86,22 @@ void FeedReader::updateFeeds(const QList& feeds) { } if (!qApp->feedUpdateLock()->tryLock()) { - qApp->showGuiMessage(Notification::Event::GeneralEvent, { - tr("Cannot fetch articles at this point"), - tr("You cannot fetch new articles now because another critical operation is ongoing."), - QSystemTrayIcon::MessageIcon::Warning }); + qApp->showGuiMessage(Notification::Event::GeneralEvent, + {tr("Cannot fetch articles at this point"), + tr("You cannot fetch new articles now because another critical operation is ongoing."), + QSystemTrayIcon::MessageIcon::Warning}); return; } - QMetaObject::invokeMethod(m_feedDownloader, "updateFeeds", + QMetaObject::invokeMethod(m_feedDownloader, + "updateFeeds", Qt::ConnectionType::QueuedConnection, Q_ARG(QList, my_feeds)); } void FeedReader::synchronizeMessageData(const QList& caches) { - QMetaObject::invokeMethod(m_feedDownloader, "synchronizeAccountCaches", + QMetaObject::invokeMethod(m_feedDownloader, + "synchronizeAccountCaches", Qt::ConnectionType::QueuedConnection, Q_ARG(QList, caches), Q_ARG(bool, true)); @@ -128,6 +131,10 @@ void FeedReader::initializeFeedDownloader() { } } +QDateTime FeedReader::lastAutoUpdate() const { + return m_lastAutoUpdate; +} + void FeedReader::showMessageFiltersManager() { FormMessageFiltersManager manager(qApp->feedReader(), qApp->feedReader()->feedsModel()->serviceRoots(), @@ -141,21 +148,24 @@ void FeedReader::showMessageFiltersManager() { void FeedReader::updateAutoUpdateStatus() { // Restore global intervals. // NOTE: Specific per-feed interval are left intact. - m_globalAutoUpdateInitialInterval = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateInterval)).toInt(); - m_globalAutoUpdateRemainingInterval = m_globalAutoUpdateInitialInterval; + m_globalAutoUpdateInterval = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateInterval)).toInt(); + + if (m_lastAutoUpdate.isNull()) { + m_lastAutoUpdate = QDateTime::currentDateTimeUtc(); + } + m_globalAutoUpdateEnabled = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateEnabled)).toBool(); - m_globalAutoUpdateOnlyUnfocused = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateOnlyUnfocused)).toBool(); + m_globalAutoUpdateOnlyUnfocused = + qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::AutoUpdateOnlyUnfocused)).toBool(); // Start global auto-update timer if it is not running yet. // NOTE: The timer must run even if global auto-update // is not enabled because user can still enable auto-update // for individual feeds. if (!m_autoUpdateTimer->isActive()) { - m_autoUpdateTimer->setInterval(AUTO_UPDATE_INTERVAL); + m_autoUpdateTimer->setInterval(AUTO_UPDATE_INTERVAL * 1000); m_autoUpdateTimer->start(); - qDebugNN << LOGSEC_CORE << "Auto-download timer started with interval " - << m_autoUpdateTimer->interval() - << " ms."; + qDebugNN << LOGSEC_CORE << "Auto-download timer started with interval " << m_autoUpdateTimer->interval() << " ms."; } else { qDebugNN << LOGSEC_CORE << "Auto-download timer is already running."; @@ -166,19 +176,16 @@ bool FeedReader::autoUpdateEnabled() const { return m_globalAutoUpdateEnabled; } -int FeedReader::autoUpdateRemainingInterval() const { - return m_globalAutoUpdateRemainingInterval; -} - -int FeedReader::autoUpdateInitialInterval() const { - return m_globalAutoUpdateInitialInterval; +int FeedReader::autoUpdateInterval() const { + return m_globalAutoUpdateInterval; } void FeedReader::loadSavedMessageFilters() { // Load all message filters from database. // All plugin services will hook active filters to // all feeds. - m_messageFilters = DatabaseQueries::getMessageFilters(qApp->database()->driver()->connection(metaObject()->className())); + m_messageFilters = + DatabaseQueries::getMessageFilters(qApp->database()->driver()->connection(metaObject()->className())); for (auto* filter : qAsConst(m_messageFilters)) { filter->setParent(this); @@ -186,7 +193,8 @@ void FeedReader::loadSavedMessageFilters() { } MessageFilter* FeedReader::addMessageFilter(const QString& title, const QString& script) { - auto* fltr = DatabaseQueries::addMessageFilter(qApp->database()->driver()->connection(metaObject()->className()), title, script); + auto* fltr = + DatabaseQueries::addMessageFilter(qApp->database()->driver()->connection(metaObject()->className()), title, script); m_messageFilters.append(fltr); return fltr; @@ -203,7 +211,8 @@ void FeedReader::removeMessageFilter(MessageFilter* filter) { } // Remove from DB. - DatabaseQueries::removeMessageFilterAssignments(qApp->database()->driver()->connection(metaObject()->className()), filter->id()); + DatabaseQueries::removeMessageFilterAssignments(qApp->database()->driver()->connection(metaObject()->className()), + filter->id()); DatabaseQueries::removeMessageFilter(qApp->database()->driver()->connection(metaObject()->className()), filter->id()); // Free from memory as last step. @@ -264,25 +273,25 @@ void FeedReader::executeNextAutoUpdate() { bool disable_update_with_window = qApp->mainFormWidget()->isActiveWindow() && m_globalAutoUpdateOnlyUnfocused; auto roots = qApp->feedReader()->feedsModel()->serviceRoots(); std::list full_caches = boolinq::from(roots) - .select([](ServiceRoot* root) -> CacheForServiceRoot* { - auto* cache = root->toCache(); + .select([](ServiceRoot* root) -> CacheForServiceRoot* { + auto* cache = root->toCache(); - if (cache != nullptr) { - return cache; - } - else { - return nullptr; - } - }) - .where([](CacheForServiceRoot* cache) { - return cache != nullptr && !cache->isEmpty(); - }).toStdList(); + if (cache != nullptr) { + return cache; + } + else { + return nullptr; + } + }) + .where([](CacheForServiceRoot* cache) { + return cache != nullptr && !cache->isEmpty(); + }) + .toStdList(); // Skip this round of auto-updating, but only if user disabled it when main window is active // and there are no caches to synchronize. if (disable_update_with_window && full_caches.empty()) { - qDebugNN << LOGSEC_CORE - << "Delaying scheduled feed auto-download for one minute since window " + qDebugNN << LOGSEC_CORE << "Delaying scheduled feed auto-download for some time since window " << "is focused and updates while focused are disabled by the " << "user and all account caches are empty."; @@ -291,26 +300,13 @@ void FeedReader::executeNextAutoUpdate() { } if (!qApp->feedUpdateLock()->tryLock()) { - qDebugNN << LOGSEC_CORE - << "Delaying scheduled feed auto-downloads and message state synchronization for " + qDebugNN << LOGSEC_CORE << "Delaying scheduled feed auto-downloads and message state synchronization for " << "one minute due to another running update."; // Cannot update, quit. return; } - // If global auto-update is enabled and its interval counter reached zero, - // then we need to restore it. - if (m_globalAutoUpdateEnabled && --m_globalAutoUpdateRemainingInterval < 0) { - // We should start next auto-update interval. - m_globalAutoUpdateRemainingInterval = m_globalAutoUpdateInitialInterval - 1; - } - - qDebugNN << LOGSEC_CORE - << "Starting auto-download event, remaining " - << m_globalAutoUpdateRemainingInterval << " minutes out of " - << m_globalAutoUpdateInitialInterval << " total minutes to next global feed update."; - qApp->feedUpdateLock()->unlock(); // Resynchronize caches. @@ -322,18 +318,29 @@ void FeedReader::executeNextAutoUpdate() { // Pass needed interval data and lets the model decide which feeds // should be updated in this pass. - QList feeds_for_update = m_feedsModel->feedsForScheduledUpdate(m_globalAutoUpdateEnabled && - m_globalAutoUpdateRemainingInterval == 0); + QDateTime current_time = QDateTime::currentDateTimeUtc(); + bool auto_update_now = + m_globalAutoUpdateEnabled && m_lastAutoUpdate.addSecs(m_globalAutoUpdateInterval) < current_time; + + if (auto_update_now) { + qDebugNN << LOGSEC_CORE << "Now it's time to auto-fetch articles because last auto-fetch was on" + << QUOTE_W_SPACE(m_lastAutoUpdate) << "and next should be in" + << NONQUOTE_W_SPACE(m_globalAutoUpdateInterval) << "seconds."; + + m_lastAutoUpdate = current_time; + } + + QList feeds_for_update = m_feedsModel->feedsForScheduledUpdate(auto_update_now); if (!feeds_for_update.isEmpty()) { // Request update for given feeds. updateFeeds(feeds_for_update); // NOTE: OSD/bubble informing about performing of scheduled update can be shown now. - qApp->showGuiMessage(Notification::Event::ArticlesFetchingStarted, { - tr("Starting auto-download of some feeds' articles"), - tr("I will auto-download new articles for %n feed(s).", nullptr, feeds_for_update.size()), - QSystemTrayIcon::MessageIcon::Information }); + qApp->showGuiMessage(Notification::Event::ArticlesFetchingStarted, + {tr("Starting auto-download of some feeds' articles"), + tr("I will auto-download new articles for %n feed(s).", nullptr, feeds_for_update.size()), + QSystemTrayIcon::MessageIcon::Information}); } } diff --git a/src/librssguard/miscellaneous/feedreader.h b/src/librssguard/miscellaneous/feedreader.h index ec42f63ac..be32e0303 100644 --- a/src/librssguard/miscellaneous/feedreader.h +++ b/src/librssguard/miscellaneous/feedreader.h @@ -21,7 +21,7 @@ class QTimer; class QThread; class RSSGUARD_DLLSPEC FeedReader : public QObject { - Q_OBJECT + Q_OBJECT public: explicit FeedReader(QObject* parent = nullptr); @@ -53,8 +53,8 @@ class RSSGUARD_DLLSPEC FeedReader : public QObject { void updateAutoUpdateStatus(); bool autoUpdateEnabled() const; - int autoUpdateRemainingInterval() const; - int autoUpdateInitialInterval() const; + int autoUpdateInterval() const; + QDateTime lastAutoUpdate() const; void loadSavedMessageFilters(); QList messageFilters() const; @@ -93,8 +93,8 @@ class RSSGUARD_DLLSPEC FeedReader : public QObject { QTimer* m_autoUpdateTimer; bool m_globalAutoUpdateEnabled{}; bool m_globalAutoUpdateOnlyUnfocused{}; - int m_globalAutoUpdateInitialInterval{}; - int m_globalAutoUpdateRemainingInterval{}; + int m_globalAutoUpdateInterval{}; // In seconds. + QDateTime m_lastAutoUpdate; QThread* m_feedDownloaderThread; FeedDownloader* m_feedDownloader; }; diff --git a/src/librssguard/services/abstract/feed.cpp b/src/librssguard/services/abstract/feed.cpp index 1c5ef42e2..58838a7cd 100644 --- a/src/librssguard/services/abstract/feed.cpp +++ b/src/librssguard/services/abstract/feed.cpp @@ -21,8 +21,8 @@ Feed::Feed(RootItem* parent) : RootItem(parent), m_source(QString()), m_status(Status::Normal), m_statusString(QString()), - m_autoUpdateType(AutoUpdateType::DefaultAutoUpdate), m_autoUpdateInitialInterval(DEFAULT_AUTO_UPDATE_INTERVAL), - m_autoUpdateRemainingInterval(DEFAULT_AUTO_UPDATE_INTERVAL), m_isSwitchedOff(false), m_openArticlesDirectly(false), + m_autoUpdateType(AutoUpdateType::DefaultAutoUpdate), m_autoUpdateInterval(DEFAULT_AUTO_UPDATE_INTERVAL), + m_lastUpdated(QDateTime::currentDateTimeUtc()), m_isSwitchedOff(false), m_openArticlesDirectly(false), m_messageFilters(QList>()) { setKind(RootItem::Kind::Feed); } @@ -41,8 +41,8 @@ Feed::Feed(const Feed& other) : RootItem(other) { setSource(other.source()); setStatus(other.status(), other.statusString()); setAutoUpdateType(other.autoUpdateType()); - setAutoUpdateInitialInterval(other.autoUpdateInitialInterval()); - setAutoUpdateRemainingInterval(other.autoUpdateRemainingInterval()); + setAutoUpdateInterval(other.autoUpdateInterval()); + setLastUpdated(other.lastUpdated()); setMessageFilters(other.messageFilters()); setOpenArticlesDirectly(other.openArticlesDirectly()); setIsSwitchedOff(other.isSwitchedOff()); @@ -91,8 +91,8 @@ QVariant Feed::data(int column, int role) const { } } -int Feed::autoUpdateInitialInterval() const { - return m_autoUpdateInitialInterval; +int Feed::autoUpdateInterval() const { + return m_autoUpdateInterval; } int Feed::countOfAllMessages() const { @@ -134,11 +134,11 @@ bool Feed::editViaGui() { return false; } -void Feed::setAutoUpdateInitialInterval(int auto_update_interval) { +void Feed::setAutoUpdateInterval(int auto_update_interval) { // If new initial auto-update interval is set, then // we should reset time that remains to the next auto-update. - m_autoUpdateInitialInterval = auto_update_interval; - m_autoUpdateRemainingInterval = auto_update_interval; + m_autoUpdateInterval = auto_update_interval; + m_lastUpdated = QDateTime::currentDateTimeUtc(); } Feed::AutoUpdateType Feed::autoUpdateType() const { @@ -149,14 +149,6 @@ void Feed::setAutoUpdateType(Feed::AutoUpdateType auto_update_type) { m_autoUpdateType = auto_update_type; } -int Feed::autoUpdateRemainingInterval() const { - return m_autoUpdateRemainingInterval; -} - -void Feed::setAutoUpdateRemainingInterval(int auto_update_remaining_interval) { - m_autoUpdateRemainingInterval = auto_update_remaining_interval; -} - Feed::Status Feed::status() const { return m_status; } @@ -219,28 +211,34 @@ QString Feed::getAutoUpdateStatusDescription() const { switch (autoUpdateType()) { case AutoUpdateType::DontAutoUpdate: - //: Describes feed auto-update status. auto_update_string = tr("does not use auto-fetching of articles"); break; case AutoUpdateType::DefaultAutoUpdate: - //: Describes feed auto-update status. - auto_update_string = qApp->feedReader()->autoUpdateEnabled() - ? tr("uses global settings (%n minute(s) to next auto-fetch of articles)", - nullptr, - qApp->feedReader()->autoUpdateRemainingInterval()) - : tr("uses global settings (global auto-fetching of articles is disabled)"); + if (qApp->feedReader()->autoUpdateEnabled()) { + int secs_to_next = + QDateTime::currentDateTimeUtc() + .secsTo(qApp->feedReader()->lastAutoUpdate().addSecs(qApp->feedReader()->autoUpdateInterval())); + + auto_update_string = + tr("uses global settings (%n minute(s) to next auto-fetch of articles)", nullptr, int(secs_to_next / 60.0)); + } + else { + auto_update_string = tr("uses global settings, but global auto-fetching of articles is disabled"); + } + break; case AutoUpdateType::SpecificAutoUpdate: default: + int secs_to_next = QDateTime::currentDateTimeUtc().secsTo(lastUpdated().addSecs(autoUpdateInterval())); //: Describes feed auto-update status. auto_update_string = tr("uses specific settings (%n minute(s) to next auto-fetching of new articles)", nullptr, - autoUpdateRemainingInterval()); + int(secs_to_next / 60.0)); break; } @@ -269,6 +267,14 @@ QString Feed::getStatusDescription() const { } } +QDateTime Feed::lastUpdated() const { + return m_lastUpdated; +} + +void Feed::setLastUpdated(const QDateTime& last_updated) { + m_lastUpdated = last_updated; +} + bool Feed::isSwitchedOff() const { return m_isSwitchedOff; } diff --git a/src/librssguard/services/abstract/feed.h b/src/librssguard/services/abstract/feed.h index 924f3a9a3..cc2195a57 100644 --- a/src/librssguard/services/abstract/feed.h +++ b/src/librssguard/services/abstract/feed.h @@ -53,15 +53,12 @@ class Feed : public RootItem { void setCountOfAllMessages(int count_all_messages); void setCountOfUnreadMessages(int count_unread_messages); - int autoUpdateInitialInterval() const; - void setAutoUpdateInitialInterval(int auto_update_interval); + int autoUpdateInterval() const; + void setAutoUpdateInterval(int auto_update_interval); AutoUpdateType autoUpdateType() const; void setAutoUpdateType(AutoUpdateType auto_update_type); - int autoUpdateRemainingInterval() const; - void setAutoUpdateRemainingInterval(int auto_update_remaining_interval); - Status status() const; QString statusString() const; void setStatus(Feed::Status status, const QString& status_text = {}); @@ -80,6 +77,9 @@ class Feed : public RootItem { void setMessageFilters(const QList>& messageFilters); void removeMessageFilter(MessageFilter* filter); + QDateTime lastUpdated() const; + void setLastUpdated(const QDateTime& last_updated); + public slots: virtual void updateCounts(bool including_total_count); @@ -92,8 +92,8 @@ class Feed : public RootItem { Status m_status; QString m_statusString; AutoUpdateType m_autoUpdateType; - int m_autoUpdateInitialInterval{}; - int m_autoUpdateRemainingInterval{}; + int m_autoUpdateInterval{}; // In seconds. + QDateTime m_lastUpdated; bool m_isSwitchedOff; bool m_openArticlesDirectly; int m_totalCount{}; diff --git a/src/librssguard/services/abstract/gui/formfeeddetails.cpp b/src/librssguard/services/abstract/gui/formfeeddetails.cpp index 4503063c8..76f86a0f9 100644 --- a/src/librssguard/services/abstract/gui/formfeeddetails.cpp +++ b/src/librssguard/services/abstract/gui/formfeeddetails.cpp @@ -44,9 +44,10 @@ void FormFeedDetails::insertCustomTab(QWidget* custom_tab, const QString& title, void FormFeedDetails::apply() { // Setup common data for the feed. - m_feed->setAutoUpdateType(static_cast(m_ui->m_cmbAutoUpdateType->itemData( - m_ui->m_cmbAutoUpdateType->currentIndex()).toInt())); - m_feed->setAutoUpdateInitialInterval(int(m_ui->m_spinAutoUpdateInterval->value())); + m_feed->setAutoUpdateType(static_cast(m_ui->m_cmbAutoUpdateType + ->itemData(m_ui->m_cmbAutoUpdateType->currentIndex()) + .toInt())); + m_feed->setAutoUpdateInterval(int(m_ui->m_spinAutoUpdateInterval->value())); m_feed->setOpenArticlesDirectly(m_ui->m_cbOpenArticlesAutomatically->isChecked()); m_feed->setIsSwitchedOff(m_ui->m_cbDisableFeed->isChecked()); @@ -59,7 +60,8 @@ void FormFeedDetails::apply() { } void FormFeedDetails::onAutoUpdateTypeChanged(int new_index) { - Feed::AutoUpdateType auto_update_type = static_cast(m_ui->m_cmbAutoUpdateType->itemData(new_index).toInt()); + Feed::AutoUpdateType auto_update_type = + static_cast(m_ui->m_cmbAutoUpdateType->itemData(new_index).toInt()); switch (auto_update_type) { case Feed::AutoUpdateType::DontAutoUpdate: @@ -74,7 +76,9 @@ void FormFeedDetails::onAutoUpdateTypeChanged(int new_index) { void FormFeedDetails::createConnections() { connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &FormFeedDetails::acceptIfPossible); - connect(m_ui->m_cmbAutoUpdateType, static_cast(&QComboBox::currentIndexChanged), this, + connect(m_ui->m_cmbAutoUpdateType, + static_cast(&QComboBox::currentIndexChanged), + this, &FormFeedDetails::onAutoUpdateTypeChanged); } @@ -85,13 +89,12 @@ void FormFeedDetails::loadFeedData() { tr("Add new feed")); } else { - GuiUtilities::applyDialogProperties(*this, - m_feed->fullIcon(), - tr("Edit \"%1\"").arg(m_feed->title())); + GuiUtilities::applyDialogProperties(*this, m_feed->fullIcon(), tr("Edit \"%1\"").arg(m_feed->title())); } - m_ui->m_cmbAutoUpdateType->setCurrentIndex(m_ui->m_cmbAutoUpdateType->findData(QVariant::fromValue(int(m_feed->autoUpdateType())))); - m_ui->m_spinAutoUpdateInterval->setValue(m_feed->autoUpdateInitialInterval()); + m_ui->m_cmbAutoUpdateType + ->setCurrentIndex(m_ui->m_cmbAutoUpdateType->findData(QVariant::fromValue(int(m_feed->autoUpdateType())))); + m_ui->m_spinAutoUpdateInterval->setValue(m_feed->autoUpdateInterval()); m_ui->m_cbOpenArticlesAutomatically->setChecked(m_feed->openArticlesDirectly()); m_ui->m_cbDisableFeed->setChecked(m_feed->isSwitchedOff()); } @@ -102,11 +105,12 @@ void FormFeedDetails::acceptIfPossible() { accept(); } catch (const ApplicationException& ex) { - qApp->showGuiMessage(Notification::Event::GeneralEvent, { - tr("Cannot save feed properties"), - tr("Cannot save changes: %1").arg(ex.message()), - QSystemTrayIcon::MessageIcon::Critical }, - {}, {}, + qApp->showGuiMessage(Notification::Event::GeneralEvent, + {tr("Cannot save feed properties"), + tr("Cannot save changes: %1").arg(ex.message()), + QSystemTrayIcon::MessageIcon::Critical}, + {}, + {}, this); } } @@ -116,6 +120,7 @@ void FormFeedDetails::initialize() { m_ui->setupUi(this); // Setup auto-update options. + m_ui->m_spinAutoUpdateInterval->setMode(TimeSpinBox::Mode::MinutesSeconds); m_ui->m_spinAutoUpdateInterval->setValue(DEFAULT_AUTO_UPDATE_INTERVAL); m_ui->m_cmbAutoUpdateType->addItem(tr("Fetch articles using global interval"), QVariant::fromValue(int(Feed::AutoUpdateType::DefaultAutoUpdate))); diff --git a/src/librssguard/services/abstract/serviceroot.cpp b/src/librssguard/services/abstract/serviceroot.cpp index 9be752c5b..794a626b3 100644 --- a/src/librssguard/services/abstract/serviceroot.cpp +++ b/src/librssguard/services/abstract/serviceroot.cpp @@ -380,7 +380,7 @@ QMap ServiceRoot::storeCustomFeedsData() { // TODO: This could potentially call Feed::customDatabaseData() and append it // to this map and also subsequently restore. - feed_custom_data.insert(QSL("auto_update_interval"), feed->autoUpdateInitialInterval()); + feed_custom_data.insert(QSL("auto_update_interval"), feed->autoUpdateInterval()); feed_custom_data.insert(QSL("auto_update_type"), int(feed->autoUpdateType())); feed_custom_data.insert(QSL("msg_filters"), QVariant::fromValue(feed->messageFilters())); feed_custom_data.insert(QSL("is_off"), feed->isSwitchedOff()); @@ -403,7 +403,7 @@ void ServiceRoot::restoreCustomFeedsData(const QMap& data, Feed* feed = feeds.value(custom_id); QVariantMap feed_custom_data = i.value(); - feed->setAutoUpdateInitialInterval(feed_custom_data.value(QSL("auto_update_interval")).toInt()); + feed->setAutoUpdateInterval(feed_custom_data.value(QSL("auto_update_interval")).toInt()); feed ->setAutoUpdateType(static_cast(feed_custom_data.value(QSL("auto_update_type")).toInt())); feed->setMessageFilters(feed_custom_data.value(QSL("msg_filters")).value>>());