Added expand/collapse animation to emoji picker overlay.

This commit is contained in:
23rd
2026-04-13 21:42:43 +03:00
parent 3bddcb5461
commit 7b720b2a3f
3 changed files with 73 additions and 36 deletions
@@ -212,10 +212,15 @@ void CreateStickerBox(
.maxSelected = kMaxEmojis, .maxSelected = kMaxEmojis,
.allowExpand = true, .allowExpand = true,
}; };
const auto overlayExpanded = [&] { const auto pickerCollapsed = [&] {
auto probe = ChatHelpers::EmojiPickerOverlay(nullptr, pickerDescriptor);
return probe.collapsedHeight();
}();
const auto pickerExpanded = [&] {
auto probe = ChatHelpers::EmojiPickerOverlay(nullptr, pickerDescriptor); auto probe = ChatHelpers::EmojiPickerOverlay(nullptr, pickerDescriptor);
return probe.expandedHeight(); return probe.expandedHeight();
}(); }();
const auto pickerExtra = pickerExpanded - pickerCollapsed;
const auto previewHolder = inner->add( const auto previewHolder = inner->add(
object_ptr<Ui::RpWidget>(inner), object_ptr<Ui::RpWidget>(inner),
@@ -223,7 +228,7 @@ void CreateStickerBox(
style::al_top); style::al_top);
previewHolder->resize( previewHolder->resize(
st::boxWideWidth, st::boxWideWidth,
kPreviewSide + overlayExpanded / 2); kPreviewSide + pickerExtra);
const auto preview = Ui::CreateChild<PreviewWidget>( const auto preview = Ui::CreateChild<PreviewWidget>(
previewHolder, previewHolder,
image); image);
@@ -236,12 +241,9 @@ void CreateStickerBox(
const auto w = std::min( const auto w = std::min(
previewHolder->width() - 2 * st::boxRowPadding.left(), previewHolder->width() - 2 * st::boxRowPadding.left(),
int(kPreviewSide * 1.1)); int(kPreviewSide * 1.1));
const auto h = picker->expanded()
? picker->expandedHeight()
: picker->collapsedHeight();
const auto x = (previewHolder->width() - w) / 2; const auto x = (previewHolder->width() - w) / 2;
const auto y = kPreviewSide - h; const auto y = kPreviewSide - pickerCollapsed;
picker->setGeometry(x, y, w, h); picker->setGeometry(x, y, w, pickerExpanded);
picker->raise(); picker->raise();
}; };
@@ -251,11 +253,6 @@ void CreateStickerBox(
layoutOverlay(); layoutOverlay();
}, preview->lifetime()); }, preview->lifetime());
picker->expandedValue(
) | rpl::on_next([=](bool) {
layoutOverlay();
}, picker->lifetime());
Ui::AddSkip(inner); Ui::AddSkip(inner);
const auto startUpload = [=, set = std::move(set), done = std::move(done)]( const auto startUpload = [=, set = std::move(set), done = std::move(done)](
@@ -240,7 +240,7 @@ void EmojiPickerOverlay::Strip::mouseReleaseEvent(QMouseEvent *e) {
const auto index = _pressed; const auto index = _pressed;
_pressed = -1; _pressed = -1;
if (released == index && index >= 0 && index < int(_cells.size())) { if (released == index && index >= 0 && index < int(_cells.size())) {
_owner->toggleEmoji(_cells[index].emoji); _owner->toggleEmoji(_cells[index].emoji, false);
} }
} }
@@ -346,7 +346,7 @@ void EmojiPickerOverlay::Grid::mouseReleaseEvent(QMouseEvent *e) {
const auto index = _pressed; const auto index = _pressed;
_pressed = -1; _pressed = -1;
if (released == index && index >= 0 && index < int(_cells.size())) { if (released == index && index >= 0 && index < int(_cells.size())) {
_owner->toggleEmoji(_cells[index].emoji); _owner->toggleEmoji(_cells[index].emoji, true);
} }
} }
@@ -402,22 +402,10 @@ EmojiPickerOverlay::EmojiPickerOverlay(
object_ptr<Grid>(_scroll.get(), this)); object_ptr<Grid>(_scroll.get(), this));
_grid = gridPtr.data(); _grid = gridPtr.data();
_grid->setEmojis(_allForGrid); _grid->setEmojis(_allForGrid);
_expanded.value(
) | rpl::on_next([=](bool value) {
if (_scroll) {
_scroll->setVisible(value);
}
if (_expandButton) {
_expandButton->update();
}
resize(width(), value ? expandedHeight() : collapsedHeight());
relayout();
}, lifetime());
} }
_selectedVar = _selectedList; _selectedVar = _selectedList;
resize(width(), collapsedHeight()); resize(width(), expandedHeight());
} }
EmojiPickerOverlay::~EmojiPickerOverlay() = default; EmojiPickerOverlay::~EmojiPickerOverlay() = default;
@@ -432,10 +420,49 @@ EmojiPickerOverlay::selectedValue() const {
} }
void EmojiPickerOverlay::setExpanded(bool expanded) { void EmojiPickerOverlay::setExpanded(bool expanded) {
if (!_allowExpand) { if (!_allowExpand || _expanded.current() == expanded) {
return; return;
} }
startExpandAnimation(expanded);
_expanded = expanded; _expanded = expanded;
if (_expandButton) {
_expandButton->update();
}
}
void EmojiPickerOverlay::startExpandAnimation(bool expanded) {
const auto from = _expandAnim.value(expanded ? 0. : 1.);
const auto to = expanded ? 1. : 0.;
_expandAnim.start(
[=] { applyExpandProgress(); },
from,
to,
st::slideWrapDuration,
anim::easeOutCirc);
applyExpandProgress();
}
float64 EmojiPickerOverlay::currentExpandValue() const {
return _expandAnim.value(_expanded.current() ? 1. : 0.);
}
int EmojiPickerOverlay::currentShownHeight() const {
const auto progress = currentExpandValue();
return anim::interpolate(
collapsedHeight(),
expandedHeight(),
progress);
}
void EmojiPickerOverlay::applyExpandProgress() {
const auto h = currentShownHeight();
setMask(QRegion(0, 0, width(), h));
if (_scroll) {
const auto progress = currentExpandValue();
_scroll->setVisible(progress > 0.);
}
relayout();
update();
} }
bool EmojiPickerOverlay::expanded() const { bool EmojiPickerOverlay::expanded() const {
@@ -465,13 +492,21 @@ void EmojiPickerOverlay::paintEvent(QPaintEvent *e) {
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setBrush(st::stickersEmojiPickerBg); p.setBrush(st::stickersEmojiPickerBg);
const auto radius = st::stickersEmojiPickerRadius; const auto radius = st::stickersEmojiPickerRadius;
p.drawRoundedRect(rect(), radius, radius); const auto h = currentShownHeight();
p.drawRoundedRect(QRect(0, 0, width(), h), radius, radius);
} }
void EmojiPickerOverlay::resizeEvent(QResizeEvent *e) { void EmojiPickerOverlay::resizeEvent(QResizeEvent *e) {
setMask(QRegion(0, 0, width(), currentShownHeight()));
relayout(); relayout();
} }
void EmojiPickerOverlay::mousePressEvent(QMouseEvent *e) {
if (e->pos().y() > currentShownHeight()) {
e->ignore();
}
}
void EmojiPickerOverlay::relayout() { void EmojiPickerOverlay::relayout() {
const auto &pad = st::stickersEmojiPickerPadding; const auto &pad = st::stickersEmojiPickerPadding;
if (_about) { if (_about) {
@@ -520,7 +555,7 @@ void EmojiPickerOverlay::relayout() {
} }
} }
void EmojiPickerOverlay::toggleEmoji(EmojiPtr emoji) { void EmojiPickerOverlay::toggleEmoji(EmojiPtr emoji, bool fromGrid) {
if (!emoji) { if (!emoji) {
return; return;
} }
@@ -537,6 +572,9 @@ void EmojiPickerOverlay::toggleEmoji(EmojiPtr emoji) {
_selectedList.push_back(emoji); _selectedList.push_back(emoji);
} }
notifySelectionChanged(); notifySelectionChanged();
if (fromGrid) {
setExpanded(false);
}
} }
void EmojiPickerOverlay::notifySelectionChanged() { void EmojiPickerOverlay::notifySelectionChanged() {
@@ -549,8 +587,4 @@ void EmojiPickerOverlay::notifySelectionChanged() {
} }
} }
void EmojiPickerOverlay::buildSections() {
// Reserved for potential future categorised rendering in the grid.
}
} // namespace ChatHelpers } // namespace ChatHelpers
@@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
#include "ui/effects/animations.h"
#include "ui/emoji_config.h" #include "ui/emoji_config.h"
namespace Ui { namespace Ui {
@@ -46,15 +47,19 @@ public:
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
private: private:
class Strip; class Strip;
class Grid; class Grid;
void buildSections();
void relayout(); void relayout();
void toggleEmoji(EmojiPtr emoji); void toggleEmoji(EmojiPtr emoji, bool fromGrid);
void notifySelectionChanged(); void notifySelectionChanged();
void startExpandAnimation(bool expanded);
void applyExpandProgress();
[[nodiscard]] float64 currentExpandValue() const;
[[nodiscard]] int currentShownHeight() const;
const QString _aboutText; const QString _aboutText;
const std::vector<EmojiPtr> _recent; const std::vector<EmojiPtr> _recent;
@@ -72,6 +77,7 @@ private:
Ui::AbstractButton *_expandButton = nullptr; Ui::AbstractButton *_expandButton = nullptr;
std::unique_ptr<Ui::ScrollArea> _scroll; std::unique_ptr<Ui::ScrollArea> _scroll;
Grid *_grid = nullptr; Grid *_grid = nullptr;
Ui::Animations::Simple _expandAnim;
}; };