diff options
Diffstat (limited to 'buteo-plugins')
11 files changed, 121 insertions, 7 deletions
diff --git a/buteo-plugins/buteo-common/buteo-common.pri b/buteo-plugins/buteo-common/buteo-common.pri index 192da35..83452ac 100644 --- a/buteo-plugins/buteo-common/buteo-common.pri +++ b/buteo-plugins/buteo-common/buteo-common.pri @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. +# +# SPDX-License-Identifier: BSD-3-Clause + INCLUDEPATH += $$PWD DEPENDPATH += . diff --git a/buteo-plugins/buteo-common/buteo-common.pro b/buteo-plugins/buteo-common/buteo-common.pro index c1aa569..c0b84a9 100644 --- a/buteo-plugins/buteo-common/buteo-common.pro +++ b/buteo-plugins/buteo-common/buteo-common.pro @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. +# +# SPDX-License-Identifier: BSD-3-Clause + TEMPLATE = lib TARGET = mastodonbuteocommon diff --git a/buteo-plugins/buteo-plugins.pro b/buteo-plugins/buteo-plugins.pro index 179aebf..ead60e6 100644 --- a/buteo-plugins/buteo-plugins.pro +++ b/buteo-plugins/buteo-plugins.pro @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. +# +# SPDX-License-Identifier: BSD-3-Clause + TEMPLATE = subdirs SUBDIRS += \ buteo-common \ diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/buteo-sync-plugin-mastodon-notifications.pro b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/buteo-sync-plugin-mastodon-notifications.pro index 3289487..d16cc3d 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/buteo-sync-plugin-mastodon-notifications.pro +++ b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/buteo-sync-plugin-mastodon-notifications.pro @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. +# +# SPDX-License-Identifier: BSD-3-Clause + TARGET = mastodon-notifications-client QT -= gui diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon-notifications.xml b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon-notifications.xml index 8d042d9..3284d61 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon-notifications.xml +++ b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon-notifications.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2013-2026 Jolla Ltd. --> +<!-- SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. --> +<!-- SPDX-License-Identifier: BSD-3-Clause --> <profile name="mastodon-notifications" type="client" > <field name="Sync Direction" /> </profile> diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon.Notifications.xml b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon.Notifications.xml index 2843180..05d5218 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon.Notifications.xml +++ b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodon.Notifications.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2013-2026 Jolla Ltd. --> +<!-- SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. --> +<!-- SPDX-License-Identifier: BSD-3-Clause --> <profile name="mastodon.Notifications" type="sync" > <key name="category" value="eventfeed" /> <key name="enabled" value="true" /> 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; diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/buteo-sync-plugin-mastodon-posts.pro b/buteo-plugins/buteo-sync-plugin-mastodon-posts/buteo-sync-plugin-mastodon-posts.pro index 86387b2..a9f65af 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/buteo-sync-plugin-mastodon-posts.pro +++ b/buteo-plugins/buteo-sync-plugin-mastodon-posts/buteo-sync-plugin-mastodon-posts.pro @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. +# +# SPDX-License-Identifier: BSD-3-Clause + TARGET = mastodon-posts-client QT -= gui diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon-posts.xml b/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon-posts.xml index 53bd93a..c1e25ae 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon-posts.xml +++ b/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon-posts.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2013-2026 Jolla Ltd. --> +<!-- SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. --> +<!-- SPDX-License-Identifier: BSD-3-Clause --> <profile name="mastodon-posts" type="client" > <field name="Sync Direction" /> </profile> diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon.Posts.xml b/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon.Posts.xml index 2904fa5..c7e2448 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon.Posts.xml +++ b/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodon.Posts.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Copyright (C) 2013-2026 Jolla Ltd. --> +<!-- SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. --> +<!-- SPDX-License-Identifier: BSD-3-Clause --> <profile name="mastodon.Posts" type="sync" > <key name="category" value="eventfeed" /> <key name="enabled" value="false" /> |
