Fly-animate custom reactions.

This commit is contained in:
John Preston 2022-08-29 17:54:56 +04:00
parent d5008fe7ac
commit ad0c9ebb79
6 changed files with 38 additions and 20 deletions

View file

@ -28,7 +28,7 @@ class Animation;
struct ReactionAnimationArgs { struct ReactionAnimationArgs {
::Data::ReactionId id; ::Data::ReactionId id;
std::shared_ptr<Ui::AnimatedIcon> flyIcon; QImage flyIcon;
QRect flyFrom; QRect flyFrom;
[[nodiscard]] ReactionAnimationArgs translated(QPoint point) const; [[nodiscard]] ReactionAnimationArgs translated(QPoint point) const;

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_bottom_info.h" #include "history/view/history_view_bottom_info.h"
#include "ui/animated_icon.h" #include "ui/animated_icon.h"
#include "data/data_message_reactions.h" #include "data/data_message_reactions.h"
#include "data/data_session.h"
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_document_media.h" #include "data/data_document_media.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
@ -31,9 +32,20 @@ Animation::Animation(
, _repaint(std::move(repaint)) , _repaint(std::move(repaint))
, _flyFrom(args.flyFrom) { , _flyFrom(args.flyFrom) {
const auto &list = owner->list(::Data::Reactions::Type::All); const auto &list = owner->list(::Data::Reactions::Type::All);
const auto i = ranges::find(list, args.id, &::Data::Reaction::id); auto centerIcon = (DocumentData*)nullptr;
if (i == end(list) || !i->centerIcon) { auto aroundAnimation = (DocumentData*)nullptr;
return; if (const auto customId = args.id.custom()) {
const auto document = owner->owner().document(customId);
if (document->sticker()) {
centerIcon = document;
}
} else {
const auto i = ranges::find(list, args.id, &::Data::Reaction::id);
if (i == end(list) || !i->centerIcon) {
return;
}
centerIcon = i->centerIcon;
aroundAnimation = i->aroundAnimation;
} }
const auto resolve = [&]( const auto resolve = [&](
std::unique_ptr<Ui::AnimatedIcon> &icon, std::unique_ptr<Ui::AnimatedIcon> &icon,
@ -53,11 +65,11 @@ Animation::Animation(
return true; return true;
}; };
_flyIcon = std::move(args.flyIcon); _flyIcon = std::move(args.flyIcon);
if (!resolve(_center, i->centerIcon, size) if (!resolve(_center, centerIcon, size)) {
|| !resolve(_effect, i->aroundAnimation, size * 2)) {
return; return;
} }
if (_flyIcon) { resolve(_effect, aroundAnimation, size * 2);
if (!_flyIcon.isNull()) {
_fly.start([=] { flyCallback(); }, 0., 1., kFlyDuration); _fly.start([=] { flyCallback(); }, 0., 1., kFlyDuration);
} else { } else {
startAnimations(); startAnimations();
@ -71,12 +83,14 @@ QRect Animation::paintGetArea(
QPainter &p, QPainter &p,
QPoint origin, QPoint origin,
QRect target) const { QRect target) const {
if (!_flyIcon) { if (_flyIcon.isNull()) {
p.drawImage(target, _center->frame()); p.drawImage(target, _center->frame());
const auto wide = QRect( const auto wide = QRect(
target.topLeft() - QPoint(target.width(), target.height()) / 2, target.topLeft() - QPoint(target.width(), target.height()) / 2,
target.size() * 2); target.size() * 2);
p.drawImage(wide, _effect->frame()); if (const auto effect = _effect.get()) {
p.drawImage(wide, effect->frame());
}
return wide; return wide;
} }
const auto from = _flyFrom.translated(origin); const auto from = _flyFrom.translated(origin);
@ -94,7 +108,7 @@ QRect Animation::paintGetArea(
auto hq = PainterHighQualityEnabler(p); auto hq = PainterHighQualityEnabler(p);
if (progress < 1.) { if (progress < 1.) {
p.setOpacity(1. - progress); p.setOpacity(1. - progress);
p.drawImage(rect, _flyIcon->frame()); p.drawImage(rect, _flyIcon);
} }
if (progress > 0.) { if (progress > 0.) {
p.setOpacity(progress); p.setOpacity(progress);
@ -142,12 +156,14 @@ int Animation::computeParabolicTop(
void Animation::startAnimations() { void Animation::startAnimations() {
_center->animate([=] { callback(); }); _center->animate([=] { callback(); });
_effect->animate([=] { callback(); }); if (const auto effect = _effect.get()) {
_effect->animate([=] { callback(); });
}
} }
void Animation::flyCallback() { void Animation::flyCallback() {
if (!_fly.animating()) { if (!_fly.animating()) {
_flyIcon = nullptr; _flyIcon = QImage();
startAnimations(); startAnimations();
} }
callback(); callback();
@ -164,7 +180,7 @@ void Animation::setRepaintCallback(Fn<void()> repaint) {
} }
bool Animation::flying() const { bool Animation::flying() const {
return (_flyIcon != nullptr); return !_flyIcon.isNull();
} }
float64 Animation::flyingProgress() const { float64 Animation::flyingProgress() const {
@ -173,7 +189,9 @@ float64 Animation::flyingProgress() const {
bool Animation::finished() const { bool Animation::finished() const {
return !_valid return !_valid
|| (!_flyIcon && !_center->animating() && !_effect->animating()); || (_flyIcon.isNull()
&& !_center->animating()
&& (!_effect || !_effect->animating()));
} }
} // namespace HistoryView::Reactions } // namespace HistoryView::Reactions

View file

@ -47,7 +47,7 @@ private:
const not_null<::Data::Reactions*> _owner; const not_null<::Data::Reactions*> _owner;
Fn<void()> _repaint; Fn<void()> _repaint;
std::shared_ptr<Ui::AnimatedIcon> _flyIcon; QImage _flyIcon;
std::unique_ptr<Ui::AnimatedIcon> _center; std::unique_ptr<Ui::AnimatedIcon> _center;
std::unique_ptr<Ui::AnimatedIcon> _effect; std::unique_ptr<Ui::AnimatedIcon> _effect;
Ui::Animations::Simple _fly; Ui::Animations::Simple _fly;

View file

@ -359,7 +359,7 @@ ChosenReaction Manager::lookupChosen(const ReactionId &id) const {
return result; return result;
} }
const auto index = _strip.fillChosenIconGetIndex(result); const auto index = _strip.fillChosenIconGetIndex(result);
if (!result.icon) { if (result.icon.isNull()) {
return result; return result;
} }
const auto between = st::reactionCornerSkip; const auto between = st::reactionCornerSkip;

View file

@ -231,9 +231,9 @@ int Strip::fillChosenIconGetIndex(ChosenReaction &chosen) const {
} }
const auto &icon = *i; const auto &icon = *i;
if (const auto &appear = icon.appear; appear && appear->animating()) { if (const auto &appear = icon.appear; appear && appear->animating()) {
chosen.icon = CreateIconSnapshot(icon.appearAnimation, appear.get()); chosen.icon = appear->frame();
} else if (const auto &select = icon.select) { } else if (const auto &select = icon.select; select && select->valid()) {
chosen.icon = CreateIconSnapshot(icon.selectAnimation, select.get()); chosen.icon = select->frame();
} }
return (i - begin(_icons)); return (i - begin(_icons));
} }

View file

@ -27,7 +27,7 @@ namespace HistoryView::Reactions {
struct ChosenReaction { struct ChosenReaction {
FullMsgId context; FullMsgId context;
Data::ReactionId id; Data::ReactionId id;
std::shared_ptr<Ui::AnimatedIcon> icon; QImage icon;
QRect geometry; QRect geometry;
explicit operator bool() const { explicit operator bool() const {