From ff835ec76ce2d0d60ef02ff74f6a95866c6cae08 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 15 Jun 2023 16:26:49 +0400 Subject: [PATCH] Show animation on story reaction sending. --- .../history_view_reactions_selector.cpp | 19 ++++++++ .../history_view_reactions_selector.h | 1 + .../stories/media_stories_controller.cpp | 46 +++++++++++++++++-- .../media/stories/media_stories_controller.h | 8 ++++ .../media/stories/media_stories_reactions.cpp | 2 +- .../media/stories/media_stories_reactions.h | 6 ++- .../ui/effects/reaction_fly_animation.cpp | 24 +++++++++- .../ui/effects/reaction_fly_animation.h | 2 + 8 files changed, 100 insertions(+), 8 deletions(-) diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp index fa0dec3f9..4aa2370a8 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/painter.h" #include "history/history_item.h" #include "data/data_document.h" +#include "data/data_document_media.h" #include "data/data_session.h" #include "data/stickers/data_custom_emoji.h" #include "main/main_session.h" @@ -667,12 +668,30 @@ ChosenReaction Selector::lookupChosen(const Data::ReactionId &id) const { return result; } +void Selector::preloadAllRecentsAnimations() { + const auto preload = [&](DocumentData *document) { + const auto view = document + ? document->activeMediaView() + : nullptr; + if (view) { + view->checkStickerLarge(); + } + }; + for (const auto &reaction : _reactions.recent) { + if (!reaction.id.custom()) { + preload(reaction.centerIcon); + } + preload(reaction.aroundAnimation); + } +} + void Selector::expand() { if (_expandScheduled) { return; } _expandScheduled = true; _willExpand.fire({}); + preloadAllRecentsAnimations(); const auto parent = parentWidget()->geometry(); const auto extents = extentsForShadow(); const auto heightLimit = _reactions.customAllowed diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.h b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.h index 648fe4adb..b47dfa2d8 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.h +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.h @@ -131,6 +131,7 @@ private: void createList(); void finishExpand(); ChosenReaction lookupChosen(const Data::ReactionId &id) const; + void preloadAllRecentsAnimations(); const style::EmojiPan &_st; const std::shared_ptr _show; diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index 7a187bcf8..1a519058b 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -11,11 +11,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/power_save_blocker.h" #include "base/qt_signal_producer.h" #include "chat_helpers/compose/compose_show.h" +#include "data/stickers/data_custom_emoji.h" #include "data/data_changes.h" #include "data/data_file_origin.h" +#include "data/data_message_reactions.h" #include "data/data_session.h" #include "data/data_stories.h" #include "data/data_user.h" +#include "history/view/reactions/history_view_reactions_strip.h" #include "main/main_session.h" #include "media/stories/media_stories_caption_full_view.h" #include "media/stories/media_stories_delegate.h" @@ -28,8 +31,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/stories/media_stories_share.h" #include "media/stories/media_stories_view.h" #include "media/audio/media_audio.h" -#include "ui/rp_widget.h" +#include "ui/effects/emoji_fly_animation.h" +#include "ui/effects/message_sending_animation_common.h" +#include "ui/effects/reaction_fly_animation.h" #include "ui/layers/box_content.h" +#include "ui/rp_widget.h" #include "styles/style_media_view.h" #include "styles/style_widgets.h" #include "styles/style_boxes.h" // UserpicButton @@ -171,8 +177,14 @@ Controller::Controller(not_null delegate) }, _lifetime); _reactions->chosen( - ) | rpl::start_with_next([=](const Data::ReactionId &id) { - _replyArea->sendReaction(id); + ) | rpl::start_with_next([=](HistoryView::Reactions::ChosenReaction id) { + startReactionAnimation(id.id, { + .type = Ui::MessageSendingAnimationFrom::Type::Emoji, + .globalStartGeometry = id.globalGeometry, + .frame = id.icon, + }); + _replyArea->sendReaction(id.id); + unfocusReply(); }, _lifetime); _delegate->storiesLayerShown( @@ -1062,4 +1074,32 @@ void Controller::updatePowerSaveBlocker(const Player::TrackState &state) { [=] { return _wrap->window()->windowHandle(); }); } +void Controller::startReactionAnimation( + Data::ReactionId id, + Ui::MessageSendingAnimationFrom from) { + Expects(shown()); + + auto args = Ui::ReactionFlyAnimationArgs{ + .id = id, + .flyIcon = from.frame, + .flyFrom = _wrap->mapFromGlobal(from.globalStartGeometry), + .scaleOutDuration = st::fadeWrapDuration * 2, + }; + _reactionAnimation = std::make_unique( + _wrap, + &shownUser()->owner().reactions(), + std::move(args), + [=] { _reactionAnimation->repaint(); }, + Data::CustomEmojiSizeTag::Isolated); + const auto layer = _reactionAnimation->layer(); + _wrap->paintRequest() | rpl::start_with_next([=] { + if (!_reactionAnimation->paintBadgeFrame(_wrap.get())) { + InvokeQueued(layer, [=] { + _reactionAnimation = nullptr; + _wrap->update(); + }); + } + }, layer->lifetime()); +} + } // namespace Media::Stories diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.h b/Telegram/SourceFiles/media/stories/media_stories_controller.h index 277140db0..74dde653b 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.h +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.h @@ -21,6 +21,7 @@ struct FileChosen; namespace Data { struct FileOrigin; +struct ReactionId; } // namespace Data namespace HistoryView::Reactions { @@ -29,6 +30,8 @@ class CachedIconFactory; namespace Ui { class RpWidget; +struct MessageSendingAnimationFrom; +class EmojiFlyAnimation; } // namespace Ui namespace Main { @@ -183,6 +186,10 @@ private: void checkMoveByDelta(); void loadMoreToList(); + void startReactionAnimation( + Data::ReactionId id, + Ui::MessageSendingAnimationFrom from); + const not_null _delegate; rpl::variable> _layout; @@ -226,6 +233,7 @@ private: std::unique_ptr _siblingRight; std::unique_ptr _powerSaveBlocker; + std::unique_ptr _reactionAnimation; Main::Session *_session = nullptr; rpl::lifetime _sessionLifetime; diff --git a/Telegram/SourceFiles/media/stories/media_stories_reactions.cpp b/Telegram/SourceFiles/media/stories/media_stories_reactions.cpp index d77e8274e..fb94bc026 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reactions.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_reactions.cpp @@ -143,7 +143,7 @@ void Reactions::create() { _selector->chosen( ) | rpl::start_with_next([=]( HistoryView::Reactions::ChosenReaction reaction) { - _chosen.fire_copy(reaction.id); + _chosen.fire_copy(reaction); hide(); }, _selector->lifetime()); diff --git a/Telegram/SourceFiles/media/stories/media_stories_reactions.h b/Telegram/SourceFiles/media/stories/media_stories_reactions.h index 1be44b34a..ca2200d7e 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_reactions.h +++ b/Telegram/SourceFiles/media/stories/media_stories_reactions.h @@ -15,6 +15,7 @@ struct ReactionId; namespace HistoryView::Reactions { class Selector; +struct ChosenReaction; } // namespace HistoryView::Reactions namespace Ui { @@ -30,10 +31,11 @@ public: explicit Reactions(not_null controller); ~Reactions(); + using Chosen = HistoryView::Reactions::ChosenReaction; [[nodiscard]] rpl::producer expandedValue() const { return _expanded.value(); } - [[nodiscard]] rpl::producer chosen() const { + [[nodiscard]] rpl::producer chosen() const { return _chosen.events(); } @@ -54,7 +56,7 @@ private: std::unique_ptr _parent; std::unique_ptr _selector; std::vector> _hiding; - rpl::event_stream _chosen; + rpl::event_stream _chosen; Ui::Animations::Simple _showing; rpl::variable _shownValue; rpl::variable _expanded; diff --git a/Telegram/SourceFiles/ui/effects/reaction_fly_animation.cpp b/Telegram/SourceFiles/ui/effects/reaction_fly_animation.cpp index 44c7686c6..361eb3b7b 100644 --- a/Telegram/SourceFiles/ui/effects/reaction_fly_animation.cpp +++ b/Telegram/SourceFiles/ui/effects/reaction_fly_animation.cpp @@ -67,7 +67,8 @@ ReactionFlyAnimation::ReactionFlyAnimation( Data::CustomEmojiSizeTag customSizeTag) : _owner(owner) , _repaint(std::move(repaint)) -, _flyFrom(args.flyFrom) { +, _flyFrom(args.flyFrom) +, _scaleOutDuration(args.scaleOutDuration) { const auto &list = owner->list(::Data::Reactions::Type::All); auto centerIcon = (DocumentData*)nullptr; auto aroundAnimation = (DocumentData*)nullptr; @@ -135,7 +136,26 @@ QRect ReactionFlyAnimation::paintGetArea( const QColor &colored, QRect clip, crl::time now) const { - if (_flyIcon.isNull()) { + const auto scale = [&] { + const auto rate = _effect ? _effect->frameRate() : 0.; + if (!_scaleOutDuration || !rate) { + return 1.; + } + const auto left = _effect->framesCount() - _effect->frameIndex(); + const auto duration = left * 1000. / rate; + return (duration < _scaleOutDuration) + ? (duration / double(_scaleOutDuration)) + : 1.; + }(); + if (scale < 1.) { + const auto delta = ((1. - scale) / 2.) * target.size(); + target = QRect( + target.topLeft() + QPoint(delta.width(), delta.height()), + target.size() * scale); + } + if (!_valid) { + return QRect(); + } else if (_flyIcon.isNull()) { const auto wide = QRect( target.topLeft() - QPoint(target.width(), target.height()) / 2, target.size() * 2); diff --git a/Telegram/SourceFiles/ui/effects/reaction_fly_animation.h b/Telegram/SourceFiles/ui/effects/reaction_fly_animation.h index 6092d46c1..595e11e86 100644 --- a/Telegram/SourceFiles/ui/effects/reaction_fly_animation.h +++ b/Telegram/SourceFiles/ui/effects/reaction_fly_animation.h @@ -27,6 +27,7 @@ struct ReactionFlyAnimationArgs { ::Data::ReactionId id; QImage flyIcon; QRect flyFrom; + crl::time scaleOutDuration = 0; [[nodiscard]] ReactionFlyAnimationArgs translated(QPoint point) const; }; @@ -102,6 +103,7 @@ private: QRect _flyFrom; float64 _centerSizeMultiplier = 0.; int _customSize = 0; + crl::time _scaleOutDuration = 0; bool _valid = false; mutable Parabolic _cached;