mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-06 15:13:57 +02:00
Sync premium sticker effect with sticker frame index.
This commit is contained in:
parent
323cb78f22
commit
a079139c3b
16 changed files with 226 additions and 26 deletions
|
@ -673,7 +673,12 @@ void InnerWidget::elementReplyTo(const FullMsgId &to) {
|
|||
void InnerWidget::elementStartInteraction(not_null<const Element*> view) {
|
||||
}
|
||||
|
||||
void InnerWidget::elementStartPremium(not_null<const Element*> view) {
|
||||
void InnerWidget::elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
Element *replacing) {
|
||||
}
|
||||
|
||||
void InnerWidget::elementCancelPremium(not_null<const Element*> view) {
|
||||
}
|
||||
|
||||
void InnerWidget::elementShowSpoilerAnimation() {
|
||||
|
|
|
@ -139,6 +139,9 @@ public:
|
|||
void elementStartInteraction(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
void elementStartPremium(
|
||||
not_null<const HistoryView::Element*> view,
|
||||
HistoryView::Element *replacing) override;
|
||||
void elementCancelPremium(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
void elementShowSpoilerAnimation() override;
|
||||
|
||||
|
|
|
@ -254,11 +254,20 @@ public:
|
|||
_widget->elementStartInteraction(view);
|
||||
}
|
||||
}
|
||||
void elementStartPremium(not_null<const Element*> view) override {
|
||||
void elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
Element *replacing) override {
|
||||
if (_widget) {
|
||||
_widget->elementStartPremium(view);
|
||||
_widget->elementStartPremium(view, replacing);
|
||||
}
|
||||
}
|
||||
|
||||
void elementCancelPremium(not_null<const Element*> view) override {
|
||||
if (_widget) {
|
||||
_widget->elementCancelPremium(view);
|
||||
}
|
||||
}
|
||||
|
||||
void elementShowSpoilerAnimation() override {
|
||||
if (_widget) {
|
||||
_widget->elementShowSpoilerAnimation();
|
||||
|
@ -3175,11 +3184,17 @@ void HistoryInner::elementStartInteraction(not_null<const Element*> view) {
|
|||
_controller->emojiInteractions().startOutgoing(view);
|
||||
}
|
||||
|
||||
void HistoryInner::elementStartPremium(not_null<const Element*> view) {
|
||||
_emojiInteractions->playPremiumEffect(view);
|
||||
void HistoryInner::elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
Element *replacing) {
|
||||
_emojiInteractions->playPremiumEffect(view, replacing);
|
||||
_animatedStickersPlayed.emplace(view->data());
|
||||
}
|
||||
|
||||
void HistoryInner::elementCancelPremium(not_null<const Element*> view) {
|
||||
_emojiInteractions->cancelPremiumEffect(view);
|
||||
}
|
||||
|
||||
void HistoryInner::elementShowSpoilerAnimation() {
|
||||
_spoilerOpacity.stop();
|
||||
_spoilerOpacity.start([=] { update(); }, 0., 1., st::fadeWrapDuration);
|
||||
|
|
|
@ -145,7 +145,10 @@ public:
|
|||
not_null<Ui::PathShiftGradient*> elementPathShiftGradient();
|
||||
void elementReplyTo(const FullMsgId &to);
|
||||
void elementStartInteraction(not_null<const Element*> view);
|
||||
void elementStartPremium(not_null<const Element*> view);
|
||||
void elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
Element *replacing);
|
||||
void elementCancelPremium(not_null<const Element*> view);
|
||||
void elementShowSpoilerAnimation();
|
||||
|
||||
void updateBotInfo(bool recount = true);
|
||||
|
|
|
@ -206,6 +206,11 @@ void SimpleElementDelegate::elementStartInteraction(
|
|||
}
|
||||
|
||||
void SimpleElementDelegate::elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
Element *replacing) {
|
||||
}
|
||||
|
||||
void SimpleElementDelegate::elementCancelPremium(
|
||||
not_null<const Element*> view) {
|
||||
}
|
||||
|
||||
|
@ -407,6 +412,19 @@ void Element::setY(int y) {
|
|||
void Element::refreshDataIdHook() {
|
||||
}
|
||||
|
||||
void Element::externalLottieProgressing(bool external) const {
|
||||
if (const auto media = _media.get()) {
|
||||
media->externalLottieProgressing(external);
|
||||
}
|
||||
}
|
||||
|
||||
bool Element::externalLottieTill(int frame) const {
|
||||
if (const auto media = _media.get()) {
|
||||
return media->externalLottieTill(frame);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Element::repaint() const {
|
||||
history()->owner().requestViewRepaint(this);
|
||||
}
|
||||
|
|
|
@ -104,7 +104,10 @@ public:
|
|||
virtual not_null<Ui::PathShiftGradient*> elementPathShiftGradient() = 0;
|
||||
virtual void elementReplyTo(const FullMsgId &to) = 0;
|
||||
virtual void elementStartInteraction(not_null<const Element*> view) = 0;
|
||||
virtual void elementStartPremium(not_null<const Element*> view) = 0;
|
||||
virtual void elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
Element *replacing) = 0;
|
||||
virtual void elementCancelPremium(not_null<const Element*> view) = 0;
|
||||
virtual void elementShowSpoilerAnimation() = 0;
|
||||
|
||||
virtual ~ElementDelegate() {
|
||||
|
@ -163,7 +166,10 @@ public:
|
|||
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
|
||||
void elementReplyTo(const FullMsgId &to) override;
|
||||
void elementStartInteraction(not_null<const Element*> view) override;
|
||||
void elementStartPremium(not_null<const Element*> view) override;
|
||||
void elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
Element *replacing) override;
|
||||
void elementCancelPremium(not_null<const Element*> view) override;
|
||||
void elementShowSpoilerAnimation() override;
|
||||
|
||||
protected:
|
||||
|
@ -265,6 +271,9 @@ public:
|
|||
Context context() const;
|
||||
void refreshDataId();
|
||||
|
||||
void externalLottieProgressing(bool external) const;
|
||||
bool externalLottieTill(int frame) const;
|
||||
|
||||
QDateTime dateTime() const;
|
||||
|
||||
int y() const;
|
||||
|
|
|
@ -63,7 +63,13 @@ EmojiInteractions::EmojiInteractions(
|
|||
_premiumSize = Sticker::Size();
|
||||
}
|
||||
|
||||
EmojiInteractions::~EmojiInteractions() = default;
|
||||
EmojiInteractions::~EmojiInteractions() {
|
||||
for (const auto &play : _plays) {
|
||||
if (play.premium) {
|
||||
play.view->externalLottieProgressing(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiInteractions::play(
|
||||
ChatHelpers::EmojiInteractionPlayRequest request,
|
||||
|
@ -90,7 +96,22 @@ void EmojiInteractions::play(
|
|||
}
|
||||
}
|
||||
|
||||
void EmojiInteractions::playPremiumEffect(not_null<const Element*> view) {
|
||||
void EmojiInteractions::playPremiumEffect(
|
||||
not_null<const Element*> view,
|
||||
Element *replacing) {
|
||||
if (replacing) {
|
||||
const auto i = ranges::find(_plays, replacing, &Play::view);
|
||||
if (i != end(_plays)) {
|
||||
if (i->premium) {
|
||||
replacing->externalLottieProgressing(false);
|
||||
}
|
||||
i->view = view;
|
||||
if (i->premium) {
|
||||
view->externalLottieProgressing(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (const auto media = view->media()) {
|
||||
if (const auto document = media->getDocument()) {
|
||||
if (document->isPremiumSticker()) {
|
||||
|
@ -107,6 +128,17 @@ void EmojiInteractions::playPremiumEffect(not_null<const Element*> view) {
|
|||
}
|
||||
}
|
||||
|
||||
void EmojiInteractions::cancelPremiumEffect(not_null<const Element*> view) {
|
||||
_plays.erase(ranges::remove_if(_plays, [&](const Play &play) {
|
||||
if (play.view != view) {
|
||||
return false;
|
||||
} else if (play.premium) {
|
||||
play.view->externalLottieProgressing(false);
|
||||
}
|
||||
return true;
|
||||
}), end(_plays));
|
||||
}
|
||||
|
||||
void EmojiInteractions::play(
|
||||
QString emoticon,
|
||||
not_null<const Element*> view,
|
||||
|
@ -142,17 +174,26 @@ void EmojiInteractions::play(
|
|||
auto lottie = preparePlayer(document, data, filepath, premium);
|
||||
|
||||
const auto shift = premium ? QPoint() : GenerateRandomShift(_emojiSize);
|
||||
const auto raw = lottie.get();
|
||||
lottie->updates(
|
||||
) | rpl::start_with_next([=](Lottie::Update update) {
|
||||
v::match(update.data, [&](const Lottie::Information &information) {
|
||||
}, [&](const Lottie::DisplayFrameRequest &request) {
|
||||
const auto rect = computeRect(view, premium).translated(shift);
|
||||
const auto i = ranges::find(_plays, raw, [](const Play &p) {
|
||||
return p.lottie.get();
|
||||
});
|
||||
const auto rect = computeRect(
|
||||
i->view,
|
||||
i->premium).translated(shift);
|
||||
if (rect.y() + rect.height() >= _visibleTop
|
||||
&& rect.y() <= _visibleBottom) {
|
||||
_updateRequests.fire_copy(rect);
|
||||
}
|
||||
});
|
||||
}, lottie->lifetime());
|
||||
if (premium) {
|
||||
view->externalLottieProgressing(true);
|
||||
}
|
||||
_plays.push_back({
|
||||
.view = view,
|
||||
.lottie = std::move(lottie),
|
||||
|
@ -285,9 +326,18 @@ void EmojiInteractions::paint(QPainter &p) {
|
|||
p.drawImage(
|
||||
QRect(rect.topLeft(), frame.image.size() / factor),
|
||||
frame.image);
|
||||
if (!play.premium || play.view->externalLottieTill(frame.index)) {
|
||||
play.lottie->markFrameShown();
|
||||
}
|
||||
_plays.erase(ranges::remove(_plays, true, &Play::finished), end(_plays));
|
||||
}
|
||||
_plays.erase(ranges::remove_if(_plays, [](const Play &play) {
|
||||
if (!play.finished) {
|
||||
return false;
|
||||
} else if (play.premium) {
|
||||
play.view->externalLottieProgressing(false);
|
||||
}
|
||||
return true;
|
||||
}), end(_plays));
|
||||
checkDelayed();
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,10 @@ public:
|
|||
void play(
|
||||
ChatHelpers::EmojiInteractionPlayRequest request,
|
||||
not_null<Element*> view);
|
||||
void playPremiumEffect(not_null<const Element*> view);
|
||||
void playPremiumEffect(
|
||||
not_null<const Element*> view,
|
||||
Element *replacing);
|
||||
void cancelPremiumEffect(not_null<const Element*> view);
|
||||
void visibleAreaUpdated(int visibleTop, int visibleBottom);
|
||||
|
||||
void paint(QPainter &p);
|
||||
|
|
|
@ -1519,7 +1519,12 @@ void ListWidget::elementReplyTo(const FullMsgId &to) {
|
|||
void ListWidget::elementStartInteraction(not_null<const Element*> view) {
|
||||
}
|
||||
|
||||
void ListWidget::elementStartPremium(not_null<const Element*> view) {
|
||||
void ListWidget::elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
Element *replacing) {
|
||||
}
|
||||
|
||||
void ListWidget::elementCancelPremium(not_null<const Element*> view) {
|
||||
}
|
||||
|
||||
void ListWidget::elementShowSpoilerAnimation() {
|
||||
|
|
|
@ -292,7 +292,11 @@ public:
|
|||
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
|
||||
void elementReplyTo(const FullMsgId &to) override;
|
||||
void elementStartInteraction(not_null<const Element*> view) override;
|
||||
void elementStartPremium(not_null<const Element*> view) override;
|
||||
void elementStartPremium(
|
||||
not_null<const Element*> view,
|
||||
Element *replacing) override;
|
||||
void elementCancelPremium(not_null<const Element*> view) override;
|
||||
|
||||
void elementShowSpoilerAnimation() override;
|
||||
|
||||
void setEmptyInfoWidget(base::unique_qptr<Ui::RpWidget> &&w);
|
||||
|
|
|
@ -173,6 +173,15 @@ public:
|
|||
virtual void checkAnimation() {
|
||||
}
|
||||
|
||||
virtual void externalLottieProgressing(bool external) {
|
||||
}
|
||||
virtual bool externalLottieTill(int frame) {
|
||||
return true;
|
||||
}
|
||||
virtual int externalLottieTillFrame() const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual QSize sizeForGroupingOptimal(int maxWidth) const {
|
||||
Unexpected("Grouping method call.");
|
||||
}
|
||||
|
|
|
@ -460,6 +460,18 @@ std::unique_ptr<Lottie::SinglePlayer> UnwrappedMedia::stickerTakeLottie(
|
|||
return _content->stickerTakeLottie(data, replacements);
|
||||
}
|
||||
|
||||
void UnwrappedMedia::externalLottieProgressing(bool external) {
|
||||
_content->externalLottieProgressing(external);
|
||||
}
|
||||
|
||||
bool UnwrappedMedia::externalLottieTill(int frame) {
|
||||
return _content->externalLottieTill(frame);
|
||||
}
|
||||
|
||||
int UnwrappedMedia::externalLottieTillFrame() const {
|
||||
return _content->externalLottieTillFrame();
|
||||
}
|
||||
|
||||
int UnwrappedMedia::calculateFullRight(const QRect &inner) const {
|
||||
const auto rightAligned = _parent->hasOutLayout()
|
||||
&& !_parent->delegate()->elementIsChatWide();
|
||||
|
|
|
@ -40,6 +40,16 @@ public:
|
|||
virtual std::unique_ptr<Lottie::SinglePlayer> stickerTakeLottie(
|
||||
not_null<DocumentData*> data,
|
||||
const Lottie::ColorReplacements *replacements);
|
||||
|
||||
virtual void externalLottieProgressing(bool external) {
|
||||
}
|
||||
virtual bool externalLottieTill(int frame) {
|
||||
return true;
|
||||
}
|
||||
virtual int externalLottieTillFrame() const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
virtual bool hasHeavyPart() const {
|
||||
return false;
|
||||
}
|
||||
|
@ -92,6 +102,10 @@ public:
|
|||
not_null<DocumentData*> data,
|
||||
const Lottie::ColorReplacements *replacements) override;
|
||||
|
||||
void externalLottieProgressing(bool external) override;
|
||||
bool externalLottieTill(int frame) override;
|
||||
int externalLottieTillFrame() const override;
|
||||
|
||||
bool hasHeavyPart() const override {
|
||||
return _content->hasHeavyPart();
|
||||
}
|
||||
|
|
|
@ -75,6 +75,12 @@ Sticker::Sticker(
|
|||
if (const auto media = replacing ? replacing->media() : nullptr) {
|
||||
_lottie = media->stickerTakeLottie(_data, _replacements);
|
||||
if (_lottie) {
|
||||
_externalTillFrame = media->externalLottieTillFrame();
|
||||
if (_data->isPremiumSticker()
|
||||
&& !_premiumEffectPlayed) {
|
||||
_premiumEffectPlayed = true;
|
||||
_parent->delegate()->elementStartPremium(_parent, replacing);
|
||||
}
|
||||
lottieCreated();
|
||||
}
|
||||
}
|
||||
|
@ -208,21 +214,24 @@ void Sticker::paintLottie(
|
|||
return;
|
||||
}
|
||||
|
||||
const auto paused = _parent->delegate()->elementIsGifPaused();
|
||||
const auto count = _lottie->information().framesCount;
|
||||
_frameIndex = frame.index;
|
||||
_framesCount = count;
|
||||
const auto paused = (_externalTillFrame >= 0)
|
||||
? (_frameIndex >= _externalTillFrame)
|
||||
: _parent->delegate()->elementIsGifPaused();
|
||||
_nextLastDiceFrame = !paused
|
||||
&& (_diceIndex > 0)
|
||||
&& (_frameIndex + 2 == count);
|
||||
const auto playOnce = (_diceIndex > 0)
|
||||
? true
|
||||
: (_diceIndex == 0)
|
||||
? false
|
||||
: (isEmojiSticker()
|
||||
|| !Core::App().settings().loopAnimatedStickers());
|
||||
const auto count = _lottie->information().framesCount;
|
||||
_frameIndex = frame.index;
|
||||
_framesCount = count;
|
||||
_nextLastDiceFrame = !paused
|
||||
&& (_diceIndex > 0)
|
||||
&& (_frameIndex + 2 == count);
|
||||
const auto lastDiceFrame = (_diceIndex > 0) && atTheEnd();
|
||||
const auto switchToNext = !playOnce
|
||||
const auto switchToNext = (_externalTillFrame >= 0)
|
||||
|| !playOnce
|
||||
|| (!lastDiceFrame && (_frameIndex != 0 || !_lottieOncePlayed));
|
||||
if (!paused
|
||||
&& switchToNext
|
||||
|
@ -403,7 +412,7 @@ void Sticker::setupLottie() {
|
|||
if (_data->isPremiumSticker()
|
||||
&& !_premiumEffectPlayed) {
|
||||
_premiumEffectPlayed = true;
|
||||
_parent->delegate()->elementStartPremium(_parent);
|
||||
_parent->delegate()->elementStartPremium(_parent, nullptr);
|
||||
}
|
||||
lottieCreated();
|
||||
}
|
||||
|
@ -417,6 +426,7 @@ void Sticker::lottieCreated() {
|
|||
) | rpl::start_with_next([=](Lottie::Update update) {
|
||||
v::match(update.data, [&](const Lottie::Information &information) {
|
||||
_parent->history()->owner().requestViewResize(_parent);
|
||||
markFramesTillExternal();
|
||||
}, [&](const Lottie::DisplayFrameRequest &request) {
|
||||
_parent->history()->owner().requestViewRepaint(_parent);
|
||||
});
|
||||
|
@ -441,6 +451,9 @@ void Sticker::unloadLottie() {
|
|||
_lottieOncePlayed = false;
|
||||
}
|
||||
_lottie = nullptr;
|
||||
if (_data->isPremiumSticker()) {
|
||||
_parent->delegate()->elementCancelPremium(_parent);
|
||||
}
|
||||
_parent->checkHeavyPart();
|
||||
}
|
||||
|
||||
|
@ -452,4 +465,35 @@ std::unique_ptr<Lottie::SinglePlayer> Sticker::stickerTakeLottie(
|
|||
: nullptr;
|
||||
}
|
||||
|
||||
void Sticker::externalLottieProgressing(bool external) {
|
||||
_externalTillFrame = !external
|
||||
? -1
|
||||
: (_externalTillFrame > 0)
|
||||
? _externalTillFrame
|
||||
: 0;
|
||||
}
|
||||
|
||||
bool Sticker::externalLottieTill(int frame) {
|
||||
_externalTillFrame = (_externalTillFrame >= 0) ? frame : -1;
|
||||
return markFramesTillExternal();
|
||||
}
|
||||
|
||||
int Sticker::externalLottieTillFrame() const {
|
||||
return _externalTillFrame;
|
||||
}
|
||||
|
||||
bool Sticker::markFramesTillExternal() {
|
||||
if (_externalTillFrame < 0 || !_lottie) {
|
||||
return true;
|
||||
} else if (!_lottie->ready()) {
|
||||
return false;
|
||||
}
|
||||
while (_lottie->frameIndex() < _externalTillFrame) {
|
||||
if (!_lottie->markFrameShown()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -51,6 +51,10 @@ public:
|
|||
not_null<DocumentData*> data,
|
||||
const Lottie::ColorReplacements *replacements) override;
|
||||
|
||||
void externalLottieProgressing(bool external) override;
|
||||
bool externalLottieTill(int frame) override;
|
||||
int externalLottieTillFrame() const override;
|
||||
|
||||
bool hasHeavyPart() const override;
|
||||
void unloadHeavyPart() override;
|
||||
|
||||
|
@ -92,6 +96,7 @@ private:
|
|||
void lottieCreated();
|
||||
void unloadLottie();
|
||||
void emojiStickerClicked();
|
||||
bool markFramesTillExternal();
|
||||
|
||||
const not_null<Element*> _parent;
|
||||
const not_null<DocumentData*> _data;
|
||||
|
@ -105,6 +110,7 @@ private:
|
|||
int _diceIndex = -1;
|
||||
mutable int _frameIndex = -1;
|
||||
mutable int _framesCount = -1;
|
||||
int _externalTillFrame = -1;
|
||||
mutable bool _lottieOncePlayed = false;
|
||||
mutable bool _premiumEffectPlayed = false;
|
||||
mutable bool _nextLastDiceFrame = false;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 478da45cf4a3fe8fc75c836de5371234adeada90
|
||||
Subproject commit fb3bb0ef3d46e61debbe3b3dd996bd5050275ba3
|
Loading…
Add table
Reference in a new issue