diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index cffa80266..67d44fcad 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -1294,7 +1294,7 @@ void ApiWrap::markContentsRead( QVector>(); markedIds.reserve(items.size()); for (const auto &item : items) { - if (!item->markContentsRead() || !item->isRegular() || true) { + if (!item->markContentsRead(true) || !item->isRegular() || true) { AssertIsDebug(); continue; } @@ -1320,7 +1320,7 @@ void ApiWrap::markContentsRead( } void ApiWrap::markContentsRead(not_null item) { - if (!item->markContentsRead() || !item->isRegular()) { + if (!item->markContentsRead(true) || !item->isRegular()) { return; } const auto ids = MTP_vector(1, MTP_int(item->id)); diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 9ed93566c..a138442e8 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1486,6 +1486,12 @@ void Session::requestAnimationPlayInline(not_null item) { } } +void Session::requestUnreadReactionsAnimation(not_null item) { + enumerateItemViews(item, [&](not_null view) { + view->animateUnreadReactions(); + }); +} + rpl::producer> Session::animationPlayInlineRequest() const { return _animationPlayInlineRequest.events(); } diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index fb1bc7f80..4146398b7 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -253,6 +253,7 @@ public: [[nodiscard]] rpl::producer> itemViewRefreshRequest() const; void requestItemTextRefresh(not_null item); void requestAnimationPlayInline(not_null item); + void requestUnreadReactionsAnimation(not_null item); [[nodiscard]] rpl::producer> animationPlayInlineRequest() const; void notifyHistoryUnloaded(not_null history); [[nodiscard]] rpl::producer> historyUnloaded() const; diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 7dc5495f1..fa083c223 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -386,7 +386,7 @@ HistoryInner::HistoryInner( return; } else if (const auto view = item->mainView()) { if (const auto top = itemTop(view); top >= 0) { - view->animateSendReaction({ + view->animateReaction({ .emoji = reaction.emoji, .flyIcon = reaction.icon, .flyFrom = reaction.geometry.translated(0, -top), diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 25dfe6136..615dbdc95 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -383,8 +383,11 @@ void HistoryItem::markReactionsRead() { history()->unreadReactions().erase(id); } -bool HistoryItem::markContentsRead() { +bool HistoryItem::markContentsRead(bool fromThisClient) { if (hasUnreadReaction()) { + if (fromThisClient) { + history()->owner().requestUnreadReactionsAnimation(this); + } markReactionsRead(); return true; } else if (isUnreadMention() || isIncomingUnreadMedia()) { diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 8f1a285a4..38efa1c5c 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -150,7 +150,7 @@ public: [[nodiscard]] bool hasUnreadMediaFlag() const; void markReactionsRead(); void markMediaAndMentionRead(); - bool markContentsRead(); + bool markContentsRead(bool fromThisClient = false); void setIsPinned(bool isPinned); // For edit media in history_message. diff --git a/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp b/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp index 72a8d8661..8ffb25399 100644 --- a/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp +++ b/Telegram/SourceFiles/history/view/history_view_bottom_info.cpp @@ -512,10 +512,10 @@ void BottomInfo::setReactionCount(Reaction &reaction, int count) { : 0; } -void BottomInfo::animateReactionSend( - SendReactionAnimationArgs &&args, +void BottomInfo::animateReaction( + ReactionAnimationArgs &&args, Fn repaint) { - _reactionAnimation = std::make_unique( + _reactionAnimation = std::make_unique( _reactionsOwner, args.translated(QPoint(width(), height())), std::move(repaint), @@ -523,12 +523,12 @@ void BottomInfo::animateReactionSend( } auto BottomInfo::takeSendReactionAnimation() --> std::unique_ptr { +-> std::unique_ptr { return std::move(_reactionAnimation); } void BottomInfo::continueSendReactionAnimation( - std::unique_ptr animation) { + std::unique_ptr animation) { _reactionAnimation = std::move(animation); } diff --git a/Telegram/SourceFiles/history/view/history_view_bottom_info.h b/Telegram/SourceFiles/history/view/history_view_bottom_info.h index 7d7fb9093..3e3581e9c 100644 --- a/Telegram/SourceFiles/history/view/history_view_bottom_info.h +++ b/Telegram/SourceFiles/history/view/history_view_bottom_info.h @@ -21,14 +21,14 @@ class Reactions; namespace HistoryView { namespace Reactions { -class SendAnimation; +class Animation; } // namespace Reactions using PaintContext = Ui::ChatPaintContext; class Message; struct TextState; -struct SendReactionAnimationArgs; +struct ReactionAnimationArgs; class BottomInfo final : public Object { public: @@ -73,13 +73,13 @@ public: bool inverted, const PaintContext &context) const; - void animateReactionSend( - SendReactionAnimationArgs &&args, + void animateReaction( + ReactionAnimationArgs &&args, Fn repaint); [[nodiscard]] auto takeSendReactionAnimation() - -> std::unique_ptr; + -> std::unique_ptr; void continueSendReactionAnimation( - std::unique_ptr animation); + std::unique_ptr animation); private: struct Reaction { @@ -124,7 +124,7 @@ private: Ui::Text::String _replies; std::vector _reactions; mutable ClickHandlerPtr _revokeLink; - mutable std::unique_ptr _reactionAnimation; + mutable std::unique_ptr _reactionAnimation; int _reactionsMaxWidth = 0; int _dateWidth = 0; bool _authorElided = false; diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 62e5278c9..0033b1ffe 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -36,6 +36,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_groups.h" #include "data/data_media_types.h" #include "data/data_sponsored_messages.h" +#include "data/data_message_reactions.h" #include "lang/lang_keys.h" #include "styles/style_chat.h" @@ -342,7 +343,7 @@ void DateBadge::paint( ServiceMessagePainter::PaintDate(p, st, text, width, y, w, chatWide); } -SendReactionAnimationArgs SendReactionAnimationArgs::translated( +ReactionAnimationArgs ReactionAnimationArgs::translated( QPoint point) const { return { .emoji = emoji, @@ -1059,11 +1060,20 @@ void Element::clickHandlerPressedChanged( } } -void Element::animateSendReaction(SendReactionAnimationArgs &&args) { +void Element::animateReaction(ReactionAnimationArgs &&args) { +} + +void Element::animateUnreadReactions() { + const auto &recent = data()->recentReactions(); + for (const auto &[emoji, list] : recent) { + if (ranges::contains(list, true, &Data::RecentReaction::unread)) { + animateReaction({ .emoji = emoji }); + } + } } auto Element::takeSendReactionAnimation() --> std::unique_ptr { +-> std::unique_ptr { return nullptr; } diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index 1ccb3bcaf..578b60bd7 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -49,7 +49,7 @@ using PaintContext = Ui::ChatPaintContext; namespace Reactions { struct ButtonParameters; -class SendAnimation; +class Animation; } // namespace Reactions enum class Context : char { @@ -229,12 +229,12 @@ struct DateBadge : public RuntimeComponent { }; -struct SendReactionAnimationArgs { +struct ReactionAnimationArgs { QString emoji; std::shared_ptr flyIcon; QRect flyFrom; - [[nodiscard]] SendReactionAnimationArgs translated(QPoint point) const; + [[nodiscard]] ReactionAnimationArgs translated(QPoint point) const; }; class Element @@ -421,9 +421,10 @@ public: [[nodiscard]] bool markSponsoredViewed(int shownFromTop) const; - virtual void animateSendReaction(SendReactionAnimationArgs &&args); + virtual void animateReaction(ReactionAnimationArgs &&args); + void animateUnreadReactions(); [[nodiscard]] virtual auto takeSendReactionAnimation() - -> std::unique_ptr; + -> std::unique_ptr; virtual ~Element(); @@ -438,7 +439,7 @@ public: static void Moused(Element *view); [[nodiscard]] static Element *Moused(); static void ClearGlobal(); - + protected: void repaint() const; diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 2079d2652..e6c4cd2c7 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -353,7 +353,7 @@ ListWidget::ListWidget( return; } else if (const auto view = viewForItem(item)) { if (const auto top = itemTop(view); top >= 0) { - view->animateSendReaction({ + view->animateReaction({ .emoji = reaction.emoji, .flyIcon = reaction.icon, .flyFrom = reaction.geometry.translated(0, -top), diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 7a28cd56d..686735fba 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -326,7 +326,7 @@ void Message::applyGroupAdminChanges( } } -void Message::animateSendReaction(SendReactionAnimationArgs &&args) { +void Message::animateReaction(ReactionAnimationArgs &&args) { const auto item = message(); const auto media = this->media(); @@ -353,12 +353,12 @@ void Message::animateSendReaction(SendReactionAnimationArgs &&args) { : 0; g.setHeight(g.height() - reactionsHeight); const auto reactionsPosition = QPoint(reactionsLeft + g.left(), g.top() + g.height() + st::mediaInBubbleSkip); - _reactions->animateSend(args.translated(-reactionsPosition), repainter); + _reactions->animate(args.translated(-reactionsPosition), repainter); return; } const auto animateInBottomInfo = [&](QPoint bottomRight) { - _bottomInfo.animateReactionSend(args.translated(-bottomRight), repainter); + _bottomInfo.animateReaction(args.translated(-bottomRight), repainter); }; if (bubble) { auto entry = logEntryOriginal(); @@ -381,7 +381,7 @@ void Message::animateSendReaction(SendReactionAnimationArgs &&args) { if (reactionsInBubble) { trect.setHeight(trect.height() - reactionsHeight); const auto reactionsPosition = QPoint(trect.left(), trect.top() + trect.height() + reactionsTop); - _reactions->animateSend(args.translated(-reactionsPosition), repainter); + _reactions->animate(args.translated(-reactionsPosition), repainter); return; } if (_viewButton) { @@ -425,7 +425,7 @@ void Message::animateSendReaction(SendReactionAnimationArgs &&args) { } auto Message::takeSendReactionAnimation() --> std::unique_ptr { +-> std::unique_ptr { return _reactions ? _reactions->takeSendAnimation() : _bottomInfo.takeSendReactionAnimation(); @@ -2163,7 +2163,7 @@ void Message::refreshReactions() { strong->data()->toggleReaction(emoji); if (const auto now = weak.get()) { if (now->data()->chosenReaction() == emoji) { - now->animateSendReaction({ + now->animateReaction({ .emoji = emoji, }); } diff --git a/Telegram/SourceFiles/history/view/history_view_message.h b/Telegram/SourceFiles/history/view/history_view_message.h index 78c1062d3..a9ffa7db0 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.h +++ b/Telegram/SourceFiles/history/view/history_view_message.h @@ -135,9 +135,9 @@ public: void applyGroupAdminChanges( const base::flat_set &changes) override; - void animateSendReaction(SendReactionAnimationArgs &&args) override; + void animateReaction(ReactionAnimationArgs &&args) override; auto takeSendReactionAnimation() - -> std::unique_ptr override; + -> std::unique_ptr override; protected: void refreshDataIdHook() override; diff --git a/Telegram/SourceFiles/history/view/history_view_react_animation.cpp b/Telegram/SourceFiles/history/view/history_view_react_animation.cpp index f1eb3890f..fbf6610e1 100644 --- a/Telegram/SourceFiles/history/view/history_view_react_animation.cpp +++ b/Telegram/SourceFiles/history/view/history_view_react_animation.cpp @@ -21,9 +21,9 @@ constexpr auto kFlyDuration = crl::time(300); } // namespace -SendAnimation::SendAnimation( +Animation::Animation( not_null<::Data::Reactions*> owner, - SendReactionAnimationArgs &&args, + ReactionAnimationArgs &&args, Fn repaint, int size) : _owner(owner) @@ -66,9 +66,9 @@ SendAnimation::SendAnimation( _valid = true; } -SendAnimation::~SendAnimation() = default; +Animation::~Animation() = default; -QRect SendAnimation::paintGetArea( +QRect Animation::paintGetArea( QPainter &p, QPoint origin, QRect target) const { @@ -105,7 +105,7 @@ QRect SendAnimation::paintGetArea( return wide; } -int SendAnimation::computeParabolicTop( +int Animation::computeParabolicTop( int from, int to, float64 progress) const { @@ -141,12 +141,12 @@ int SendAnimation::computeParabolicTop( return int(base::SafeRound(_cachedA * t * t + _cachedB * t + from)); } -void SendAnimation::startAnimations() { +void Animation::startAnimations() { _center->animate([=] { callback(); }, 0, _center->framesCount() - 1); _effect->animate([=] { callback(); }, 0, _effect->framesCount() - 1); } -void SendAnimation::flyCallback() { +void Animation::flyCallback() { if (!_fly.animating()) { _flyIcon = nullptr; startAnimations(); @@ -154,25 +154,25 @@ void SendAnimation::flyCallback() { callback(); } -void SendAnimation::callback() { +void Animation::callback() { if (_repaint) { _repaint(); } } -void SendAnimation::setRepaintCallback(Fn repaint) { +void Animation::setRepaintCallback(Fn repaint) { _repaint = std::move(repaint); } -bool SendAnimation::flying() const { +bool Animation::flying() const { return (_flyIcon != nullptr); } -float64 SendAnimation::flyingProgress() const { +float64 Animation::flyingProgress() const { return _fly.value(1.); } -QString SendAnimation::playingAroundEmoji() const { +QString Animation::playingAroundEmoji() const { const auto finished = !_valid || (!_flyIcon && !_center->animating() && !_effect->animating()); return finished ? QString() : _emoji; diff --git a/Telegram/SourceFiles/history/view/history_view_react_animation.h b/Telegram/SourceFiles/history/view/history_view_react_animation.h index 7c3cba254..d0add07b3 100644 --- a/Telegram/SourceFiles/history/view/history_view_react_animation.h +++ b/Telegram/SourceFiles/history/view/history_view_react_animation.h @@ -18,19 +18,19 @@ class Reactions; } // namespace Data namespace HistoryView { -struct SendReactionAnimationArgs; +struct ReactionAnimationArgs; } // namespace HistoryView namespace HistoryView::Reactions { -class SendAnimation final { +class Animation final { public: - SendAnimation( + Animation( not_null<::Data::Reactions*> owner, - SendReactionAnimationArgs &&args, + ReactionAnimationArgs &&args, Fn repaint, int size); - ~SendAnimation(); + ~Animation(); void setRepaintCallback(Fn repaint); QRect paintGetArea(QPainter &p, QPoint origin, QRect target) const; diff --git a/Telegram/SourceFiles/history/view/history_view_reactions.cpp b/Telegram/SourceFiles/history/view/history_view_reactions.cpp index f495bf3bc..41f0c9cef 100644 --- a/Telegram/SourceFiles/history/view/history_view_reactions.cpp +++ b/Telegram/SourceFiles/history/view/history_view_reactions.cpp @@ -408,10 +408,10 @@ bool InlineList::getState( return false; } -void InlineList::animateSend( - SendReactionAnimationArgs &&args, +void InlineList::animate( + ReactionAnimationArgs &&args, Fn repaint) { - _animation = std::make_unique( + _animation = std::make_unique( _owner, std::move(args), std::move(repaint), @@ -447,12 +447,12 @@ void InlineList::resolveUserpicsImage(const Button &button) const { kMaxRecentUserpics); } -std::unique_ptr InlineList::takeSendAnimation() { +std::unique_ptr InlineList::takeSendAnimation() { return std::move(_animation); } void InlineList::continueSendAnimation( - std::unique_ptr animation) { + std::unique_ptr animation) { _animation = std::move(animation); } diff --git a/Telegram/SourceFiles/history/view/history_view_reactions.h b/Telegram/SourceFiles/history/view/history_view_reactions.h index 2629d8fe5..f73a01253 100644 --- a/Telegram/SourceFiles/history/view/history_view_reactions.h +++ b/Telegram/SourceFiles/history/view/history_view_reactions.h @@ -22,13 +22,13 @@ namespace HistoryView { using PaintContext = Ui::ChatPaintContext; class Message; struct TextState; -struct SendReactionAnimationArgs; +struct ReactionAnimationArgs; struct UserpicInRow; } // namespace HistoryView namespace HistoryView::Reactions { -class SendAnimation; +class Animation; struct InlineListData { enum class Flag : uchar { @@ -72,11 +72,11 @@ public: QPoint point, not_null outResult) const; - void animateSend( - SendReactionAnimationArgs &&args, + void animate( + ReactionAnimationArgs &&args, Fn repaint); - [[nodiscard]] std::unique_ptr takeSendAnimation(); - void continueSendAnimation(std::unique_ptr animation); + [[nodiscard]] std::unique_ptr takeSendAnimation(); + void continueSendAnimation(std::unique_ptr animation); private: struct Userpics { @@ -113,7 +113,7 @@ private: std::vector