Play premium sticker effects.

This commit is contained in:
John Preston 2022-04-22 20:23:47 +04:00
parent d87c9c72fb
commit 935fb79c52
15 changed files with 168 additions and 40 deletions

View file

@ -254,6 +254,7 @@ void DocumentMedia::videoThumbnailWanted(Data::FileOrigin origin) {
void DocumentMedia::setVideoThumbnail(QByteArray content) { void DocumentMedia::setVideoThumbnail(QByteArray content) {
_videoThumbnailBytes = std::move(content); _videoThumbnailBytes = std::move(content);
_videoThumbnailBytes.detach();
} }
void DocumentMedia::checkStickerLarge() { void DocumentMedia::checkStickerLarge() {

View file

@ -414,6 +414,7 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
| Flag::Scam | Flag::Scam
| Flag::Fake | Flag::Fake
| Flag::BotInlineGeo | Flag::BotInlineGeo
| Flag::Premium
| Flag::Support | Flag::Support
| (!minimal | (!minimal
? Flag::Contact ? Flag::Contact
@ -2827,7 +2828,7 @@ void Session::documentApplyFields(
? Images::FromVideoSize(_session, data, *videoThumbnailSize) ? Images::FromVideoSize(_session, data, *videoThumbnailSize)
: ImageWithLocation(); : ImageWithLocation();
const auto isPremiumSticker = videoThumbnailSize const auto isPremiumSticker = videoThumbnailSize
&& (videoThumbnailSize->c_videoSize().vtype().v == "fp"); && (videoThumbnailSize->c_videoSize().vtype().v == "f");
documentApplyFields( documentApplyFields(
document, document,
data.vaccess_hash().v, data.vaccess_hash().v,

View file

@ -673,6 +673,9 @@ void InnerWidget::elementReplyTo(const FullMsgId &to) {
void InnerWidget::elementStartInteraction(not_null<const Element*> view) { void InnerWidget::elementStartInteraction(not_null<const Element*> view) {
} }
void InnerWidget::elementStartPremium(not_null<const Element*> view) {
}
void InnerWidget::elementShowSpoilerAnimation() { void InnerWidget::elementShowSpoilerAnimation() {
_spoilerOpacity.stop(); _spoilerOpacity.stop();
_spoilerOpacity.start([=] { update(); }, 0., 1., st::fadeWrapDuration); _spoilerOpacity.start([=] { update(); }, 0., 1., st::fadeWrapDuration);

View file

@ -138,6 +138,8 @@ public:
void elementReplyTo(const FullMsgId &to) override; void elementReplyTo(const FullMsgId &to) override;
void elementStartInteraction( void elementStartInteraction(
not_null<const HistoryView::Element*> view) override; not_null<const HistoryView::Element*> view) override;
void elementStartPremium(
not_null<const HistoryView::Element*> view) override;
void elementShowSpoilerAnimation() override; void elementShowSpoilerAnimation() override;
~InnerWidget(); ~InnerWidget();

View file

@ -254,6 +254,11 @@ public:
_widget->elementStartInteraction(view); _widget->elementStartInteraction(view);
} }
} }
void elementStartPremium(not_null<const Element*> view) override {
if (_widget) {
_widget->elementStartPremium(view);
}
}
void elementShowSpoilerAnimation() override { void elementShowSpoilerAnimation() override {
if (_widget) { if (_widget) {
_widget->elementShowSpoilerAnimation(); _widget->elementShowSpoilerAnimation();
@ -3171,6 +3176,11 @@ void HistoryInner::elementStartInteraction(not_null<const Element*> view) {
_controller->emojiInteractions().startOutgoing(view); _controller->emojiInteractions().startOutgoing(view);
} }
void HistoryInner::elementStartPremium(not_null<const Element*> view) {
_emojiInteractions->playPremiumEffect(view);
_animatedStickersPlayed.emplace(view->data());
}
void HistoryInner::elementShowSpoilerAnimation() { void HistoryInner::elementShowSpoilerAnimation() {
_spoilerOpacity.stop(); _spoilerOpacity.stop();
_spoilerOpacity.start([=] { update(); }, 0., 1., st::fadeWrapDuration); _spoilerOpacity.start([=] { update(); }, 0., 1., st::fadeWrapDuration);

View file

@ -145,6 +145,7 @@ public:
not_null<Ui::PathShiftGradient*> elementPathShiftGradient(); not_null<Ui::PathShiftGradient*> elementPathShiftGradient();
void elementReplyTo(const FullMsgId &to); void elementReplyTo(const FullMsgId &to);
void elementStartInteraction(not_null<const Element*> view); void elementStartInteraction(not_null<const Element*> view);
void elementStartPremium(not_null<const Element*> view);
void elementShowSpoilerAnimation(); void elementShowSpoilerAnimation();
void updateBotInfo(bool recount = true); void updateBotInfo(bool recount = true);

View file

@ -205,6 +205,10 @@ void SimpleElementDelegate::elementStartInteraction(
not_null<const Element*> view) { not_null<const Element*> view) {
} }
void SimpleElementDelegate::elementStartPremium(
not_null<const Element*> view) {
}
void SimpleElementDelegate::elementShowSpoilerAnimation() { void SimpleElementDelegate::elementShowSpoilerAnimation() {
} }

View file

@ -104,6 +104,7 @@ public:
virtual not_null<Ui::PathShiftGradient*> elementPathShiftGradient() = 0; virtual not_null<Ui::PathShiftGradient*> elementPathShiftGradient() = 0;
virtual void elementReplyTo(const FullMsgId &to) = 0; virtual void elementReplyTo(const FullMsgId &to) = 0;
virtual void elementStartInteraction(not_null<const Element*> view) = 0; virtual void elementStartInteraction(not_null<const Element*> view) = 0;
virtual void elementStartPremium(not_null<const Element*> view) = 0;
virtual void elementShowSpoilerAnimation() = 0; virtual void elementShowSpoilerAnimation() = 0;
virtual ~ElementDelegate() { virtual ~ElementDelegate() {
@ -162,6 +163,7 @@ public:
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override; not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
void elementReplyTo(const FullMsgId &to) override; void elementReplyTo(const FullMsgId &to) override;
void elementStartInteraction(not_null<const Element*> view) override; void elementStartInteraction(not_null<const Element*> view) override;
void elementStartPremium(not_null<const Element*> view) override;
void elementShowSpoilerAnimation() override; void elementShowSpoilerAnimation() override;
protected: protected:

View file

@ -24,8 +24,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace HistoryView { namespace HistoryView {
namespace { namespace {
constexpr auto kSizeMultiplier = 3; constexpr auto kEmojiMultiplier = 3;
constexpr auto kCachesCount = 4; constexpr auto kPremiumMultiplier = 2.25;
constexpr auto kEmojiCachesCount = 4;
constexpr auto kPremiumCachesCount = 8;
constexpr auto kMaxPlays = 5; constexpr auto kMaxPlays = 5;
constexpr auto kMaxPlaysWithSmallDelay = 3; constexpr auto kMaxPlaysWithSmallDelay = 3;
constexpr auto kSmallDelay = crl::time(200); constexpr auto kSmallDelay = crl::time(200);
@ -55,6 +57,7 @@ EmojiInteractions::EmojiInteractions(not_null<Main::Session*> session)
}, _lifetime); }, _lifetime);
_emojiSize = Sticker::EmojiSize(); _emojiSize = Sticker::EmojiSize();
_premiumSize = Sticker::Size();
} }
EmojiInteractions::~EmojiInteractions() = default; EmojiInteractions::~EmojiInteractions() = default;
@ -84,27 +87,63 @@ void EmojiInteractions::play(
} }
} }
void EmojiInteractions::playPremiumEffect(not_null<const Element*> view) {
if (const auto media = view->media()) {
if (const auto document = media->getDocument()) {
if (document->isPremiumSticker()) {
play(
QString(),
view,
document,
document->createMediaView()->videoThumbnailContent(),
QString(),
false,
true);
}
}
}
}
void EmojiInteractions::play( void EmojiInteractions::play(
QString emoticon, QString emoticon,
not_null<Element*> view, not_null<const Element*> view,
std::shared_ptr<Data::DocumentMedia> media, std::shared_ptr<Data::DocumentMedia> media,
bool incoming) { bool incoming) {
play(
std::move(emoticon),
view,
media->owner(),
media->bytes(),
media->owner()->filepath(),
incoming,
false);
}
void EmojiInteractions::play(
QString emoticon,
not_null<const Element*> view,
not_null<DocumentData*> document,
QByteArray data,
QString filepath,
bool incoming,
bool premium) {
const auto top = view->block()->y() + view->y(); const auto top = view->block()->y() + view->y();
const auto bottom = top + view->height(); const auto bottom = top + view->height();
if (_visibleTop >= bottom if (_visibleTop >= bottom
|| _visibleBottom <= top || _visibleBottom <= top
|| _visibleTop == _visibleBottom) { || _visibleTop == _visibleBottom
|| (data.isEmpty() && filepath.isEmpty())) {
return; return;
} }
auto lottie = preparePlayer(media.get()); auto lottie = preparePlayer(document, data, filepath, premium);
const auto shift = GenerateRandomShift(_emojiSize); const auto shift = premium ? QPoint() : GenerateRandomShift(_emojiSize);
lottie->updates( lottie->updates(
) | rpl::start_with_next([=](Lottie::Update update) { ) | rpl::start_with_next([=](Lottie::Update update) {
v::match(update.data, [&](const Lottie::Information &information) { v::match(update.data, [&](const Lottie::Information &information) {
}, [&](const Lottie::DisplayFrameRequest &request) { }, [&](const Lottie::DisplayFrameRequest &request) {
const auto rect = computeRect(view).translated(shift); const auto rect = computeRect(view, premium).translated(shift);
if (rect.y() + rect.height() >= _visibleTop if (rect.y() + rect.height() >= _visibleTop
&& rect.y() <= _visibleBottom) { && rect.y() <= _visibleBottom) {
_updateRequests.fire_copy(rect); _updateRequests.fire_copy(rect);
@ -115,19 +154,30 @@ void EmojiInteractions::play(
.view = view, .view = view,
.lottie = std::move(lottie), .lottie = std::move(lottie),
.shift = shift, .shift = shift,
.premium = premium,
}); });
if (incoming) { if (incoming) {
_playStarted.fire(std::move(emoticon)); _playStarted.fire(std::move(emoticon));
} }
if (const auto media = view->media()) { if (const auto media = view->media()) {
media->stickerClearLoopPlayed(); if (!premium) {
media->stickerClearLoopPlayed();
}
} }
} }
QSize EmojiInteractions::sizeFor(bool premium) const {
return premium
? (_premiumSize * kPremiumMultiplier)
: (_emojiSize * kEmojiMultiplier);
}
std::unique_ptr<Lottie::SinglePlayer> EmojiInteractions::preparePlayer( std::unique_ptr<Lottie::SinglePlayer> EmojiInteractions::preparePlayer(
not_null<Data::DocumentMedia*> media) { not_null<DocumentData*> document,
QByteArray data,
QString filepath,
bool premium) {
// Shortened copy from stickers_lottie module. // Shortened copy from stickers_lottie module.
const auto document = media->owner();
const auto baseKey = document->bigFileBaseCacheKey(); const auto baseKey = document->bigFileBaseCacheKey();
const auto tag = uint8(0); const auto tag = uint8(0);
const auto keyShift = ((tag << 4) & 0xF0) const auto keyShift = ((tag << 4) & 0xF0)
@ -149,10 +199,8 @@ std::unique_ptr<Lottie::SinglePlayer> EmojiInteractions::preparePlayer(
std::move(data)); std::move(data));
}); });
}; };
const auto data = media->bytes();
const auto filepath = document->filepath();
const auto request = Lottie::FrameRequest{ const auto request = Lottie::FrameRequest{
_emojiSize * kSizeMultiplier * style::DevicePixelRatio(), sizeFor(premium) * style::DevicePixelRatio(),
}; };
auto &weakProvider = _sharedProviders[document]; auto &weakProvider = _sharedProviders[document];
auto shared = [&] { auto shared = [&] {
@ -160,7 +208,7 @@ std::unique_ptr<Lottie::SinglePlayer> EmojiInteractions::preparePlayer(
return result; return result;
} }
const auto result = Lottie::SinglePlayer::SharedProvider( const auto result = Lottie::SinglePlayer::SharedProvider(
kCachesCount, premium ? kPremiumCachesCount : kEmojiCachesCount,
get, get,
put, put,
Lottie::ReadContent(data, filepath), Lottie::ReadContent(data, filepath),
@ -179,19 +227,23 @@ void EmojiInteractions::visibleAreaUpdated(
_visibleBottom = visibleBottom; _visibleBottom = visibleBottom;
} }
QRect EmojiInteractions::computeRect(not_null<Element*> view) const { QRect EmojiInteractions::computeRect(
not_null<const Element*> view,
bool premium) const {
const auto fullWidth = view->width(); const auto fullWidth = view->width();
const auto shift = (_emojiSize.width() * kSizeMultiplier) / 40; const auto sticker = premium ? _premiumSize : _emojiSize;
const auto size = sizeFor(premium);
const auto shift = size.width() / 40;
const auto skip = (view->hasFromPhoto() ? st::msgPhotoSkip : 0) const auto skip = (view->hasFromPhoto() ? st::msgPhotoSkip : 0)
+ st::msgMargin.left(); + st::msgMargin.left();
const auto rightAligned = view->hasOutLayout() const auto rightAligned = view->hasOutLayout()
&& !view->delegate()->elementIsChatWide(); && !view->delegate()->elementIsChatWide();
const auto left = rightAligned const auto left = rightAligned
? (fullWidth - skip + shift - _emojiSize.width() * kSizeMultiplier) ? (fullWidth - skip + shift - size.width())
: (skip - shift); : (skip - shift);
const auto viewTop = view->block()->y() + view->y() + view->marginTop(); const auto viewTop = view->block()->y() + view->y() + view->marginTop();
const auto top = viewTop - _emojiSize.height(); const auto top = viewTop + (sticker.height() - size.height()) / 2;
return QRect(QPoint(left, top), _emojiSize * kSizeMultiplier); return QRect(QPoint(left, top), size);
} }
void EmojiInteractions::paint(QPainter &p) { void EmojiInteractions::paint(QPainter &p) {
@ -201,7 +253,7 @@ void EmojiInteractions::paint(QPainter &p) {
continue; continue;
} }
auto request = Lottie::FrameRequest(); auto request = Lottie::FrameRequest();
request.box = _emojiSize * kSizeMultiplier * factor; request.box = sizeFor(play.premium) * factor;
const auto rightAligned = play.view->hasOutLayout() const auto rightAligned = play.view->hasOutLayout()
&& !play.view->delegate()->elementIsChatWide(); && !play.view->delegate()->elementIsChatWide();
if (!rightAligned) { if (!rightAligned) {
@ -217,7 +269,7 @@ void EmojiInteractions::paint(QPainter &p) {
if (play.frame + 1 == play.framesCount) { if (play.frame + 1 == play.framesCount) {
play.finished = true; play.finished = true;
} }
const auto rect = computeRect(play.view); const auto rect = computeRect(play.view, play.premium);
p.drawImage( p.drawImage(
QRect(rect.topLeft() + play.shift, frame.image.size() / factor), QRect(rect.topLeft() + play.shift, frame.image.size() / factor),
frame.image); frame.image);

View file

@ -36,6 +36,7 @@ public:
void play( void play(
ChatHelpers::EmojiInteractionPlayRequest request, ChatHelpers::EmojiInteractionPlayRequest request,
not_null<Element*> view); not_null<Element*> view);
void playPremiumEffect(not_null<const Element*> view);
void visibleAreaUpdated(int visibleTop, int visibleBottom); void visibleAreaUpdated(int visibleTop, int visibleBottom);
void paint(QPainter &p); void paint(QPainter &p);
@ -44,39 +45,55 @@ public:
private: private:
struct Play { struct Play {
not_null<Element*> view; not_null<const Element*> view;
std::unique_ptr<Lottie::SinglePlayer> lottie; std::unique_ptr<Lottie::SinglePlayer> lottie;
QPoint shift; QPoint shift;
int frame = 0; int frame = 0;
int framesCount = 0; int framesCount = 0;
int frameRate = 0; int frameRate = 0;
bool premium = false;
bool finished = false; bool finished = false;
}; };
struct Delayed { struct Delayed {
QString emoticon; QString emoticon;
not_null<Element*> view; not_null<const Element*> view;
std::shared_ptr<Data::DocumentMedia> media; std::shared_ptr<Data::DocumentMedia> media;
crl::time shouldHaveStartedAt = 0; crl::time shouldHaveStartedAt = 0;
bool incoming = false; bool incoming = false;
}; };
[[nodiscard]] QRect computeRect(not_null<Element*> view) const; [[nodiscard]] QRect computeRect(
not_null<const Element*> view,
bool premium) const;
void play( void play(
QString emoticon, QString emoticon,
not_null<Element*> view, not_null<const Element*> view,
std::shared_ptr<Data::DocumentMedia> media, std::shared_ptr<Data::DocumentMedia> media,
bool incoming); bool incoming);
void play(
QString emoticon,
not_null<const Element*> view,
not_null<DocumentData*> document,
QByteArray data,
QString filepath,
bool incoming,
bool premium);
void checkDelayed(); void checkDelayed();
[[nodiscard]] QSize sizeFor(bool premium) const;
[[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> preparePlayer( [[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> preparePlayer(
not_null<Data::DocumentMedia*> media); not_null<DocumentData*> document,
QByteArray data,
QString filepath,
bool premium);
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;
int _visibleTop = 0; int _visibleTop = 0;
int _visibleBottom = 0; int _visibleBottom = 0;
QSize _emojiSize; QSize _emojiSize;
QSize _premiumSize;
std::vector<Play> _plays; std::vector<Play> _plays;
std::vector<Delayed> _delayed; std::vector<Delayed> _delayed;

View file

@ -1519,6 +1519,9 @@ void ListWidget::elementReplyTo(const FullMsgId &to) {
void ListWidget::elementStartInteraction(not_null<const Element*> view) { void ListWidget::elementStartInteraction(not_null<const Element*> view) {
} }
void ListWidget::elementStartPremium(not_null<const Element*> view) {
}
void ListWidget::elementShowSpoilerAnimation() { void ListWidget::elementShowSpoilerAnimation() {
_spoilerOpacity.stop(); _spoilerOpacity.stop();
_spoilerOpacity.start([=] { update(); }, 0., 1., st::fadeWrapDuration); _spoilerOpacity.start([=] { update(); }, 0., 1., st::fadeWrapDuration);

View file

@ -292,6 +292,7 @@ public:
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override; not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
void elementReplyTo(const FullMsgId &to) override; void elementReplyTo(const FullMsgId &to) override;
void elementStartInteraction(not_null<const Element*> view) override; void elementStartInteraction(not_null<const Element*> view) override;
void elementStartPremium(not_null<const Element*> view) override;
void elementShowSpoilerAnimation() override; void elementShowSpoilerAnimation() override;
void setEmptyInfoWidget(base::unique_qptr<Ui::RpWidget> &&w); void setEmptyInfoWidget(base::unique_qptr<Ui::RpWidget> &&w);

View file

@ -68,6 +68,9 @@ Sticker::Sticker(
dataMediaCreated(); dataMediaCreated();
} else { } else {
_data->loadThumbnail(parent->data()->fullId()); _data->loadThumbnail(parent->data()->fullId());
if (_data->isPremiumSticker()) {
_data->loadVideoThumbnail(parent->data()->fullId());
}
} }
if (const auto media = replacing ? replacing->media() : nullptr) { if (const auto media = replacing ? replacing->media() : nullptr) {
_lottie = media->stickerTakeLottie(_data, _replacements); _lottie = media->stickerTakeLottie(_data, _replacements);
@ -123,7 +126,9 @@ bool Sticker::readyToDrawLottie() {
ensureDataMediaCreated(); ensureDataMediaCreated();
_dataMedia->checkStickerLarge(); _dataMedia->checkStickerLarge();
const auto loaded = _dataMedia->loaded(); const auto loaded = _dataMedia->loaded();
if (sticker->isLottie() && !_lottie && loaded) { const auto waitingForPremium = _data->isPremiumSticker()
&& _dataMedia->videoThumbnailContent().isEmpty();
if (sticker->isLottie() && !_lottie && loaded && !waitingForPremium) {
setupLottie(); setupLottie();
} }
return (_lottie && _lottie->ready()); return (_lottie && _lottie->ready());
@ -153,6 +158,19 @@ void Sticker::draw(
} }
} }
ClickHandlerPtr Sticker::link() {
return _link;
}
DocumentData *Sticker::document() {
return _data;
}
void Sticker::stickerClearLoopPlayed() {
_lottieOncePlayed = false;
_premiumEffectPlayed = false;
}
void Sticker::paintLottie( void Sticker::paintLottie(
Painter &p, Painter &p,
const PaintContext &context, const PaintContext &context,
@ -162,6 +180,14 @@ void Sticker::paintLottie(
if (context.selected() && !_nextLastDiceFrame) { if (context.selected() && !_nextLastDiceFrame) {
request.colored = context.st->msgStickerOverlay()->c; request.colored = context.st->msgStickerOverlay()->c;
} }
const auto premium = _data->isPremiumSticker();
if (premium) {
const auto rightAligned = _parent->hasOutLayout()
&& !_parent->delegate()->elementIsChatWide();
if (!rightAligned) {
request.mirrorHorizontal = true;
}
}
const auto frame = _lottie const auto frame = _lottie
? _lottie->frameInfo(request) ? _lottie->frameInfo(request)
: Lottie::Animation::FrameInfo(); : Lottie::Animation::FrameInfo();
@ -201,10 +227,10 @@ void Sticker::paintLottie(
_framesCount = count; _framesCount = count;
_nextLastDiceFrame = !paused _nextLastDiceFrame = !paused
&& (_diceIndex > 0) && (_diceIndex > 0)
&& (frame.index + 2 == count); && (_frameIndex + 2 == count);
const auto lastDiceFrame = (_diceIndex > 0) && atTheEnd(); const auto lastDiceFrame = (_diceIndex > 0) && atTheEnd();
const auto switchToNext = !playOnce const auto switchToNext = !playOnce
|| (!lastDiceFrame && (frame.index != 0 || !_lottieOncePlayed)); || (!lastDiceFrame && (_frameIndex != 0 || !_lottieOncePlayed));
if (!paused if (!paused
&& switchToNext && switchToNext
&& _lottie->markFrameShown() && _lottie->markFrameShown()
@ -338,6 +364,9 @@ void Sticker::dataMediaCreated() const {
if (_dataMedia->thumbnailPath().isEmpty()) { if (_dataMedia->thumbnailPath().isEmpty()) {
_dataMedia->thumbnailWanted(_parent->data()->fullId()); _dataMedia->thumbnailWanted(_parent->data()->fullId());
} }
if (_data->isPremiumSticker()) {
_data->loadVideoThumbnail(_parent->data()->fullId());
}
_parent->history()->owner().registerHeavyViewPart(_parent); _parent->history()->owner().registerHeavyViewPart(_parent);
} }
@ -355,6 +384,11 @@ void Sticker::setupLottie() {
ChatHelpers::StickerLottieSize::MessageHistory, ChatHelpers::StickerLottieSize::MessageHistory,
size() * cIntRetinaFactor(), size() * cIntRetinaFactor(),
Lottie::Quality::High); Lottie::Quality::High);
if (_data->isPremiumSticker()
&& !_premiumEffectPlayed) {
_premiumEffectPlayed = true;
_parent->delegate()->elementStartPremium(_parent);
}
lottieCreated(); lottieCreated();
} }

View file

@ -43,16 +43,10 @@ public:
Painter &p, Painter &p,
const PaintContext &context, const PaintContext &context,
const QRect &r) override; const QRect &r) override;
ClickHandlerPtr link() override { ClickHandlerPtr link() override;
return _link;
}
DocumentData *document() override { DocumentData *document() override;
return _data; void stickerClearLoopPlayed() override;
}
void stickerClearLoopPlayed() override {
_lottieOncePlayed = false;
}
std::unique_ptr<Lottie::SinglePlayer> stickerTakeLottie( std::unique_ptr<Lottie::SinglePlayer> stickerTakeLottie(
not_null<DocumentData*> data, not_null<DocumentData*> data,
const Lottie::ColorReplacements *replacements) override; const Lottie::ColorReplacements *replacements) override;
@ -111,6 +105,7 @@ private:
mutable int _frameIndex = -1; mutable int _frameIndex = -1;
mutable int _framesCount = -1; mutable int _framesCount = -1;
mutable bool _lottieOncePlayed = false; mutable bool _lottieOncePlayed = false;
mutable bool _premiumEffectPlayed = false;
mutable bool _nextLastDiceFrame = false; mutable bool _nextLastDiceFrame = false;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;

View file

@ -45,7 +45,9 @@ void Document::writeToStream(QDataStream &stream, DocumentData *document) {
} }
} }
stream << qint32(document->getDuration()); stream << qint32(document->getDuration());
stream << qint32(document->isPremiumSticker() ? 1 : 0); if (document->type == StickerDocument) {
stream << qint32(document->isPremiumSticker() ? 1 : 0);
}
writeImageLocation(stream, document->thumbnailLocation()); writeImageLocation(stream, document->thumbnailLocation());
stream << qint32(document->thumbnailByteSize()); stream << qint32(document->thumbnailByteSize());
writeImageLocation(stream, document->videoThumbnailLocation()); writeImageLocation(stream, document->videoThumbnailLocation());