diff --git a/Telegram/SourceFiles/api/api_who_reacted.cpp b/Telegram/SourceFiles/api/api_who_reacted.cpp index 07ce80485..9dcb62f8c 100644 --- a/Telegram/SourceFiles/api/api_who_reacted.cpp +++ b/Telegram/SourceFiles/api/api_who_reacted.cpp @@ -592,8 +592,13 @@ bool WhoReadExists(not_null item) { return true; } -bool WhoReactedExists(not_null item) { - return item->canViewReactions() || WhoReadExists(item); +bool WhoReactedExists( + not_null item, + WhoReactedList list) { + if (item->canViewReactions() || WhoReadExists(item)) { + return true; + } + return (list == WhoReactedList::One) && item->history()->peer->isUser(); } rpl::producer WhoReacted( diff --git a/Telegram/SourceFiles/api/api_who_reacted.h b/Telegram/SourceFiles/api/api_who_reacted.h index 0a1159690..b79b47584 100644 --- a/Telegram/SourceFiles/api/api_who_reacted.h +++ b/Telegram/SourceFiles/api/api_who_reacted.h @@ -24,8 +24,15 @@ struct ReactionId; namespace Api { +enum class WhoReactedList { + All, + One, +}; + [[nodiscard]] bool WhoReadExists(not_null item); -[[nodiscard]] bool WhoReactedExists(not_null item); +[[nodiscard]] bool WhoReactedExists( + not_null item, + WhoReactedList list); struct WhoReadList { std::vector list; diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index a3398422a..cf793780e 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -77,11 +77,12 @@ constexpr auto kTopReactionsLimit = 10; } // namespace -PossibleItemReactions LookupPossibleReactions(not_null item) { +PossibleItemReactionsRef LookupPossibleReactions( + not_null item) { if (!item->canReact()) { return {}; } - auto result = PossibleItemReactions(); + auto result = PossibleItemReactionsRef(); const auto peer = item->history()->peer; const auto session = &peer->session(); const auto reactions = &session->data().reactions(); @@ -157,6 +158,15 @@ PossibleItemReactions LookupPossibleReactions(not_null item) { return result; } +PossibleItemReactions::PossibleItemReactions( + const PossibleItemReactionsRef &other) + : recent(other.recent | ranges::views::transform([](const auto &value) { + return *value; +}) | ranges::to_vector) +, morePremiumAvailable(other.morePremiumAvailable) +, customAllowed(other.customAllowed) { +} + Reactions::Reactions(not_null owner) : _owner(owner) , _topRefreshTimer([=] { refreshTop(); }) @@ -194,6 +204,10 @@ Reactions::Reactions(not_null owner) Reactions::~Reactions() = default; +Main::Session &Reactions::session() const { + return _owner->session(); +} + void Reactions::refreshTop() { requestTop(); } @@ -868,7 +882,7 @@ void MessageReactions::add(const ReactionId &id, bool addToRecent) { } return removed; }), end(_list)); - if (_item->canViewReactions()) { + if (_item->canViewReactions() || history->peer->isUser()) { auto &list = _recent[id]; list.insert(begin(list), RecentReaction{ self }); } diff --git a/Telegram/SourceFiles/data/data_message_reactions.h b/Telegram/SourceFiles/data/data_message_reactions.h index 84591c796..06fdbc9a6 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.h +++ b/Telegram/SourceFiles/data/data_message_reactions.h @@ -38,13 +38,22 @@ struct Reaction { bool premium = false; }; -struct PossibleItemReactions { +struct PossibleItemReactionsRef { std::vector> recent; bool morePremiumAvailable = false; bool customAllowed = false; }; -[[nodiscard]] PossibleItemReactions LookupPossibleReactions( +struct PossibleItemReactions { + PossibleItemReactions() = default; + explicit PossibleItemReactions(const PossibleItemReactionsRef &other); + + std::vector recent; + bool morePremiumAvailable = false; + bool customAllowed = false; +}; + +[[nodiscard]] PossibleItemReactionsRef LookupPossibleReactions( not_null item); class Reactions final : private CustomEmojiManager::Listener { @@ -52,6 +61,11 @@ public: explicit Reactions(not_null owner); ~Reactions(); + [[nodiscard]] Session &owner() const { + return *_owner; + } + [[nodiscard]] Main::Session &session() const; + void refreshTop(); void refreshRecent(); void refreshRecentDelayed(); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 745c4072e..2c2a5395b 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -2011,13 +2011,15 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } const auto hasWhoReactedItem = _dragStateItem - && Api::WhoReactedExists(_dragStateItem); + && Api::WhoReactedExists(_dragStateItem, Api::WhoReactedList::All); const auto clickedReaction = link ? link->property( kReactionsCountEmojiProperty).value() : Data::ReactionId(); _whoReactedMenuLifetime.destroy(); - if (hasWhoReactedItem && !clickedReaction.empty()) { + if (!clickedReaction.empty() + && _dragStateItem + && Api::WhoReactedExists(_dragStateItem, Api::WhoReactedList::One)) { HistoryView::ShowWhoReactedMenu( &_menu, e->globalPos(), diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index fccc53f60..053e53f64 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -948,7 +948,8 @@ base::unique_qptr FillContextMenu( : nullptr; const auto hasSelection = !request.selectedItems.empty() || !request.selectedText.empty(); - const auto hasWhoReactedItem = item && Api::WhoReactedExists(item); + const auto hasWhoReactedItem = item + && Api::WhoReactedExists(item, Api::WhoReactedList::All); auto result = base::make_unique_q( list, diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index eb11e2566..4f855dd2c 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/media/history_view_custom_emoji.h" #include "history/view/reactions/history_view_reactions_animation.h" #include "history/view/reactions/history_view_reactions_button.h" +#include "history/view/reactions/history_view_reactions.h" #include "history/view/history_view_cursor_state.h" #include "history/history.h" #include "base/unixtime.h" @@ -430,6 +431,20 @@ void Element::prepareCustomEmojiPaint( } } +void Element::prepareCustomEmojiPaint( + Painter &p, + const Reactions::InlineList &reactions) const { + if (!reactions.hasCustomEmoji()) { + return; + } + clearCustomEmojiRepaint(); + p.setInactive(delegate()->elementIsGifPaused()); + if (!_heavyCustomEmoji) { + _heavyCustomEmoji = true; + history()->owner().registerHeavyViewPart(const_cast(this)); + } +} + //void Element::externalLottieProgressing(bool external) const { // if (const auto media = _media.get()) { // media->externalLottieProgressing(external); diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index 595e0588b..3f0655d4c 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -49,6 +49,7 @@ using PaintContext = Ui::ChatPaintContext; namespace Reactions { struct ButtonParameters; class Animation; +class InlineList; } // namespace Reactions enum class Context : char { @@ -421,6 +422,9 @@ public: void prepareCustomEmojiPaint( Painter &p, const Ui::Text::String &text) const; + void prepareCustomEmojiPaint( + Painter &p, + const Reactions::InlineList &reactions) const; void clearCustomEmojiRepaint() const; [[nodiscard]] ClickHandlerPtr fromPhotoLink() const { diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 833f62b45..38cd8e508 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -2210,13 +2210,15 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { ? _overElement->data().get() : nullptr; const auto hasWhoReactedItem = overItem - && Api::WhoReactedExists(overItem); + && Api::WhoReactedExists(overItem, Api::WhoReactedList::All); const auto clickedReaction = link ? link->property( kReactionsCountEmojiProperty).value() : Data::ReactionId(); _whoReactedMenuLifetime.destroy(); - if (hasWhoReactedItem && !clickedReaction.empty()) { + if (!clickedReaction.empty() + && overItem + && Api::WhoReactedExists(overItem, Api::WhoReactedList::One)) { HistoryView::ShowWhoReactedMenu( &_menu, e->globalPos(), diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 767e4e59d..ced6a2be1 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -739,6 +739,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { g.setHeight(g.height() - reactionsHeight); const auto reactionsPosition = QPoint(reactionsLeft + g.left(), g.top() + g.height() + st::mediaInBubbleSkip); p.translate(reactionsPosition); + prepareCustomEmojiPaint(p, *_reactions); _reactions->paint(p, context, g.width(), context.clip.translated(-reactionsPosition)); if (context.reactionInfo) { context.reactionInfo->position = reactionsPosition; @@ -794,6 +795,7 @@ void Message::draw(Painter &p, const PaintContext &context) const { trect.setHeight(trect.height() - reactionsHeight); const auto reactionsPosition = QPoint(trect.left(), trect.top() + trect.height() + reactionsTop); p.translate(reactionsPosition); + prepareCustomEmojiPaint(p, *_reactions); _reactions->paint(p, context, g.width(), context.clip.translated(-reactionsPosition)); if (context.reactionInfo) { context.reactionInfo->position = reactionsPosition; @@ -1385,6 +1387,9 @@ bool Message::hasHeavyPart() const { void Message::unloadHeavyPart() { Element::unloadHeavyPart(); + if (_reactions) { + _reactions->unloadCustomEmoji(); + } _comments = nullptr; } @@ -2232,6 +2237,7 @@ void Message::refreshReactions() { _reactions = std::make_unique( &item->history()->owner().reactions(), handlerFactory, + [=] { customEmojiRepaint(); }, std::move(reactionsData)); } else { _reactions->update(std::move(reactionsData), width()); diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp index ee43def46..77b9fe141 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp @@ -14,9 +14,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_cursor_state.h" #include "history/view/history_view_group_call_bar.h" #include "core/click_handler_types.h" +#include "data/stickers/data_custom_emoji.h" #include "data/data_message_reactions.h" #include "data/data_peer.h" +#include "data/data_session.h" #include "lang/lang_tag.h" +#include "ui/text/text_block.h" #include "ui/chat/chat_style.h" #include "styles/style_chat.h" @@ -40,6 +43,7 @@ struct InlineList::Button { mutable std::unique_ptr animation; mutable QImage image; mutable ClickHandlerPtr link; + mutable std::unique_ptr custom; std::unique_ptr userpics; ReactionId id; QString countText; @@ -51,9 +55,11 @@ struct InlineList::Button { InlineList::InlineList( not_null<::Data::Reactions*> owner, Fn handlerFactory, + Fn customEmojiRepaint, Data &&data) : _owner(owner) , _handlerFactory(std::move(handlerFactory)) +, _customEmojiRepaint(std::move(customEmojiRepaint)) , _data(std::move(data)) { layout(); } @@ -76,6 +82,21 @@ void InlineList::removeSkipBlock() { _skipBlock = {}; } +bool InlineList::hasCustomEmoji() const { + return _hasCustomEmoji; +} + +void InlineList::unloadCustomEmoji() { + if (!hasCustomEmoji()) { + return; + } + for (const auto &button : _buttons) { + if (const auto custom = button.custom.get()) { + custom->unload(); + } + } +} + void InlineList::layout() { layoutButtons(); initDimensions(); @@ -106,6 +127,7 @@ void InlineList::layoutButtons() { < ranges::find(list, b->id, &::Data::Reaction::id); }); + _hasCustomEmoji = false; auto buttons = std::vector