diff options
| author | Andrew Branson <andrew.branson@jolla.com> | 2026-03-27 18:20:03 +0100 |
|---|---|---|
| committer | Andrew Branson <andrew.branson@jolla.com> | 2026-03-27 18:20:03 +0100 |
| commit | fd2fac203d3ffd8770c2ed60dedbd7b0777e0e32 (patch) | |
| tree | 2ee6b34e53338e44fe91902c8786a869f77bc29f | |
| parent | 2b1a3046832074e47ad2ad703cd518526b9fb459 (diff) | |
2 files changed, 93 insertions, 3 deletions
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.cpp b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.cpp index 8d21782..98dbbc8 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.cpp +++ b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.cpp @@ -57,6 +57,7 @@ namespace { const char *const NotificationIdHint = "x-nemo.sociald.notification-id"; const char *const LastFetchedNotificationIdKey = "LastFetchedNotificationId"; const int NotificationsPageLimit = 80; + const uint NotificationDismissedReason = 1; //% "mentioned you" const char *const TrIdMentionedYou = QT_TRID_NOOP("lipstick-jolla-home-la-mastodon-notification-mentioned_you"); @@ -240,13 +241,14 @@ namespace { return QString(); } - bool hasActiveNotificationsForAccount(int accountId) + bool hasActiveNotificationsForAccount(int accountId, const Notification *ignoredNotification = 0) { bool hasActiveNotifications = false; const QList<QObject *> notifications = Notification::notifications(); foreach (QObject *object, notifications) { Notification *notification = qobject_cast<Notification *>(object); if (notification + && notification != ignoredNotification && notification->category() == QLatin1String(NotificationCategory) && notification->hintValue("x-nemo.sociald.account-id").toInt() == accountId) { hasActiveNotifications = true; @@ -312,6 +314,7 @@ void MastodonNotificationsSyncAdaptor::purgeDataForOldAccount(int oldId, SocialN { closeAccountNotifications(oldId); + m_accessTokens.remove(oldId); m_pendingSyncStates.remove(oldId); m_lastMarkedReadIds.remove(oldId); saveLastFetchedId(oldId, QString()); @@ -319,6 +322,7 @@ void MastodonNotificationsSyncAdaptor::purgeDataForOldAccount(int oldId, SocialN void MastodonNotificationsSyncAdaptor::beginSync(int accountId, const QString &accessToken) { + m_accessTokens.insert(accountId, accessToken); m_pendingSyncStates.remove(accountId); requestUnreadMarker(accountId, accessToken); } @@ -465,6 +469,7 @@ void MastodonNotificationsSyncAdaptor::finishedUnreadMarkerHandler() PendingSyncState state; state.accessToken = accessToken; + state.markerKnown = true; state.unreadFloorId = markerId; state.lastFetchedId = loadLastFetchedId(accountId); if (state.lastFetchedId.isEmpty() && !markerId.isEmpty()) { @@ -576,6 +581,9 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler() if (!isError && ok) { if (!notifications.size()) { qCDebug(lcMastodonNotifications) << "no notifications received for account" << accountId; + if (state.markerKnown) { + closeAccountNotifications(accountId); + } m_pendingSyncStates.remove(accountId); decrementSemaphore(accountId); return; @@ -599,6 +607,10 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler() pageMinNotificationId = notificationId; } + if (state.markerKnown) { + state.unreadNotificationIds.insert(notificationId); + } + if (state.maxFetchedId.isEmpty() || compareNotificationIds(notificationId, state.maxFetchedId) > 0) { state.maxFetchedId = notificationId; @@ -703,6 +715,10 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler() } } + if (state.markerKnown) { + closeAccountNotifications(accountId, state.unreadNotificationIds); + } + if (!state.maxFetchedId.isEmpty() && (state.lastFetchedId.isEmpty() || compareNotificationIds(state.maxFetchedId, state.lastFetchedId) > 0)) { @@ -715,10 +731,10 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler() const QString currentMarkerId = m_lastMarkedReadIds.value(accountId); if (!markerId.isEmpty() && !state.accessToken.isEmpty() - && !hasActiveNotificationsForAccount(accountId) + && state.markerKnown && (currentMarkerId.isEmpty() || compareNotificationIds(markerId, currentMarkerId) > 0)) { - requestMarkRead(accountId, state.accessToken, markerId); + maybeMarkAccountNotificationsRead(accountId, state.accessToken); } } else { qCWarning(lcMastodonNotifications) << "unable to parse notifications data from request with account" << accountId @@ -795,6 +811,70 @@ void MastodonNotificationsSyncAdaptor::publishSystemNotification(int accountId, } } +void MastodonNotificationsSyncAdaptor::notificationClosedWithReason(uint reason) +{ + Notification *notification = qobject_cast<Notification *>(sender()); + removeCachedNotification(notification); + if (reason == NotificationDismissedReason) { + markReadFromNotification(notification); + } +} + +void MastodonNotificationsSyncAdaptor::maybeMarkAccountNotificationsRead(int accountId, + const QString &accessToken, + Notification *ignoredNotification) +{ + if (accountId <= 0 || accessToken.isEmpty()) { + return; + } + + if (hasActiveNotificationsForAccount(accountId, ignoredNotification)) { + return; + } + + const QString lastReadId = loadLastFetchedId(accountId); + if (lastReadId.isEmpty()) { + return; + } + + const QString currentMarkerId = m_lastMarkedReadIds.value(accountId); + if (!currentMarkerId.isEmpty() && compareNotificationIds(lastReadId, currentMarkerId) <= 0) { + return; + } + + requestMarkRead(accountId, accessToken, lastReadId); +} + +void MastodonNotificationsSyncAdaptor::markReadFromNotification(Notification *notification) +{ + if (!notification) { + return; + } + + const int accountId = notification->hintValue("x-nemo.sociald.account-id").toInt(); + const QString accessToken = m_accessTokens.value(accountId).trimmed(); + if (accountId <= 0 || accessToken.isEmpty()) { + return; + } + + maybeMarkAccountNotificationsRead(accountId, accessToken, notification); +} + +void MastodonNotificationsSyncAdaptor::removeCachedNotification(Notification *notification) +{ + if (!notification) { + return; + } + + const int accountId = notification->hintValue("x-nemo.sociald.account-id").toInt(); + const QString notificationId = notification->hintValue(NotificationIdHint).toString(); + if (accountId <= 0 || notificationId.isEmpty()) { + return; + } + + m_notificationObjects.remove(notificationObjectKey(accountId, notificationId)); +} + void MastodonNotificationsSyncAdaptor::closeAccountNotifications(int accountId, const QSet<QString> &keepNotificationIds) { @@ -859,6 +939,7 @@ Notification *MastodonNotificationsSyncAdaptor::createNotification(int accountId notification->setHintValue("x-nemo-priority", 100); // Show on lockscreen notification->setCategory(QLatin1String(NotificationCategory)); + connect(notification, SIGNAL(closed(uint)), this, SLOT(notificationClosedWithReason(uint)), Qt::UniqueConnection); m_notificationObjects.insert(objectKey, notification); return notification; diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.h b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.h index 4c667fa..0e9106c 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.h +++ b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.h @@ -57,9 +57,11 @@ private: struct PendingSyncState { QString accessToken; + bool markerKnown = false; QString unreadFloorId; QString lastFetchedId; QString maxFetchedId; + QSet<QString> unreadNotificationIds; QHash<QString, PendingNotification> pendingNotifications; }; @@ -80,13 +82,20 @@ private: Notification *findNotification(int accountId, const QString ¬ificationId); void closeAccountNotifications(int accountId, const QSet<QString> &keepNotificationIds = QSet<QString>()); static QString notificationObjectKey(int accountId, const QString ¬ificationId); + void maybeMarkAccountNotificationsRead(int accountId, + const QString &accessToken, + Notification *ignoredNotification = 0); + void markReadFromNotification(Notification *notification); + void removeCachedNotification(Notification *notification); private Q_SLOTS: void finishedUnreadMarkerHandler(); void finishedNotificationsHandler(); void finishedMarkReadHandler(); + void notificationClosedWithReason(uint reason); private: + QHash<int, QString> m_accessTokens; QHash<int, PendingSyncState> m_pendingSyncStates; QHash<int, QString> m_lastMarkedReadIds; QHash<QString, Notification *> m_notificationObjects; |
