diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 0ec2f632e2..2aebd8bc4c 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -165,6 +165,14 @@ base::Observable &Session::downloaderTaskFinished() { return downloader().taskFinished(); } +uint64 Session::uniqueId() const { + auto result = uint64(uint32(userId())); + if (mtp().isTestMode()) { + result |= 0x0100'0000'0000'0000ULL; + } + return result; +} + UserId Session::userId() const { return _user->bareId(); } diff --git a/Telegram/SourceFiles/main/main_session.h b/Telegram/SourceFiles/main/main_session.h index f1edc4e077..4962508025 100644 --- a/Telegram/SourceFiles/main/main_session.h +++ b/Telegram/SourceFiles/main/main_session.h @@ -80,6 +80,7 @@ public: [[nodiscard]] Domain &domain() const; [[nodiscard]] Storage::Domain &domainLocal() const; + [[nodiscard]] uint64 uniqueId() const; // userId() with TestDC shift. [[nodiscard]] UserId userId() const; [[nodiscard]] PeerId userPeerId() const; [[nodiscard]] not_null user() const { diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp index 5400eb326f..df70df966d 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.cpp @@ -205,22 +205,18 @@ QString GetImageKey(const QVersionNumber &specificationVersion) { } // namespace NotificationData::NotificationData( - const base::weak_ptr &manager, - const QString &title, - const QString &subtitle, - const QString &msg, - PeerId peerId, - MsgId msgId, - UserId selfId, - bool hideReplyButton) + const base::weak_ptr &manager, + const QString &title, + const QString &subtitle, + const QString &msg, + NotificationId id, + bool hideReplyButton) : _dbusConnection(QDBusConnection::sessionBus()) , _manager(manager) , _title(title) , _imageKey(GetImageKey(ParseSpecificationVersion( GetServerInformation()))) -, _peerId(peerId) -, _msgId(msgId) -, _selfId(selfId) { +, _id(id) { const auto capabilities = GetCapabilities(); if (capabilities.contains(qsl("body-markup"))) { @@ -377,14 +373,10 @@ void NotificationData::setImage(const QString &imagePath) { _hints[_imageKey] = QVariant::fromValue(imageData); } -NotificationData::NotificationId NotificationData::myId() const { - return { .peerId = _peerId, .msgId = _msgId, .selfId = _selfId }; -} - void NotificationData::notificationClosed(uint id) { if (id == _notificationId) { const auto manager = _manager; - const auto my = myId(); + const auto my = _id; crl::on_main(manager, [=] { manager->clearNotification(my); }); @@ -399,13 +391,13 @@ void NotificationData::actionInvoked(uint id, const QString &actionName) { if (actionName == qsl("default") || actionName == qsl("mail-reply-sender")) { const auto manager = _manager; - const auto my = myId(); + const auto my = _id; crl::on_main(manager, [=] { manager->notificationActivated(my); }); } else if (actionName == qsl("mail-mark-read")) { const auto manager = _manager; - const auto my = myId(); + const auto my = _id; crl::on_main(manager, [=] { manager->notificationReplied(my, {}); }); @@ -415,7 +407,7 @@ void NotificationData::actionInvoked(uint id, const QString &actionName) { void NotificationData::notificationReplied(uint id, const QString &text) { if (id == _notificationId) { const auto manager = _manager; - const auto my = myId(); + const auto my = _id; crl::on_main(manager, [=] { manager->notificationReplied(my, { text, {} }); }); @@ -541,17 +533,16 @@ void Manager::Private::showNotification( bool hideReplyButton) { if (!Supported()) return; - const auto peerId = peer->id; - const auto selfId = peer->session().userId(); - const auto key = FullPeer{ peerId, selfId }; + const auto key = FullPeer{ + .sessionId = peer->session().uniqueId(), + .peerId = peer->id + }; auto notification = std::make_shared( _manager, title, subtitle, msg, - peer->id, - msgId, - peer->session().userId(), + NotificationId{ .full = key, .msgId = msgId }, hideReplyButton); if (!hideNameAndPhoto) { @@ -601,8 +592,8 @@ void Manager::Private::clearFromHistory(not_null history) { if (!Supported()) return; const auto key = FullPeer{ - history->peer->id, - history->session().userId() + .sessionId = history->session().uniqueId(), + .peerId = history->peer->id }; auto i = _notifications.find(key); if (i != _notifications.cend()) { @@ -618,9 +609,9 @@ void Manager::Private::clearFromHistory(not_null history) { void Manager::Private::clearFromSession(not_null session) { if (!Supported()) return; - const auto selfId = session->userId(); + const auto sessionId = session->uniqueId(); for (auto i = _notifications.begin(); i != _notifications.end();) { - if (i->first.second == selfId) { + if (i->first.sessionId == sessionId) { const auto temp = base::take(i->second); i = _notifications.erase(i); @@ -634,7 +625,7 @@ void Manager::Private::clearFromSession(not_null session) { void Manager::Private::clearNotification(NotificationId id) { if (!Supported()) return; - auto i = _notifications.find(FullPeer{ id.peerId, id.selfId }); + auto i = _notifications.find(id.full); if (i != _notifications.cend()) { if (i->second.remove(id.msgId) && i->second.empty()) { _notifications.erase(i); diff --git a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h index c24ec30cb7..bc318111ae 100644 --- a/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h +++ b/Telegram/SourceFiles/platform/linux/notifications_manager_linux.h @@ -31,9 +31,7 @@ public: const QString &title, const QString &subtitle, const QString &msg, - PeerId peerId, - MsgId msgId, - UserId selfId, + NotificationId id, bool hideReplyButton); NotificationData(const NotificationData &other) = delete; @@ -53,8 +51,6 @@ public: }; private: - [[nodiscard]] NotificationId myId() const; - QDBusConnection _dbusConnection; base::weak_ptr _manager; @@ -65,14 +61,13 @@ private: QString _imageKey; uint _notificationId = 0; - PeerId _peerId = 0; - MsgId _msgId = 0; - UserId _selfId = 0; + NotificationId _id; private slots: void notificationClosed(uint id); void actionInvoked(uint id, const QString &actionName); void notificationReplied(uint id, const QString &text); + }; using Notification = std::shared_ptr; diff --git a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm index 054c402c0b..9db0ab40d3 100644 --- a/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm +++ b/Telegram/SourceFiles/platform/mac/notifications_manager_mac.mm @@ -92,10 +92,10 @@ NSImage *qt_mac_create_nsimage(const QPixmap &pm); return; } - NSNumber *selfObject = [notificationUserInfo objectForKey:@"self"]; - const auto notificationSelfId = selfObject ? [selfObject intValue] : 0; - if (!notificationSelfId) { - LOG(("App Error: A notification with unknown self was received")); + NSNumber *sessionObject = [notificationUserInfo objectForKey:@"session"]; + const auto notificationSessionId = sessionObject ? [sessionObject unsignedLongLongValue] : 0; + if (!notificationSessionId) { + LOG(("App Error: A notification with unknown session was received")); return; } NSNumber *peerObject = [notificationUserInfo objectForKey:@"peer"]; @@ -109,9 +109,11 @@ NSImage *qt_mac_create_nsimage(const QPixmap &pm); const auto notificationMsgId = msgObject ? [msgObject intValue] : 0; const auto my = Window::Notifications::Manager::NotificationId{ - .peerId = notificationPeerId, - .msgId = notificationMsgId, - .selfId = notificationSelfId + .full = FullPeer{ + .sessionId = notificationSessionId, + .peerId = notificationPeerId + }, + .msgId = notificationMsgId }; if (notification.activationType == NSUserNotificationActivationTypeReplied) { const auto notificationReply = QString::fromUtf8([[[notification response] string] UTF8String]); @@ -207,7 +209,7 @@ private: FullPeer fullPeer; }; struct ClearFromSession { - UserId selfId = 0; + uint64 sessionId = 0; }; struct ClearAll { }; @@ -249,7 +251,7 @@ void Manager::Private::showNotification( auto identifierValue = Q2NSString(identifier); [notification setIdentifier:identifierValue]; } - [notification setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedLongLong:peer->session().userId()],@"self",[NSNumber numberWithUnsignedLongLong:peer->id],@"peer",[NSNumber numberWithInt:msgId],@"msgid",[NSNumber numberWithUnsignedLongLong:_managerId],@"manager",nil]]; + [notification setUserInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedLongLong:peer->session().uniqueId()],@"session",[NSNumber numberWithUnsignedLongLong:peer->id],@"peer",[NSNumber numberWithInt:msgId],@"msgid",[NSNumber numberWithUnsignedLongLong:_managerId],@"manager",nil]]; [notification setTitle:Q2NSString(title)]; [notification setSubtitle:Q2NSString(subtitle)]; @@ -279,7 +281,7 @@ void Manager::Private::clearingThreadLoop() { while (!finished) { auto clearAll = false; auto clearFromPeers = base::flat_set(); - auto clearFromSessions = base::flat_set(); + auto clearFromSessions = base::flat_set(); { std::unique_lock lock(_clearingMutex); @@ -295,23 +297,26 @@ void Manager::Private::clearingThreadLoop() { } else if (auto fromHistory = base::get_if(&task)) { clearFromPeers.emplace(fromHistory->fullPeer); } else if (auto fromSession = base::get_if(&task)) { - clearFromSessions.emplace(fromSession->selfId); + clearFromSessions.emplace(fromSession->sessionId); } } _clearingTasks.clear(); } auto clearBySpecial = [&](NSDictionary *notificationUserInfo) { - NSNumber *selfObject = [notificationUserInfo objectForKey:@"self"]; - const auto notificationSelfId = selfObject ? [selfObject intValue] : 0; - if (!notificationSelfId) { + NSNumber *sessionObject = [notificationUserInfo objectForKey:@"session"]; + const auto notificationSessionId = sessionObject ? [sessionObject unsignedLongLongValue] : 0; + if (!notificationSessionId) { return true; } if (NSNumber *peerObject = [notificationUserInfo objectForKey:@"peer"]) { const auto notificationPeerId = [peerObject unsignedLongLongValue]; if (notificationPeerId) { - return clearFromSessions.contains(notificationSelfId) - || clearFromPeers.contains(FullPeer{ notificationPeerId, notificationSelfId }); + return clearFromSessions.contains(notificationSessionId) + || clearFromPeers.contains(FullPeer{ + .sessionId = notificationSessionId, + .peerId = notificationPeerId + }); } } return true; @@ -348,11 +353,14 @@ void Manager::Private::clearAll() { } void Manager::Private::clearFromHistory(not_null history) { - putClearTask(ClearFromHistory { FullPeer{ history->peer->id, history->session().userId() } }); + putClearTask(ClearFromHistory { FullPeer{ + .sessionId = history->session().uniqueId(), + .peerId = history->peer->id + } }); } void Manager::Private::clearFromSession(not_null session) { - putClearTask(ClearFromSession { session->userId() }); + putClearTask(ClearFromSession { session->uniqueId() }); } void Manager::Private::updateDelegate() { diff --git a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp index d5d9d93c60..f5cfdf51d1 100644 --- a/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp +++ b/Telegram/SourceFiles/platform/win/notifications_manager_win.cpp @@ -214,12 +214,8 @@ public: // We keep a weak pointer to a member field of native notifications manager. ToastEventHandler( const std::shared_ptr &guarded, - PeerId peer, - MsgId msg, - UserId selfId) - : _peerId(peer) - , _msgId(msg) - , _selfId(selfId) + NotificationId id) + : _id(id) , _weak(guarded) { } @@ -232,7 +228,7 @@ public: // DesktopToastActivatedEventHandler IFACEMETHODIMP Invoke(_In_ IToastNotification *sender, _In_ IInspectable* args) { - const auto my = myId(); + const auto my = _id; performOnMainQueue([my](Manager *manager) { manager->notificationActivated(my); }); @@ -249,7 +245,7 @@ public: case ToastDismissalReason_UserCanceled: case ToastDismissalReason_TimedOut: default: - const auto my = myId(); + const auto my = _id; performOnMainQueue([my](Manager *manager) { manager->clearNotification(my); }); @@ -261,7 +257,7 @@ public: // DesktopToastFailedEventHandler IFACEMETHODIMP Invoke(_In_ IToastNotification *sender, _In_ IToastFailedEventArgs *e) { - const auto my = myId(); + const auto my = _id; performOnMainQueue([my](Manager *manager) { manager->clearNotification(my); }); @@ -301,14 +297,8 @@ public: } private: - [[nodiscard]] NotificationId myId() const { - return { .peerId = _peerId, .msgId = _msgId, .selfId = _selfId }; - } - ULONG _refCount = 0; - PeerId _peerId = 0; - MsgId _msgId = 0; - UserId _selfId = 0; + NotificationId _id; std::weak_ptr _weak; }; @@ -439,8 +429,8 @@ void Manager::Private::clearFromHistory(not_null history) { if (!_notifier) return; auto i = _notifications.find(FullPeer{ - history->peer->id, - history->session().userId() + .sessionId = history->session().uniqueId(), + .peerId = history->peer->id }); if (i != _notifications.cend()) { auto temp = base::take(i->second); @@ -455,9 +445,9 @@ void Manager::Private::clearFromHistory(not_null history) { void Manager::Private::clearFromSession(not_null session) { if (!_notifier) return; - const auto selfId = session->userId(); + const auto sessionId = session->uniqueId(); for (auto i = _notifications.begin(); i != _notifications.end();) { - if (i->first.selfId == selfId) { + if (i->first.sessionId == sessionId) { const auto temp = base::take(i->second); _notifications.erase(i); @@ -479,7 +469,7 @@ void Manager::Private::afterNotificationActivated(NotificationId id) { } void Manager::Private::clearNotification(NotificationId id) { - auto i = _notifications.find(FullPeer{ id.peerId, id.selfId }); + auto i = _notifications.find(id.full); if (i != _notifications.cend()) { i->second.remove(id.msgId); if (i->second.empty()) { @@ -565,12 +555,19 @@ bool Manager::Private::showNotification( hr = _notificationFactory->CreateToastNotification(toastXml.Get(), &toast); if (!SUCCEEDED(hr)) return false; + const auto key = FullPeer{ + .sessionId = peer->session().uniqueId(), + .peerId = peer->id, + }; + const auto notificationId = NotificationId{ + .full = key, + .msgId = msgId + }; + EventRegistrationToken activatedToken, dismissedToken, failedToken; ComPtr eventHandler(new ToastEventHandler( _guarded, - peer->id, - msgId, - peer->session().userId())); + notificationId)); hr = toast->add_Activated(eventHandler.Get(), &activatedToken); if (!SUCCEEDED(hr)) return false; @@ -581,10 +578,6 @@ bool Manager::Private::showNotification( hr = toast->add_Failed(eventHandler.Get(), &failedToken); if (!SUCCEEDED(hr)) return false; - const auto key = FullPeer{ - peer->id, - peer->session().userId() - }; auto i = _notifications.find(key); if (i != _notifications.cend()) { auto j = i->second.find(msgId); diff --git a/Telegram/SourceFiles/window/notifications_manager.cpp b/Telegram/SourceFiles/window/notifications_manager.cpp index 0eb9aa4d4e..73d428cb25 100644 --- a/Telegram/SourceFiles/window/notifications_manager.cpp +++ b/Telegram/SourceFiles/window/notifications_manager.cpp @@ -74,10 +74,10 @@ void System::createManager() { } } -Main::Session *System::findSession(UserId selfId) const { +Main::Session *System::findSession(uint64 sessionId) const { for (const auto &[index, account] : Core::App().domain().accounts()) { if (const auto session = account->maybeSession()) { - if (session->userId() == selfId) { + if (session->uniqueId() == sessionId) { return session; } } @@ -293,12 +293,13 @@ void System::checkDelayed() { } void System::showGrouped() { - if (const auto session = findSession(_lastHistorySelfId)) { + if (const auto session = findSession(_lastHistorySessionId)) { if (const auto lastItem = session->data().message(_lastHistoryItemId)) { _waitForAllGroupedTimer.cancel(); _manager->showNotification(lastItem, _lastForwardedCount); _lastForwardedCount = 0; _lastHistoryItemId = FullMsgId(); + _lastHistorySessionId = 0; } } } @@ -307,13 +308,17 @@ void System::showNext() { if (App::quitting()) return; const auto isSameGroup = [=](HistoryItem *item) { - if (!_lastHistoryItemId || !item) { + if (!_lastHistorySessionId || !_lastHistoryItemId || !item) { + return false; + } else if (item->history()->session().uniqueId() + != _lastHistorySessionId) { return false; } const auto lastItem = item->history()->owner().message( _lastHistoryItemId); if (lastItem) { - return (lastItem->groupId() == item->groupId() || lastItem->author() == item->author()); + return (lastItem->groupId() == item->groupId()) + || (lastItem->author() == item->author()); } return false; }; @@ -476,6 +481,7 @@ void System::showNext() { } if (!_lastHistoryItemId && groupedItem) { + _lastHistorySessionId = groupedItem->history()->session().uniqueId(); _lastHistoryItemId = groupedItem->fullId(); } @@ -493,6 +499,7 @@ void System::showNext() { } // We have to wait until all the messages in this group are loaded. _lastForwardedCount += forwardedCount; + _lastHistorySessionId = groupedItem->history()->session().uniqueId(); _lastHistoryItemId = groupedItem->fullId(); _waitForAllGroupedTimer.callOnce(kWaitingForAllGroupedDelay); } else { @@ -567,13 +574,13 @@ QString Manager::accountNameSeparator() { void Manager::notificationActivated(NotificationId id) { onBeforeNotificationActivated(id); - if (const auto session = system()->findSession(id.selfId)) { + if (const auto session = system()->findSession(id.full.sessionId)) { if (session->windows().empty()) { Core::App().domain().activate(&session->account()); } if (!session->windows().empty()) { const auto window = session->windows().front(); - const auto history = session->data().history(id.peerId); + const auto history = session->data().history(id.full.peerId); window->widget()->showFromTray(); window->widget()->reActivateWindow(); if (Core::App().passcodeLocked()) { @@ -622,15 +629,15 @@ void Manager::openNotificationMessage( void Manager::notificationReplied( NotificationId id, const TextWithTags &reply) { - if (!id.selfId || !id.peerId) { + if (!id.full.sessionId || !id.full.peerId) { return; } - const auto session = system()->findSession(id.selfId); + const auto session = system()->findSession(id.full.sessionId); if (!session) { return; } - const auto history = session->data().history(id.peerId); + const auto history = session->data().history(id.full.peerId); auto message = Api::MessageToSend(history); message.textWithTags = reply; diff --git a/Telegram/SourceFiles/window/notifications_manager.h b/Telegram/SourceFiles/window/notifications_manager.h index 4086ab55d4..13fbb0c440 100644 --- a/Telegram/SourceFiles/window/notifications_manager.h +++ b/Telegram/SourceFiles/window/notifications_manager.h @@ -67,7 +67,7 @@ public: System(); ~System(); - [[nodiscard]] Main::Session *findSession(UserId selfId) const; + [[nodiscard]] Main::Session *findSession(uint64 sessionId) const; void createManager(); @@ -126,27 +126,26 @@ private: std::unique_ptr _soundTrack; int _lastForwardedCount = 0; - UserId _lastHistorySelfId = 0; + uint64 _lastHistorySessionId = 0; FullMsgId _lastHistoryItemId; }; class Manager { public: - struct NotificationId { - PeerId peerId = 0; - MsgId msgId = 0; - UserId selfId = 0; - }; struct FullPeer { + uint64 sessionId = 0; PeerId peerId = 0; - UserId selfId = 0; friend inline bool operator<(const FullPeer &a, const FullPeer &b) { - return std::tie(a.peerId, a.selfId) - < std::tie(b.peerId, b.selfId); + return std::tie(a.sessionId, a.peerId) + < std::tie(b.sessionId, b.peerId); } }; + struct NotificationId { + FullPeer full; + MsgId msgId = 0; + }; explicit Manager(not_null system) : _system(system) { } diff --git a/Telegram/SourceFiles/window/notifications_manager_default.cpp b/Telegram/SourceFiles/window/notifications_manager_default.cpp index c4b9117ca7..d9eba08a32 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -950,10 +950,10 @@ Notifications::Manager::NotificationId Notification::myId() const { if (!_history) { return {}; } - const auto selfId = _history->session().userId(); - const auto peerId = _history->peer->id; - const auto msgId = _item ? _item->id : ShowAtUnreadMsgId; - return { .peerId = peerId, .msgId = msgId, .selfId = selfId }; + return { .full = { + .sessionId = _history->session().uniqueId(), + .peerId = _history->peer->id + }, .msgId = _item ? _item->id : ShowAtUnreadMsgId }; } void Notification::changeHeight(int newHeight) {