Show appear animations in reactions dropdown.

This commit is contained in:
John Preston 2022-01-05 22:29:11 +03:00
parent c0b19000d6
commit 508ba4750c
3 changed files with 64 additions and 5 deletions

View file

@ -35,6 +35,7 @@ constexpr auto kButtonExpandDelay = crl::time(25);
constexpr auto kButtonHideDelay = crl::time(300); constexpr auto kButtonHideDelay = crl::time(300);
constexpr auto kButtonExpandedHideDelay = crl::time(0); constexpr auto kButtonExpandedHideDelay = crl::time(0);
constexpr auto kSizeForDownscale = 96; constexpr auto kSizeForDownscale = 96;
constexpr auto kHoverScale = 1.2;
[[nodiscard]] QPoint LocalPosition(not_null<QWheelEvent*> e) { [[nodiscard]] QPoint LocalPosition(not_null<QWheelEvent*> e) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
@ -98,6 +99,10 @@ bool Button::isHidden() const {
return (_state == State::Hidden) && !_opacityAnimation.animating(); return (_state == State::Hidden) && !_opacityAnimation.animating();
} }
bool Button::hasInitialView() const {
return (_geometry.height() == _collapsed.height());
}
QRect Button::geometry() const { QRect Button::geometry() const {
return _geometry; return _geometry;
} }
@ -368,6 +373,9 @@ void Manager::updateButton(ButtonParameters parameters) {
return; return;
} else if (_button) { } else if (_button) {
_button->applyParameters(parameters); _button->applyParameters(parameters);
if (_button->hasInitialView()) {
clearAppearAnimations();
}
return; return;
} else if (parameters.outside) { } else if (parameters.outside) {
_buttonShowTimer.cancel(); _buttonShowTimer.cancel();
@ -386,6 +394,7 @@ void Manager::updateButton(ButtonParameters parameters) {
} }
void Manager::showButtonDelayed() { void Manager::showButtonDelayed() {
clearAppearAnimations();
_button = std::make_unique<Button>( _button = std::make_unique<Button>(
_buttonUpdate, _buttonUpdate,
*_scheduledParameters, *_scheduledParameters,
@ -503,11 +512,14 @@ void Manager::loadIcons() {
return entry.icon; return entry.icon;
}; };
_icons.clear(); _icons.clear();
auto main = true;
for (const auto &reaction : _list) { for (const auto &reaction : _list) {
_icons.push_back({ _icons.push_back({
.appear = load(reaction.appearAnimation, 1), .appear = load(reaction.appearAnimation, main ? -1 : 1),
.select = load(reaction.selectAnimation, -1), .select = load(reaction.selectAnimation, -1),
.appearAnimated = main,
}); });
main = false;
} }
} }
@ -656,6 +668,9 @@ void Manager::paintButton(
} else { } else {
const auto source = validateEmoji(frameIndex, scale); const auto source = validateEmoji(frameIndex, scale);
p.drawImage(mainEmojiPosition, _cacheParts, source); p.drawImage(mainEmojiPosition, _cacheParts, source);
if (button == _button.get()) {
clearAppearAnimations();
}
} }
if (opacity != 1.) { if (opacity != 1.) {
@ -663,6 +678,25 @@ void Manager::paintButton(
} }
} }
void Manager::clearAppearAnimations() {
if (!_showingAll) {
return;
}
_showingAll = false;
auto main = true;
for (auto &icon : _icons) {
if (icon.appearAnimated != main) {
if (const auto appear = icon.appear.get()) {
appear->jumpTo(
main ? (appear->framesCount() - 1) : 1,
nullptr);
}
icon.appearAnimated = main;
}
main = false;
}
}
void Manager::paintLongImage( void Manager::paintLongImage(
QPainter &p, QPainter &p,
QRect geometry, QRect geometry,
@ -702,7 +736,14 @@ void Manager::paintAllEmoji(
not_null<Button*> button, not_null<Button*> button,
float64 scale, float64 scale,
QPoint mainEmojiPosition) { QPoint mainEmojiPosition) {
const auto current = (button == _button.get());
if (current) {
_showingAll = true;
}
const auto clip = buttonInner(button); const auto clip = buttonInner(button);
const auto skip = st::reactionAppearStartSkip;
const auto animationRect = clip.marginsRemoved({ 0, skip, 0, skip });
p.setClipRect(clip); p.setClipRect(clip);
auto hq = PainterHighQualityEnabler(p); auto hq = PainterHighQualityEnabler(p);
@ -720,17 +761,30 @@ void Manager::paintAllEmoji(
const auto shift = QPoint(0, oneHeight * (expandUp ? -1 : 1)); const auto shift = QPoint(0, oneHeight * (expandUp ? -1 : 1));
auto emojiPosition = mainEmojiPosition auto emojiPosition = mainEmojiPosition
+ QPoint(0, button->scroll() * (expandUp ? 1 : -1)); + QPoint(0, button->scroll() * (expandUp ? 1 : -1));
for (const auto &icon : _icons) { const auto update = [=] {
if (_button) _buttonUpdate(_button->geometry());
};
for (auto &icon : _icons) {
const auto target = basicTarget.translated(emojiPosition); const auto target = basicTarget.translated(emojiPosition);
emojiPosition += shift; emojiPosition += shift;
if (!target.intersects(clip)) { if (!target.intersects(clip)) {
if (current) {
if (const auto appear = icon.appear.get()) {
appear->jumpTo(1, nullptr);
}
icon.appearAnimated = false;
}
continue; continue;
} else if (icon.appear) { } else if (icon.appear) {
if (current
&& !icon.appearAnimated
&& target.intersects(animationRect)) {
icon.appearAnimated = true;
icon.appear->animate(update, 0, icon.appear->framesCount());
}
const auto size = int(base::SafeRound(target.width())); const auto size = int(base::SafeRound(target.width()));
const auto frame = icon.appear->frame( const auto frame = icon.appear->frame({ size, size }, update);
{ size, size },
[=] { if (_button) _buttonUpdate(_button->geometry()); });
p.drawImage(target, frame.image); p.drawImage(target, frame.image);
} }
} }

View file

@ -75,6 +75,7 @@ public:
[[nodiscard]] bool expandUp() const; [[nodiscard]] bool expandUp() const;
[[nodiscard]] bool isHidden() const; [[nodiscard]] bool isHidden() const;
[[nodiscard]] bool hasInitialView() const;
[[nodiscard]] QRect geometry() const; [[nodiscard]] QRect geometry() const;
[[nodiscard]] int scroll() const; [[nodiscard]] int scroll() const;
[[nodiscard]] float64 currentScale() const; [[nodiscard]] float64 currentScale() const;
@ -146,6 +147,7 @@ private:
struct ReactionIcons { struct ReactionIcons {
std::shared_ptr<Lottie::Icon> appear; std::shared_ptr<Lottie::Icon> appear;
std::shared_ptr<Lottie::Icon> select; std::shared_ptr<Lottie::Icon> select;
bool appearAnimated = false;
}; };
static constexpr auto kFramesCount = 30; static constexpr auto kFramesCount = 30;
@ -178,6 +180,7 @@ private:
void setMainReactionIcon(); void setMainReactionIcon();
void applyPatternedShadow(const QColor &shadow); void applyPatternedShadow(const QColor &shadow);
void clearAppearAnimations();
[[nodiscard]] QRect cacheRect(int frameIndex, int columnIndex) const; [[nodiscard]] QRect cacheRect(int frameIndex, int columnIndex) const;
QRect validateShadow( QRect validateShadow(
int frameIndex, int frameIndex,
@ -223,6 +226,7 @@ private:
base::flat_map<not_null<DocumentData*>, ReactionDocument> _loadCache; base::flat_map<not_null<DocumentData*>, ReactionDocument> _loadCache;
std::vector<ReactionIcons> _icons; std::vector<ReactionIcons> _icons;
rpl::lifetime _loadCacheLifetime; rpl::lifetime _loadCacheLifetime;
bool _showingAll = false;
std::optional<ButtonParameters> _scheduledParameters; std::optional<ButtonParameters> _scheduledParameters;
base::Timer _buttonShowTimer; base::Timer _buttonShowTimer;

View file

@ -983,3 +983,4 @@ reactionCornerActiveAreaPadding: margins(10px, 10px, 10px, 10px);
reactionCornerAddedHeightMax: 120px; reactionCornerAddedHeightMax: 120px;
reactionCornerSkip: 2px; reactionCornerSkip: 2px;
reactionAppearStartSkip: 2px;