diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 615dbdc952..f41bfa87b8 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -846,23 +846,19 @@ void HistoryItem::toggleReaction(const QString &reaction) { } void HistoryItem::updateReactions(const MTPMessageReactions *reactions) { - const auto history = this->history(); - const auto toUser = (reactions && out()) - ? history->peer->asUser() - : nullptr; - const auto toContact = toUser && toUser->isContact(); const auto hadUnread = hasUnreadReaction(); setReactions(reactions); const auto hasUnread = hasUnreadReaction(); if (hasUnread && !hadUnread) { - // This may read the reaction already. addToUnreadThings(HistoryUnreadThings::AddType::New); - if (toContact && hasUnreadReaction()) { + + // Call to addToUnreadThings may have read the reaction already. + if (hasUnreadReaction()) { const auto notification = ItemNotification{ this, ItemNotificationType::Reaction, }; - history->pushNotification(notification); + history()->pushNotification(notification); Core::App().notifications().schedule(notification); } } else if (!hasUnread && hadUnread) { @@ -947,22 +943,21 @@ QString HistoryItem::chosenReaction() const { return _reactions ? _reactions->chosen() : QString(); } -QString HistoryItem::lookupHisReaction() const { +HistoryItemUnreadReaction HistoryItem::lookupUnreadReaction() const { if (!_reactions) { - return QString(); + return {}; } - const auto &list = _reactions->list(); - if (list.empty()) { - return QString(); + const auto recent = _reactions->recent(); + for (const auto &[emoji, list] : _reactions->recent()) { + const auto i = ranges::find( + list, + true, + &Data::RecentReaction::unread); + if (i != end(list)) { + return { .from = i->peer, .emoji = emoji }; + } } - const auto chosen = _reactions->chosen(); - const auto &[first, count] = list.front(); - if (chosen.isEmpty() || first != chosen || count > 1) { - return first; - } else if (list.size() == 1) { - return QString(); - } - return list.back().first; + return {}; } crl::time HistoryItem::lastReactionsRefreshTime() const { diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 38efa1c5cf..a132b6e4c7 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -63,6 +63,15 @@ enum class Context : char; class ElementDelegate; } // namespace HistoryView +struct HistoryItemUnreadReaction { + PeerData *from = nullptr; + QString emoji; + + explicit operator bool() const { + return (from != nullptr) && !emoji.isEmpty(); + } +}; + struct HiddenSenderInfo; class History; @@ -373,7 +382,7 @@ public: std::vector> &; [[nodiscard]] bool canViewReactions() const; [[nodiscard]] QString chosenReaction() const; - [[nodiscard]] QString lookupHisReaction() const; + [[nodiscard]] HistoryItemUnreadReaction lookupUnreadReaction() const; [[nodiscard]] crl::time lastReactionsRefreshTime() const; [[nodiscard]] bool hasDirectLink() const; diff --git a/Telegram/SourceFiles/window/notifications_manager.cpp b/Telegram/SourceFiles/window/notifications_manager.cpp index ed5006e6c9..2657549573 100644 --- a/Telegram/SourceFiles/window/notifications_manager.cpp +++ b/Telegram/SourceFiles/window/notifications_manager.cpp @@ -657,13 +657,14 @@ void System::showNext() { const auto reactionNotification = (notify->type == ItemNotificationType::Reaction); const auto reaction = reactionNotification - ? notify->item->lookupHisReaction() - : QString(); - if (!reactionNotification || !reaction.isEmpty()) { + ? notify->item->lookupUnreadReaction() + : HistoryItemUnreadReaction(); + if (!reactionNotification || reaction) { _manager->showNotification({ .item = notify->item, .forwardedCount = forwardedCount, - .reaction = reaction, + .reactionFrom = reaction.from, + .reactionEmoji = reaction.emoji, }); } } @@ -879,13 +880,14 @@ void Manager::openNotificationMessage( not_null history, MsgId messageId) { const auto openExactlyMessage = [&] { - if (history->peer->isChannel()) { + const auto peer = history->peer; + if (peer->isBroadcast()) { return false; } const auto item = history->owner().message(history->peer, messageId); if (!item || !item->isRegular() - || (!item->out() && !item->mentionsMe())) { + || (!item->out() && (!item->mentionsMe() || peer->isUser()))) { return false; } return true; @@ -928,17 +930,17 @@ void Manager::notificationReplied( void NativeManager::doShowNotification(NotificationFields &&fields) { const auto options = getNotificationOptions( fields.item, - (fields.reaction.isEmpty() - ? ItemNotificationType::Message - : ItemNotificationType::Reaction)); + (fields.reactionFrom + ? ItemNotificationType::Reaction + : ItemNotificationType::Message)); const auto item = fields.item; const auto peer = item->history()->peer; - const auto reaction = fields.reaction; - if (!reaction.isEmpty() && options.hideNameAndPhoto) { + const auto reactionFrom = fields.reactionFrom; + if (reactionFrom && options.hideNameAndPhoto) { return; } const auto scheduled = !options.hideNameAndPhoto - && fields.reaction.isEmpty() + && !reactionFrom && (item->out() || peer->isSelf()) && item->isFromScheduled(); const auto title = options.hideNameAndPhoto @@ -947,13 +949,15 @@ void NativeManager::doShowNotification(NotificationFields &&fields) { ? tr::lng_notification_reminder(tr::now) : peer->name; const auto fullTitle = addTargetAccountName(title, &peer->session()); - const auto subtitle = (options.hideNameAndPhoto || !reaction.isEmpty()) + const auto subtitle = reactionFrom + ? (reactionFrom != peer ? reactionFrom->name : QString()) + : options.hideNameAndPhoto ? QString() : item->notificationHeader(); - const auto text = !reaction.isEmpty() + const auto text = reactionFrom ? TextWithPermanentSpoiler(ComposeReactionNotification( item, - reaction, + fields.reactionEmoji, options.hideMessageText)) : options.hideMessageText ? tr::lng_notification_preview(tr::now) diff --git a/Telegram/SourceFiles/window/notifications_manager.h b/Telegram/SourceFiles/window/notifications_manager.h index 5dd643cf71..5f228e6c84 100644 --- a/Telegram/SourceFiles/window/notifications_manager.h +++ b/Telegram/SourceFiles/window/notifications_manager.h @@ -219,7 +219,8 @@ public: struct NotificationFields { not_null item; int forwardedCount = 0; - QString reaction; + PeerData *reactionFrom = nullptr; + QString reactionEmoji; }; 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 9b5f07194b..cfbca35525 100644 --- a/Telegram/SourceFiles/window/notifications_manager_default.cpp +++ b/Telegram/SourceFiles/window/notifications_manager_default.cpp @@ -78,8 +78,12 @@ Manager::Manager(System *system) Manager::QueuedNotification::QueuedNotification(NotificationFields &&fields) : history(fields.item->history()) , peer(history->peer) -, reaction(fields.reaction) -, author(reaction.isEmpty() ? fields.item->notificationHeader() : QString()) +, reaction(fields.reactionEmoji) +, author(!fields.reactionFrom + ? fields.item->notificationHeader() + : (fields.reactionFrom != peer) + ? fields.reactionFrom->name + : QString()) , item((fields.forwardedCount < 2) ? fields.item.get() : nullptr) , forwardedCount(fields.forwardedCount) , fromScheduled(reaction.isEmpty() && (fields.item->out() || peer->isSelf()) @@ -814,10 +818,13 @@ void Notification::updateNotifyDisplay() { p.setPen(st::dialogsTextFg); p.setFont(st::dialogsTextFont); const auto text = !_reaction.isEmpty() - ? Manager::ComposeReactionNotification( + ? (!_author.isEmpty() + ? Ui::Text::PlainLink(_author).append(' ') + : TextWithEntities() + ).append(Manager::ComposeReactionNotification( _item, _reaction, - options.hideMessageText) + options.hideMessageText)) : _item ? _item->toPreview({ .hideSender = reminder,