mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Fade in/out effect preview.
This commit is contained in:
parent
8a58ded582
commit
487fa9728a
6 changed files with 155 additions and 64 deletions
|
@ -575,7 +575,9 @@ void Reactions::preloadReactionImageFor(const ReactionId &emoji) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reactions::preloadEffectImageFor(EffectId id) {
|
void Reactions::preloadEffectImageFor(EffectId id) {
|
||||||
preloadImageFor({ DocumentId(id) });
|
if (id != kFakeEffectId) {
|
||||||
|
preloadImageFor({ DocumentId(id) });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reactions::preloadImageFor(const ReactionId &id) {
|
void Reactions::preloadImageFor(const ReactionId &id) {
|
||||||
|
@ -651,7 +653,9 @@ QImage Reactions::resolveReactionImageFor(const ReactionId &emoji) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage Reactions::resolveEffectImageFor(EffectId id) {
|
QImage Reactions::resolveEffectImageFor(EffectId id) {
|
||||||
return resolveImageFor({ DocumentId(id) });
|
return (id == kFakeEffectId)
|
||||||
|
? QImage()
|
||||||
|
: resolveImageFor({ DocumentId(id) });
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage Reactions::resolveImageFor(const ReactionId &id) {
|
QImage Reactions::resolveImageFor(const ReactionId &id) {
|
||||||
|
|
|
@ -119,6 +119,10 @@ public:
|
||||||
void preloadReactionImageFor(const ReactionId &emoji);
|
void preloadReactionImageFor(const ReactionId &emoji);
|
||||||
[[nodiscard]] QImage resolveReactionImageFor(const ReactionId &emoji);
|
[[nodiscard]] QImage resolveReactionImageFor(const ReactionId &emoji);
|
||||||
|
|
||||||
|
// This is used to reserve space for the effect in BottomInfo but not
|
||||||
|
// actually paint anything, used in case we want to paint icon ourselves.
|
||||||
|
static constexpr auto kFakeEffectId = EffectId(1);
|
||||||
|
|
||||||
void preloadEffectImageFor(EffectId id);
|
void preloadEffectImageFor(EffectId id);
|
||||||
[[nodiscard]] QImage resolveEffectImageFor(EffectId id);
|
[[nodiscard]] QImage resolveEffectImageFor(EffectId id);
|
||||||
|
|
||||||
|
|
|
@ -203,6 +203,7 @@ Selector::Selector(
|
||||||
TextWithEntities about,
|
TextWithEntities about,
|
||||||
Fn<void(bool fast)> close,
|
Fn<void(bool fast)> close,
|
||||||
IconFactory iconFactory,
|
IconFactory iconFactory,
|
||||||
|
Fn<bool()> paused,
|
||||||
bool child)
|
bool child)
|
||||||
: Selector(
|
: Selector(
|
||||||
parent,
|
parent,
|
||||||
|
@ -216,8 +217,9 @@ Selector::Selector(
|
||||||
: ChatHelpers::EmojiListMode::MessageEffects),
|
: ChatHelpers::EmojiListMode::MessageEffects),
|
||||||
{},
|
{},
|
||||||
std::move(about),
|
std::move(about),
|
||||||
iconFactory,
|
std::move(iconFactory),
|
||||||
close,
|
std::move(paused),
|
||||||
|
std::move(close),
|
||||||
child) {
|
child) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +255,7 @@ Selector::Selector(
|
||||||
std::vector<DocumentId> recent,
|
std::vector<DocumentId> recent,
|
||||||
TextWithEntities about,
|
TextWithEntities about,
|
||||||
IconFactory iconFactory,
|
IconFactory iconFactory,
|
||||||
|
Fn<bool()> paused,
|
||||||
Fn<void(bool fast)> close,
|
Fn<void(bool fast)> close,
|
||||||
bool child)
|
bool child)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
|
@ -261,6 +264,7 @@ Selector::Selector(
|
||||||
, _reactions(reactions)
|
, _reactions(reactions)
|
||||||
, _recent(std::move(recent))
|
, _recent(std::move(recent))
|
||||||
, _listMode(mode)
|
, _listMode(mode)
|
||||||
|
, _paused(std::move(paused))
|
||||||
, _jumpedToPremium([=] { close(false); })
|
, _jumpedToPremium([=] { close(false); })
|
||||||
, _cachedRound(
|
, _cachedRound(
|
||||||
QSize(2 * st::reactStripSkip + st::reactStripSize, st::reactStripHeight),
|
QSize(2 * st::reactStripSkip + st::reactStripSize, st::reactStripHeight),
|
||||||
|
@ -1005,7 +1009,7 @@ void Selector::createList() {
|
||||||
object_ptr<EmojiListWidget>(lists, EmojiListDescriptor{
|
object_ptr<EmojiListWidget>(lists, EmojiListDescriptor{
|
||||||
.show = _show,
|
.show = _show,
|
||||||
.mode = _listMode,
|
.mode = _listMode,
|
||||||
.paused = [] { return false; },
|
.paused = _paused ? _paused : [] { return false; },
|
||||||
.customRecentList = std::move(recentList),
|
.customRecentList = std::move(recentList),
|
||||||
.customRecentFactory = _unifiedFactoryOwner->factory(),
|
.customRecentFactory = _unifiedFactoryOwner->factory(),
|
||||||
.freeEffects = std::move(freeEffects),
|
.freeEffects = std::move(freeEffects),
|
||||||
|
@ -1026,7 +1030,7 @@ void Selector::createList() {
|
||||||
StickersListDescriptor{
|
StickersListDescriptor{
|
||||||
.show = _show,
|
.show = _show,
|
||||||
.mode = StickersListMode::MessageEffects,
|
.mode = StickersListMode::MessageEffects,
|
||||||
.paused = [] { return false; },
|
.paused = _paused ? _paused : [] { return false; },
|
||||||
.customRecentList = std::move(descriptors),
|
.customRecentList = std::move(descriptors),
|
||||||
.st = st,
|
.st = st,
|
||||||
}));
|
}));
|
||||||
|
@ -1352,7 +1356,8 @@ auto AttachSelectorToMenu(
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
const Data::PossibleItemReactionsRef &reactions,
|
const Data::PossibleItemReactionsRef &reactions,
|
||||||
TextWithEntities about,
|
TextWithEntities about,
|
||||||
IconFactory iconFactory)
|
IconFactory iconFactory,
|
||||||
|
Fn<bool()> paused)
|
||||||
-> base::expected<not_null<Selector*>, AttachSelectorResult> {
|
-> base::expected<not_null<Selector*>, AttachSelectorResult> {
|
||||||
if (reactions.recent.empty()) {
|
if (reactions.recent.empty()) {
|
||||||
return base::make_unexpected(AttachSelectorResult::Skipped);
|
return base::make_unexpected(AttachSelectorResult::Skipped);
|
||||||
|
@ -1366,6 +1371,7 @@ auto AttachSelectorToMenu(
|
||||||
std::move(about),
|
std::move(about),
|
||||||
[=](bool fast) { menu->hideMenu(fast); },
|
[=](bool fast) { menu->hideMenu(fast); },
|
||||||
std::move(iconFactory),
|
std::move(iconFactory),
|
||||||
|
std::move(paused),
|
||||||
false); // child
|
false); // child
|
||||||
if (!AdjustMenuGeometryForSelector(menu, desiredPosition, selector)) {
|
if (!AdjustMenuGeometryForSelector(menu, desiredPosition, selector)) {
|
||||||
return base::make_unexpected(AttachSelectorResult::Failed);
|
return base::make_unexpected(AttachSelectorResult::Failed);
|
||||||
|
|
|
@ -85,6 +85,7 @@ public:
|
||||||
TextWithEntities about,
|
TextWithEntities about,
|
||||||
Fn<void(bool fast)> close,
|
Fn<void(bool fast)> close,
|
||||||
IconFactory iconFactory = nullptr,
|
IconFactory iconFactory = nullptr,
|
||||||
|
Fn<bool()> paused = nullptr,
|
||||||
bool child = false);
|
bool child = false);
|
||||||
#if 0 // not ready
|
#if 0 // not ready
|
||||||
Selector(
|
Selector(
|
||||||
|
@ -149,6 +150,7 @@ private:
|
||||||
std::vector<DocumentId> recent,
|
std::vector<DocumentId> recent,
|
||||||
TextWithEntities about,
|
TextWithEntities about,
|
||||||
IconFactory iconFactory,
|
IconFactory iconFactory,
|
||||||
|
Fn<bool()> paused,
|
||||||
Fn<void(bool fast)> close,
|
Fn<void(bool fast)> close,
|
||||||
bool child);
|
bool child);
|
||||||
|
|
||||||
|
@ -187,6 +189,7 @@ private:
|
||||||
const Data::PossibleItemReactions _reactions;
|
const Data::PossibleItemReactions _reactions;
|
||||||
const std::vector<DocumentId> _recent;
|
const std::vector<DocumentId> _recent;
|
||||||
const ChatHelpers::EmojiListMode _listMode;
|
const ChatHelpers::EmojiListMode _listMode;
|
||||||
|
const Fn<bool()> _paused;
|
||||||
Fn<void()> _jumpedToPremium;
|
Fn<void()> _jumpedToPremium;
|
||||||
Ui::RoundAreaWithShadow _cachedRound;
|
Ui::RoundAreaWithShadow _cachedRound;
|
||||||
std::unique_ptr<Strip> _strip;
|
std::unique_ptr<Strip> _strip;
|
||||||
|
@ -274,7 +277,8 @@ AttachSelectorResult AttachSelectorToMenu(
|
||||||
std::shared_ptr<ChatHelpers::Show> show,
|
std::shared_ptr<ChatHelpers::Show> show,
|
||||||
const Data::PossibleItemReactionsRef &reactions,
|
const Data::PossibleItemReactionsRef &reactions,
|
||||||
TextWithEntities about,
|
TextWithEntities about,
|
||||||
IconFactory iconFactory = nullptr
|
IconFactory iconFactory = nullptr,
|
||||||
|
Fn<bool()> paused = nullptr
|
||||||
) -> base::expected<not_null<Selector*>, AttachSelectorResult>;
|
) -> base::expected<not_null<Selector*>, AttachSelectorResult>;
|
||||||
|
|
||||||
[[nodiscard]] TextWithEntities ItemReactionsAbout(
|
[[nodiscard]] TextWithEntities ItemReactionsAbout(
|
||||||
|
|
|
@ -668,7 +668,8 @@ void Reactions::Panel::create() {
|
||||||
? tr::lng_stories_reaction_as_message(tr::now)
|
? tr::lng_stories_reaction_as_message(tr::now)
|
||||||
: QString()) },
|
: QString()) },
|
||||||
[=](bool fast) { hide(mode); },
|
[=](bool fast) { hide(mode); },
|
||||||
nullptr,
|
nullptr, // iconFactory
|
||||||
|
nullptr, // paused
|
||||||
true);
|
true);
|
||||||
|
|
||||||
_selector->chosen(
|
_selector->chosen(
|
||||||
|
|
|
@ -59,6 +59,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace SendMenu {
|
namespace SendMenu {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kToggleDuration = crl::time(400);
|
||||||
|
|
||||||
class Delegate final : public HistoryView::DefaultElementDelegate {
|
class Delegate final : public HistoryView::DefaultElementDelegate {
|
||||||
public:
|
public:
|
||||||
Delegate(not_null<Ui::PathShiftGradient*> pathGradient)
|
Delegate(not_null<Ui::PathShiftGradient*> pathGradient)
|
||||||
|
@ -90,6 +92,8 @@ public:
|
||||||
Fn<void(Action, Details)> action,
|
Fn<void(Action, Details)> action,
|
||||||
Fn<void()> done);
|
Fn<void()> done);
|
||||||
|
|
||||||
|
void hideAnimated();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void mousePressEvent(QMouseEvent *e) override;
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
@ -104,8 +108,12 @@ private:
|
||||||
void setupSend(Details details);
|
void setupSend(Details details);
|
||||||
void createLottie();
|
void createLottie();
|
||||||
|
|
||||||
|
[[nodiscard]] bool ready() const;
|
||||||
|
void paintLoading(QPainter &p);
|
||||||
|
void paintLottie(QPainter &p);
|
||||||
bool checkIconBecameLoaded();
|
bool checkIconBecameLoaded();
|
||||||
[[nodiscard]] bool checkReady();
|
[[nodiscard]] bool checkLoaded();
|
||||||
|
void toggle(bool shown);
|
||||||
|
|
||||||
const EffectId _effectId = 0;
|
const EffectId _effectId = 0;
|
||||||
const Data::Reaction _effect;
|
const Data::Reaction _effect;
|
||||||
|
@ -135,6 +143,10 @@ private:
|
||||||
QRect _iconRect;
|
QRect _iconRect;
|
||||||
std::unique_ptr<Ui::InfiniteRadialAnimation> _loading;
|
std::unique_ptr<Ui::InfiniteRadialAnimation> _loading;
|
||||||
|
|
||||||
|
Ui::Animations::Simple _shownAnimation;
|
||||||
|
QPixmap _bottomCache;
|
||||||
|
bool _hiding = false;
|
||||||
|
|
||||||
rpl::lifetime _readyCheckLifetime;
|
rpl::lifetime _readyCheckLifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -248,7 +260,7 @@ EffectPreview::EffectPreview(
|
||||||
_history->peer->id,
|
_history->peer->id,
|
||||||
_replyTo->data()->fullId(),
|
_replyTo->data()->fullId(),
|
||||||
tr::lng_settings_chat_message_reply(tr::now),
|
tr::lng_settings_chat_message_reply(tr::now),
|
||||||
_effectId))
|
Data::Reactions::kFakeEffectId))
|
||||||
, _send(canSend()
|
, _send(canSend()
|
||||||
? std::make_unique<BottomRounded>(
|
? std::make_unique<BottomRounded>(
|
||||||
this,
|
this,
|
||||||
|
@ -271,68 +283,87 @@ EffectPreview::EffectPreview(
|
||||||
, _close(done)
|
, _close(done)
|
||||||
, _actionWithEffect(ComposeActionWithEffect(action, _effectId, done)) {
|
, _actionWithEffect(ComposeActionWithEffect(action, _effectId, done)) {
|
||||||
setupGeometry(position);
|
setupGeometry(position);
|
||||||
setupBackground();
|
|
||||||
setupItem();
|
setupItem();
|
||||||
|
setupBackground();
|
||||||
setupLottie();
|
setupLottie();
|
||||||
setupSend(details);
|
setupSend(details);
|
||||||
|
|
||||||
|
toggle(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectPreview::paintEvent(QPaintEvent *e) {
|
void EffectPreview::paintEvent(QPaintEvent *e) {
|
||||||
auto p = Painter(this);
|
checkIconBecameLoaded();
|
||||||
|
|
||||||
|
const auto progress = _shownAnimation.value(_hiding ? 0. : 1.);
|
||||||
|
if (!progress) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto p = QPainter(this);
|
||||||
|
p.setOpacity(progress);
|
||||||
p.drawImage(0, 0, _bg);
|
p.drawImage(0, 0, _bg);
|
||||||
|
|
||||||
p.setClipRect(_inner);
|
if (!_bottomCache.isNull()) {
|
||||||
p.translate(_itemShift);
|
p.drawPixmap(_bottom->pos(), _bottomCache);
|
||||||
auto rect = QRect(0, 0, st::windowMinWidth, _inner.height());
|
}
|
||||||
auto context = _theme->preparePaintContext(
|
|
||||||
_chatStyle.get(),
|
|
||||||
rect,
|
|
||||||
rect,
|
|
||||||
false);
|
|
||||||
context.outbg = _item->hasOutLayout();
|
|
||||||
_item->draw(p, context);
|
|
||||||
p.translate(-_itemShift);
|
|
||||||
|
|
||||||
checkIconBecameLoaded();
|
if (!ready()) {
|
||||||
if (_icon.isNull()) {
|
paintLoading(p);
|
||||||
if (!_loading) {
|
|
||||||
_loading = std::make_unique<Ui::InfiniteRadialAnimation>([=] {
|
|
||||||
update();
|
|
||||||
}, st::effectPreviewLoading);
|
|
||||||
_loading->start(st::defaultInfiniteRadialAnimation.linearPeriod);
|
|
||||||
}
|
|
||||||
const auto loading = _iconRect.marginsRemoved(
|
|
||||||
{ st::lineWidth, st::lineWidth, st::lineWidth, st::lineWidth });
|
|
||||||
auto hq = PainterHighQualityEnabler(p);
|
|
||||||
Ui::InfiniteRadialAnimation::Draw(
|
|
||||||
p,
|
|
||||||
_loading->computeState(),
|
|
||||||
loading.topLeft(),
|
|
||||||
loading.size(),
|
|
||||||
width(),
|
|
||||||
_chatStyle->msgInDateFg(),
|
|
||||||
st::effectPreviewLoading.thickness);
|
|
||||||
} else {
|
} else {
|
||||||
_loading = nullptr;
|
_loading = nullptr;
|
||||||
}
|
p.drawImage(_iconRect, _icon);
|
||||||
if (_lottie && _lottie->ready()) {
|
if (!_hiding) {
|
||||||
const auto factor = style::DevicePixelRatio();
|
p.setOpacity(1.);
|
||||||
auto request = Lottie::FrameRequest();
|
|
||||||
request.box = _inner.size() * factor;
|
|
||||||
const auto rightAligned = _item->hasRightLayout();
|
|
||||||
if (!rightAligned) {
|
|
||||||
request.mirrorHorizontal = true;
|
|
||||||
}
|
}
|
||||||
const auto frame = _lottie->frameInfo(request);
|
paintLottie(p);
|
||||||
p.drawImage(
|
|
||||||
QRect(_inner.topLeft(), frame.image.size() / factor),
|
|
||||||
frame.image);
|
|
||||||
_lottie->markFrameShown();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EffectPreview::ready() const {
|
||||||
|
return !_icon.isNull() && _lottie && _lottie->ready();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectPreview::paintLoading(QPainter &p) {
|
||||||
|
if (!_loading) {
|
||||||
|
_loading = std::make_unique<Ui::InfiniteRadialAnimation>([=] {
|
||||||
|
update();
|
||||||
|
}, st::effectPreviewLoading);
|
||||||
|
_loading->start(st::defaultInfiniteRadialAnimation.linearPeriod);
|
||||||
|
}
|
||||||
|
const auto loading = _iconRect.marginsRemoved(
|
||||||
|
{ st::lineWidth, st::lineWidth, st::lineWidth, st::lineWidth });
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
Ui::InfiniteRadialAnimation::Draw(
|
||||||
|
p,
|
||||||
|
_loading->computeState(),
|
||||||
|
loading.topLeft(),
|
||||||
|
loading.size(),
|
||||||
|
width(),
|
||||||
|
_chatStyle->msgInDateFg(),
|
||||||
|
st::effectPreviewLoading.thickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectPreview::paintLottie(QPainter &p) {
|
||||||
|
const auto factor = style::DevicePixelRatio();
|
||||||
|
auto request = Lottie::FrameRequest();
|
||||||
|
request.box = _inner.size() * factor;
|
||||||
|
const auto rightAligned = _item->hasRightLayout();
|
||||||
|
if (!rightAligned) {
|
||||||
|
request.mirrorHorizontal = true;
|
||||||
|
}
|
||||||
|
const auto frame = _lottie->frameInfo(request);
|
||||||
|
p.drawImage(
|
||||||
|
QRect(_inner.topLeft(), frame.image.size() / factor),
|
||||||
|
frame.image);
|
||||||
|
_lottie->markFrameShown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectPreview::hideAnimated() {
|
||||||
|
toggle(false);
|
||||||
|
}
|
||||||
|
|
||||||
void EffectPreview::mousePressEvent(QMouseEvent *e) {
|
void EffectPreview::mousePressEvent(QMouseEvent *e) {
|
||||||
delete this;
|
hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EffectPreview::setupGeometry(QPoint position) {
|
void EffectPreview::setupGeometry(QPoint position) {
|
||||||
|
@ -402,7 +433,7 @@ void EffectPreview::repaintBackground() {
|
||||||
bg.setDevicePixelRatio(ratio);
|
bg.setDevicePixelRatio(ratio);
|
||||||
|
|
||||||
{
|
{
|
||||||
auto p = QPainter(&bg);
|
auto p = Painter(&bg);
|
||||||
Window::SectionWidget::PaintBackground(
|
Window::SectionWidget::PaintBackground(
|
||||||
p,
|
p,
|
||||||
_theme.get(),
|
_theme.get(),
|
||||||
|
@ -411,6 +442,18 @@ void EffectPreview::repaintBackground() {
|
||||||
p.fillRect(
|
p.fillRect(
|
||||||
QRect(0, _inner.height(), _inner.width(), _bottom->height()),
|
QRect(0, _inner.height(), _inner.width(), _bottom->height()),
|
||||||
st::previewMarkRead.bgColor);
|
st::previewMarkRead.bgColor);
|
||||||
|
|
||||||
|
p.translate(_itemShift - _inner.topLeft());
|
||||||
|
auto rect = QRect(0, 0, st::windowMinWidth, _inner.height());
|
||||||
|
auto context = _theme->preparePaintContext(
|
||||||
|
_chatStyle.get(),
|
||||||
|
rect,
|
||||||
|
rect,
|
||||||
|
false);
|
||||||
|
context.outbg = _item->hasOutLayout();
|
||||||
|
_item->draw(p, context);
|
||||||
|
p.translate(_inner.topLeft() - _itemShift);
|
||||||
|
|
||||||
auto hq = PainterHighQualityEnabler(p);
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
||||||
auto roundRect = Ui::RoundRect(st::previewMenu.radius, st::menuBg);
|
auto roundRect = Ui::RoundRect(st::previewMenu.radius, st::menuBg);
|
||||||
|
@ -438,7 +481,7 @@ void EffectPreview::setupLottie() {
|
||||||
rpl::single(rpl::empty) | rpl::then(
|
rpl::single(rpl::empty) | rpl::then(
|
||||||
_show->session().downloaderTaskFinished()
|
_show->session().downloaderTaskFinished()
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
if (checkReady()) {
|
if (checkLoaded()) {
|
||||||
_readyCheckLifetime.destroy();
|
_readyCheckLifetime.destroy();
|
||||||
createLottie();
|
createLottie();
|
||||||
}
|
}
|
||||||
|
@ -495,10 +538,14 @@ bool EffectPreview::checkIconBecameLoaded() {
|
||||||
}
|
}
|
||||||
const auto reactions = &_show->session().data().reactions();
|
const auto reactions = &_show->session().data().reactions();
|
||||||
_icon = reactions->resolveEffectImageFor(_effect.id.custom());
|
_icon = reactions->resolveEffectImageFor(_effect.id.custom());
|
||||||
return !_icon.isNull();
|
if (_icon.isNull()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
repaintBackground();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EffectPreview::checkReady() {
|
bool EffectPreview::checkLoaded() {
|
||||||
if (checkIconBecameLoaded()) {
|
if (checkIconBecameLoaded()) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
@ -511,6 +558,29 @@ bool EffectPreview::checkReady() {
|
||||||
return !_icon.isNull() && (!_bytes.isEmpty() || !_filepath.isEmpty());
|
return !_icon.isNull() && (!_bytes.isEmpty() || !_filepath.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EffectPreview::toggle(bool shown) {
|
||||||
|
if (!shown && _hiding) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_hiding = !shown;
|
||||||
|
if (_bottomCache.isNull()) {
|
||||||
|
_bottomCache = Ui::GrabWidget(_bottom);
|
||||||
|
_bottom->hide();
|
||||||
|
}
|
||||||
|
_shownAnimation.start([=] {
|
||||||
|
update();
|
||||||
|
if (!_shownAnimation.animating()) {
|
||||||
|
if (_hiding) {
|
||||||
|
delete this;
|
||||||
|
} else {
|
||||||
|
_bottomCache = QPixmap();
|
||||||
|
_bottom->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, shown ? 0. : 1., shown ? 1. : 0., kToggleDuration, anim::easeOutCirc);
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Fn<void(Action, Details)> DefaultCallback(
|
Fn<void(Action, Details)> DefaultCallback(
|
||||||
|
@ -571,6 +641,7 @@ FillMenuResult FillSendMenu(
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace HistoryView::Reactions;
|
using namespace HistoryView::Reactions;
|
||||||
|
const auto effect = std::make_shared<QPointer<EffectPreview>>();
|
||||||
const auto position = desiredPositionOverride.value_or(QCursor::pos());
|
const auto position = desiredPositionOverride.value_or(QCursor::pos());
|
||||||
const auto selector = (showForEffect && details.effectAllowed)
|
const auto selector = (showForEffect && details.effectAllowed)
|
||||||
? AttachSelectorToMenu(
|
? AttachSelectorToMenu(
|
||||||
|
@ -579,7 +650,9 @@ FillMenuResult FillSendMenu(
|
||||||
st::reactPanelEmojiPan,
|
st::reactPanelEmojiPan,
|
||||||
showForEffect,
|
showForEffect,
|
||||||
LookupPossibleEffects(&showForEffect->session()),
|
LookupPossibleEffects(&showForEffect->session()),
|
||||||
{ tr::lng_effect_add_title(tr::now) })
|
{ tr::lng_effect_add_title(tr::now) },
|
||||||
|
nullptr, // iconFactory
|
||||||
|
[=] { return (*effect) != nullptr; }) // paused
|
||||||
: base::make_unexpected(AttachSelectorResult::Skipped);
|
: base::make_unexpected(AttachSelectorResult::Skipped);
|
||||||
if (!selector) {
|
if (!selector) {
|
||||||
if (selector.error() == AttachSelectorResult::Failed) {
|
if (selector.error() == AttachSelectorResult::Failed) {
|
||||||
|
@ -589,7 +662,6 @@ FillMenuResult FillSendMenu(
|
||||||
return FillMenuResult::Prepared;
|
return FillMenuResult::Prepared;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto effect = std::make_shared<QPointer<EffectPreview>>();
|
|
||||||
(*selector)->chosen(
|
(*selector)->chosen(
|
||||||
) | rpl::start_with_next([=](ChosenReaction chosen) {
|
) | rpl::start_with_next([=](ChosenReaction chosen) {
|
||||||
const auto &reactions = showForEffect->session().data().reactions();
|
const auto &reactions = showForEffect->session().data().reactions();
|
||||||
|
@ -597,7 +669,7 @@ FillMenuResult FillSendMenu(
|
||||||
const auto i = ranges::find(effects, chosen.id, &Data::Reaction::id);
|
const auto i = ranges::find(effects, chosen.id, &Data::Reaction::id);
|
||||||
if (i != end(effects)) {
|
if (i != end(effects)) {
|
||||||
if (const auto strong = effect->data()) {
|
if (const auto strong = effect->data()) {
|
||||||
delete strong;
|
strong->hideAnimated();
|
||||||
}
|
}
|
||||||
const auto weak = Ui::MakeWeak(menu);
|
const auto weak = Ui::MakeWeak(menu);
|
||||||
const auto done = [=] {
|
const auto done = [=] {
|
||||||
|
|
Loading…
Add table
Reference in a new issue