diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp index ac149705f..646c780eb 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp @@ -828,6 +828,7 @@ public: const QString &msg, DisplayOptions options); void clearAll(); + void clearFromItem(not_null<HistoryItem*> item); void clearFromHistory(not_null<History*> history); void clearFromSession(not_null<Main::Session*> session); void clearNotification(NotificationId id); @@ -943,6 +944,30 @@ void Manager::Private::clearAll() { } } +void Manager::Private::clearFromItem(not_null<HistoryItem*> item) { + if (!Supported()) { + return; + } + const auto key = FullPeer{ + .sessionId = item->history()->session().uniqueId(), + .peerId = item->history()->peer->id + }; + const auto i = _notifications.find(key); + if (i == _notifications.cend()) { + return; + } + const auto j = i->second.find(item->id); + if (j == i->second.end()) { + return; + } + const auto taken = base::take(j->second); + i->second.erase(j); + if (i->second.empty()) { + _notifications.erase(i); + } + taken->close(); +} + void Manager::Private::clearFromHistory(not_null<History*> history) { if (!Supported()) { return; @@ -952,7 +977,7 @@ void Manager::Private::clearFromHistory(not_null<History*> history) { .sessionId = history->session().uniqueId(), .peerId = history->peer->id }; - auto i = _notifications.find(key); + const auto i = _notifications.find(key); if (i != _notifications.cend()) { const auto temp = base::take(i->second); _notifications.erase(i); @@ -1033,6 +1058,10 @@ void Manager::doClearAllFast() { _private->clearAll(); } +void Manager::doClearFromItem(not_null<HistoryItem*> item) { + _private->clearFromItem(item); +} + void Manager::doClearFromHistory(not_null<History*> history) { _private->clearFromHistory(history); } diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h index 2689e4f82..4dcc870df 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h @@ -28,6 +28,7 @@ protected: const QString &msg, DisplayOptions options) override; void doClearAllFast() override; + void doClearFromItem(not_null<HistoryItem*> item) override; void doClearFromHistory(not_null<History*> history) override; void doClearFromSession(not_null<Main::Session*> session) override; bool doSkipAudio() const override; diff --git a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.h b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.h index a743f1794..50bb84100 100644 --- a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.h +++ b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.h @@ -28,6 +28,7 @@ protected: const QString &msg, DisplayOptions options) override; void doClearAllFast() override; + void doClearFromItem(not_null<HistoryItem*> item) override; void doClearFromHistory(not_null<History*> history) override; void doClearFromSession(not_null<Main::Session*> session) override; QString accountNameSeparator() override; diff --git a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm index 5e1e6fbf0..5b0ad0616 100644 --- a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm +++ b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/platform/mac/base_utilities_mac.h" #include "base/random.h" #include "history/history.h" +#include "history/history_item.h" #include "ui/empty_userpic.h" #include "main/main_session.h" #include "mainwindow.h" @@ -107,7 +108,7 @@ using Manager = Platform::Notifications::Manager; } NSNumber *msgObject = [notificationUserInfo objectForKey:@"msgid"]; - const auto notificationMsgId = msgObject ? [msgObject intValue] : 0; + const auto notificationMsgId = msgObject ? [msgObject longLongValue] : 0LL; const auto my = Window::Notifications::Manager::NotificationId{ .full = Manager::FullPeer{ @@ -186,6 +187,7 @@ public: const QString &msg, DisplayOptions options); void clearAll(); + void clearFromItem(not_null<HistoryItem*> item); void clearFromHistory(not_null<History*> history); void clearFromSession(not_null<Main::Session*> session); void updateDelegate(); @@ -207,6 +209,9 @@ private: std::mutex _clearingMutex; std::condition_variable _clearingCondition; + struct ClearFromItem { + NotificationId id; + }; struct ClearFromHistory { FullPeer fullPeer; }; @@ -218,6 +223,7 @@ private: struct ClearFinish { }; using ClearTask = std::variant< + ClearFromItem, ClearFromHistory, ClearFromSession, ClearAll, @@ -268,7 +274,7 @@ void Manager::Private::showNotification( @"session", [NSNumber numberWithUnsignedLongLong:peer->id.value], @"peer", - [NSNumber numberWithInt:msgId.bare], + [NSNumber numberWithLongLong:msgId.bare], @"msgid", [NSNumber numberWithUnsignedLongLong:_managerId], @"manager", @@ -305,6 +311,7 @@ void Manager::Private::clearingThreadLoop() { auto finished = false; while (!finished) { auto clearAll = false; + auto clearFromItems = base::flat_set<NotificationId>(); auto clearFromPeers = base::flat_set<FullPeer>(); auto clearFromSessions = base::flat_set<uint64>(); { @@ -318,6 +325,8 @@ void Manager::Private::clearingThreadLoop() { clearAll = true; }, [&](ClearAll) { clearAll = true; + }, [&](const ClearFromItem &value) { + clearFromItems.emplace(value.id); }, [&](const ClearFromHistory &value) { clearFromPeers.emplace(value.fullPeer); }, [&](const ClearFromSession &value) { @@ -335,17 +344,21 @@ void Manager::Private::clearingThreadLoop() { if (!notificationSessionId) { return true; } - if (NSNumber *peerObject = [notificationUserInfo objectForKey:@"peer"]) { - const auto notificationPeerId = [peerObject unsignedLongLongValue]; - if (notificationPeerId) { - return clearFromSessions.contains(notificationSessionId) - || clearFromPeers.contains(FullPeer{ - .sessionId = notificationSessionId, - .peerId = PeerId(notificationPeerId) - }); - } + NSNumber *peerObject = [notificationUserInfo objectForKey:@"peer"]; + const auto notificationPeerId = peerObject ? [peerObject unsignedLongLongValue] : 0; + if (!notificationPeerId) { + return true; } - return true; + NSNumber *msgObject = [notificationUserInfo objectForKey:@"msgid"]; + const auto msgId = msgObject ? [msgObject longLongValue] : 0LL; + const auto full = FullPeer{ + .sessionId = notificationSessionId, + .peerId = PeerId(notificationPeerId) + }; + const auto id = NotificationId{ full, MsgId(msgId) }; + return clearFromSessions.contains(notificationSessionId) + || clearFromPeers.contains(full) + || (msgId && clearFromItems.contains(id)); }; NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter]; @@ -380,6 +393,13 @@ void Manager::Private::clearAll() { putClearTask(ClearAll()); } +void Manager::Private::clearFromItem(not_null<HistoryItem*> item) { + putClearTask(ClearFromItem { FullPeer{ + .sessionId = history->session().uniqueId(), + .peerId = history->peer->id + }, item->id }); +} + void Manager::Private::clearFromHistory(not_null<History*> history) { putClearTask(ClearFromHistory { FullPeer{ .sessionId = history->session().uniqueId(), @@ -434,6 +454,10 @@ void Manager::doClearAllFast() { _private->clearAll(); } +void Manager::doClearFromItem(not_null<HistoryItem*> item) { + _private->clearFromItem(item); +} + void Manager::doClearFromHistory(not_null<History*> history) { _private->clearFromHistory(history); } diff --git a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp index a1d79b582..b761b06fa 100644 --- a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp +++ b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp @@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "platform/win/windows_dlls.h" #include "platform/win/specific_win.h" #include "history/history.h" +#include "history/history_item.h" #include "core/application.h" #include "core/core_settings.h" #include "main/main_session.h" @@ -418,6 +419,7 @@ public: const QString &msg, DisplayOptions options); void clearAll(); + void clearFromItem(not_null<HistoryItem*> item); void clearFromHistory(not_null<History*> history); void clearFromSession(not_null<Main::Session*> session); void beforeNotificationActivated(NotificationId id); @@ -489,6 +491,30 @@ void Manager::Private::clearAll() { } } +void Manager::Private::clearFromItem(not_null<HistoryItem*> item) { + if (!_notifier) { + return; + } + + auto i = _notifications.find(FullPeer{ + .sessionId = item->history()->session().uniqueId(), + .peerId = item->history()->peer->id + }); + if (i == _notifications.cend()) { + return; + } + const auto j = i->second.find(item->id); + if (j == end(i->second)) { + return; + } + const auto taken = std::exchange(j->second, nullptr); + i->second.erase(j); + if (i->second.empty()) { + _notifications.erase(i); + } + _notifier.Hide(taken); +} + void Manager::Private::clearFromHistory(not_null<History*> history) { if (!_notifier) { return; @@ -499,7 +525,7 @@ void Manager::Private::clearFromHistory(not_null<History*> history) { .peerId = history->peer->id }); if (i != _notifications.cend()) { - auto temp = base::take(i->second); + const auto temp = base::take(i->second); _notifications.erase(i); for (const auto &[msgId, notification] : temp) { @@ -842,6 +868,10 @@ void Manager::doClearAllFast() { _private->clearAll(); } +void Manager::doClearFromItem(not_null<HistoryItem*> item) { + _private->clearFromItem(item); +} + void Manager::doClearFromHistory(not_null<History*> history) { _private->clearFromHistory(history); } diff --git a/Telegram/SourceFiles/platform/win/notifications_manager_win.h b/Telegram/SourceFiles/platform/win/notifications_manager_win.h index 9833cb8dc..5ae34cc0f 100644 --- a/Telegram/SourceFiles/platform/win/notifications_manager_win.h +++ b/Telegram/SourceFiles/platform/win/notifications_manager_win.h @@ -36,6 +36,7 @@ protected: const QString &msg, DisplayOptions options) override; void doClearAllFast() override; + void doClearFromItem(not_null<HistoryItem*> item) override; void doClearFromHistory(not_null<History*> history) override; void doClearFromSession(not_null<Main::Session*> session) override; void onBeforeNotificationActivated(NotificationId id) override; diff --git a/Telegram/SourceFiles/window/notifications_manager.h b/Telegram/SourceFiles/window/notifications_manager.h index e867aad4c..26afab1be 100644 --- a/Telegram/SourceFiles/window/notifications_manager.h +++ b/Telegram/SourceFiles/window/notifications_manager.h @@ -162,6 +162,12 @@ public: struct NotificationId { FullPeer full; MsgId msgId = 0; + + friend inline bool operator<( + const NotificationId &a, + const NotificationId &b) { + return std::tie(a.full, a.msgId) < std::tie(b.full, b.msgId); + } }; explicit Manager(not_null<System*> system) : _system(system) { @@ -275,8 +281,6 @@ protected: void doClearAll() override { doClearAllFast(); } - void doClearFromItem(not_null<HistoryItem*> item) override { - } void doShowNotification( not_null<HistoryItem*> item, int forwardedCount) override; @@ -314,6 +318,8 @@ protected: } void doClearAllFast() override { } + void doClearFromItem(not_null<HistoryItem*> item) override { + } void doClearFromHistory(not_null<History*> history) override { } void doClearFromSession(not_null<Main::Session*> session) override {