mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Show appear animations in reactions dropdown.
This commit is contained in:
parent
c0b19000d6
commit
508ba4750c
3 changed files with 64 additions and 5 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -983,3 +983,4 @@ reactionCornerActiveAreaPadding: margins(10px, 10px, 10px, 10px);
|
||||||
reactionCornerAddedHeightMax: 120px;
|
reactionCornerAddedHeightMax: 120px;
|
||||||
|
|
||||||
reactionCornerSkip: 2px;
|
reactionCornerSkip: 2px;
|
||||||
|
reactionAppearStartSkip: 2px;
|
||||||
|
|
Loading…
Add table
Reference in a new issue