From 2022775dd052b6b1a1a82c1f418e892e40dd4fc8 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Thu, 9 Apr 2020 20:52:50 +0200 Subject: [PATCH] Clear notifications when event is read --- src/Cache.cpp | 10 +++++-- src/Cache_p.h | 1 + src/ChatPage.cpp | 5 ++++ src/notifications/Manager.h | 30 +++++++++++++++++++++ src/notifications/ManagerLinux.cpp | 42 +++++++++++++++++++++++++++++- src/notifications/ManagerMac.mm | 5 ++++ src/notifications/ManagerWin.cpp | 5 ++++ 7 files changed, 95 insertions(+), 3 deletions(-) diff --git a/src/Cache.cpp b/src/Cache.cpp index fb2ded7d..bdca76f2 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -829,6 +829,7 @@ Cache::filterReadEvents(const QString &room_id, void Cache::updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Receipts &receipts) { + auto user_id = this->localUserId_.toStdString(); for (const auto &receipt : receipts) { const auto event_id = receipt.first; auto event_receipts = receipt.second; @@ -857,8 +858,13 @@ Cache::updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Recei } // Append the new ones. - for (const auto &event_receipt : event_receipts) - saved_receipts.emplace(event_receipt.first, event_receipt.second); + for (const auto &[read_by, timestamp] : event_receipts) { + if (read_by == user_id) { + emit removeNotification(QString::fromStdString(room_id), + QString::fromStdString(event_id)); + } + saved_receipts.emplace(read_by, timestamp); + } // Save back the merged (or only the new) receipts. nlohmann::json json_updated_value = saved_receipts; diff --git a/src/Cache_p.h b/src/Cache_p.h index 14ceafe8..6eae45a9 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -229,6 +229,7 @@ public: signals: void newReadReceipts(const QString &room_id, const std::vector &event_ids); void roomReadStatus(const std::map &status); + void removeNotification(const QString &room_id, const QString &event_id); private: //! Save an invited room. diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index 5312ea43..d7d11a12 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -645,6 +645,11 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token) connect( cache::client(), &Cache::roomReadStatus, room_list_, &RoomList::updateReadStatus); + connect(cache::client(), + &Cache::removeNotification, + ¬ificationsManager, + &NotificationsManager::removeNotification); + const bool isInitialized = cache::isInitialized(); const bool isValid = cache::isFormatValid(); diff --git a/src/notifications/Manager.h b/src/notifications/Manager.h index 56541ece..6cbecbc6 100644 --- a/src/notifications/Manager.h +++ b/src/notifications/Manager.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -15,6 +16,27 @@ struct roomEventId QString eventId; }; +inline bool +operator<(const roomEventId &a, const roomEventId &b) +{ + if (a.roomId == b.roomId) + return a.eventId < b.eventId; + else + return a.roomId < b.roomId; +} + +inline bool +operator==(const roomEventId &a, const roomEventId &b) +{ + return a.roomId == b.roomId && a.eventId == b.eventId; +} + +inline uint +qHash(const roomEventId &v, uint seed) +{ + return qHash(v.roomId, seed) ^ qHash(v.eventId, seed); +} + class NotificationsManager : public QObject { Q_OBJECT @@ -31,13 +53,21 @@ public: signals: void notificationClicked(const QString roomId, const QString eventId); +public slots: + void removeNotification(const QString &roomId, const QString &eventId); + #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) +public: + void closeNotifications(QString roomId); + private: QDBusInterface dbus; uint showNotification(const QString summary, const QString text, const QImage image); + void closeNotification(uint id); // notification ID to (room ID, event ID) QMap notificationIds; + QHash eventToNotificationId; #endif // these slots are platform specific (D-Bus only) diff --git a/src/notifications/ManagerLinux.cpp b/src/notifications/ManagerLinux.cpp index 1914f61c..33fcb41d 100644 --- a/src/notifications/ManagerLinux.cpp +++ b/src/notifications/ManagerLinux.cpp @@ -40,6 +40,7 @@ NotificationsManager::postNotification(const QString &roomid, { uint id = showNotification(roomname, sender + ": " + text, icon); notificationIds[id] = roomEventId{roomid, eventid}; + eventToNotificationId[roomEventId{roomid, eventid}] = id; } /** * This function is based on code from @@ -54,6 +55,7 @@ NotificationsManager::showNotification(const QString summary, { QVariantMap hints; hints["image-data"] = image; + hints["sound-name"] = "message-new-instant"; QList argumentList; argumentList << "nheko"; // app_name argumentList << (uint)0; // replace_id @@ -78,6 +80,44 @@ NotificationsManager::showNotification(const QString summary, return true; } +void +NotificationsManager::closeNotification(uint id) +{ + QList argumentList; + argumentList << (uint)id; // replace_id + + static QDBusInterface closeCall("org.freedesktop.Notifications", + "/org/freedesktop/Notifications", + "org.freedesktop.Notifications"); + QDBusMessage reply = + closeCall.callWithArgumentList(QDBus::AutoDetect, "CloseNotification", argumentList); + if (reply.type() == QDBusMessage::ErrorMessage) { + qDebug() << "D-Bus Error:" << reply.errorMessage(); + } +} + +void +NotificationsManager::removeNotification(const QString &roomId, const QString &eventId) +{ + roomEventId reId = {roomId, eventId}; + if (eventToNotificationId.contains(reId)) { + for (auto elem = notificationIds.begin(); elem != notificationIds.end(); ++elem) { + if (elem.value().roomId != roomId) + continue; + + // close all notifications matching the eventId or having a lower + // notificationId + // This relies on the notificationId not wrapping around. This allows for + // approximately 2,147,483,647 notifications, so it is a bit unlikely. + // Otherwise we would need to store a 64bit counter instead. + closeNotification(elem.key()); + + if (elem.value() == reId) + break; + } + } +} + void NotificationsManager::actionInvoked(uint id, QString action) { @@ -91,7 +131,7 @@ void NotificationsManager::notificationClosed(uint id, uint reason) { Q_UNUSED(reason); - notificationIds.remove(id); + eventToNotificationId.remove(notificationIds.take(id)); } /** diff --git a/src/notifications/ManagerMac.mm b/src/notifications/ManagerMac.mm index 66ef713f..e46b0b82 100644 --- a/src/notifications/ManagerMac.mm +++ b/src/notifications/ManagerMac.mm @@ -46,3 +46,8 @@ void NotificationsManager::notificationClosed(uint, uint) { } + +void +NotificationsManager::removeNotification(const QString &roomId, const QString &eventId) +{} + diff --git a/src/notifications/ManagerWin.cpp b/src/notifications/ManagerWin.cpp index 9cc4da9b..b00bac2e 100644 --- a/src/notifications/ManagerWin.cpp +++ b/src/notifications/ManagerWin.cpp @@ -63,3 +63,8 @@ NotificationsManager::postNotification(const QString &room_id, void NotificationsManager::actionInvoked(uint, QString) {} void NotificationsManager::notificationClosed(uint, uint) {} + +void +NotificationsManager::removeNotification(const QString &roomId, const QString &eventId) +{} +