From ad1816cb7c0fd933185883b5875df67fbf4cca93 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 28 Jun 2019 16:26:03 +0200 Subject: [PATCH] Use Lottie::MultiPlayer in StickersListWidget. --- .../SourceFiles/chat_helpers/stickers.cpp | 33 ++++++++-- Telegram/SourceFiles/chat_helpers/stickers.h | 7 ++ .../chat_helpers/stickers_list_widget.cpp | 66 ++++++++++++++----- .../chat_helpers/stickers_list_widget.h | 12 +++- 4 files changed, 96 insertions(+), 22 deletions(-) diff --git a/Telegram/SourceFiles/chat_helpers/stickers.cpp b/Telegram/SourceFiles/chat_helpers/stickers.cpp index 45bda3293..e8dc619a1 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers.cpp @@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/toast/toast.h" #include "ui/emoji_config.h" #include "lottie/lottie_single_player.h" +#include "lottie/lottie_multi_player.h" #include "styles/style_chat_helpers.h" namespace Stickers { @@ -1092,7 +1093,9 @@ RecentStickerPack &GetRecentPack() { return cRefRecentStickers(); } -std::unique_ptr LottiePlayerFromDocument( +template +auto LottieFromDocument( + Method &&method, not_null document, LottieSize sizeTag, QSize box) { @@ -1100,7 +1103,7 @@ std::unique_ptr LottiePlayerFromDocument( const auto filepath = document->filepath(); if (box.width() & box.height() > kDontCacheLottieAfterArea) { // Don't use frame caching for large stickers. - return std::make_unique( + return method( Lottie::ReadContent(data, filepath), Lottie::FrameRequest{ box }); } @@ -1120,15 +1123,37 @@ std::unique_ptr LottiePlayerFromDocument( weak->data().cacheBigFile().put(key, std::move(data)); }); }; - return std::make_unique( + return method( get, put, Lottie::ReadContent(data, filepath), Lottie::FrameRequest{ box }); } - return std::make_unique( + return method( Lottie::ReadContent(data, filepath), Lottie::FrameRequest{ box }); } +std::unique_ptr LottiePlayerFromDocument( + not_null document, + LottieSize sizeTag, + QSize box) { + const auto method = [](auto &&...args) { + return std::make_unique( + std::forward(args)...); + }; + return LottieFromDocument(method, document, sizeTag, box); +} + +not_null LottieAnimationFromDocument( + not_null player, + not_null document, + LottieSize sizeTag, + QSize box) { + const auto method = [&](auto &&...args) { + return player->append(std::forward(args)...); + }; + return LottieFromDocument(method, document, sizeTag, box); +} + } // namespace Stickers diff --git a/Telegram/SourceFiles/chat_helpers/stickers.h b/Telegram/SourceFiles/chat_helpers/stickers.h index 939f9f157..8f412b58f 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers.h +++ b/Telegram/SourceFiles/chat_helpers/stickers.h @@ -13,6 +13,8 @@ class DocumentData; namespace Lottie { class SinglePlayer; +class MultiPlayer; +class Animation; } // namespace Lottie namespace Stickers { @@ -119,5 +121,10 @@ std::unique_ptr LottiePlayerFromDocument( not_null document, LottieSize sizeTag, QSize box); +not_null LottieAnimationFromDocument( + not_null player, + not_null document, + LottieSize sizeTag, + QSize box); } // namespace Stickers diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index beaa39bf2..2a0a094dd 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -14,7 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/animations.h" #include "ui/effects/ripple_animation.h" #include "ui/image/image.h" -#include "lottie/lottie_single_player.h" +#include "lottie/lottie_multi_player.h" +#include "lottie/lottie_animation.h" #include "boxes/stickers_box.h" #include "inline_bots/inline_bot_result.h" #include "chat_helpers/stickers.h" @@ -839,6 +840,7 @@ bool StickersListWidget::enumerateSections(Callback callback) const { StickersListWidget::SectionInfo StickersListWidget::sectionInfo(int section) const { Expects(section >= 0 && section < shownSets().size()); + auto result = SectionInfo(); enumerateSections([searchForSection = section, &result](const SectionInfo &info) { if (info.section == searchForSection) { @@ -1200,6 +1202,13 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) { return false; } auto &set = sets[info.section]; + if (const auto player = set.lottiePlayer.get()) { + const auto paused = controller()->isGifPausedAtLeastFor( + Window::GifPauseReason::SavedGifs); + if (!paused) { + player->markFrameShown(); + } + } if (set.externalLayout) { const auto size = (set.flags & MTPDstickerSet_ClientFlag::f_not_loaded) @@ -1364,21 +1373,41 @@ void StickersListWidget::paintMegagroupEmptySet(Painter &p, int y, bool buttonSe p.drawTextLeft(button.x() - (st::stickerGroupCategoryAdd.width / 2), button.y() + st::stickerGroupCategoryAdd.textTop, width(), _megagroupSetButtonText, _megagroupSetButtonTextWidth); } +void StickersListWidget::ensureLottiePlayer(Set &set) { + if (set.lottiePlayer) { + return; + } + set.lottiePlayer = std::make_unique( + getLottieRenderer()); + const auto raw = set.lottiePlayer.get(); + set.lottiePlayer->updates( + ) | rpl::start_with_next([=] { + const auto &sets = shownSets(); + + enumerateSections([&](const SectionInfo &info) { + if (shownSets()[info.section].lottiePlayer.get() == raw) { + update( + 0, + info.rowsTop, + width(), + info.rowsBottom - info.rowsTop); + return false; + } + return true; + }); + }, lifetime()); +} + void StickersListWidget::setupLottie(Set &set, int section, int index) { auto &sticker = set.stickers[index]; const auto document = sticker.document; - sticker.animated = Stickers::LottiePlayerFromDocument( + ensureLottiePlayer(set); + sticker.animated = Stickers::LottieAnimationFromDocument( + set.lottiePlayer.get(), document, Stickers::LottieSize::StickersPanel, boundingBoxSize() * cIntRetinaFactor()); - const auto animation = sticker.animated.get(); - - animation->updates( - ) | rpl::start_with_next_error([=](Lottie::Update update) { - rtlupdate(stickerRect(section, index)); - }, [=](Lottie::Error error) { - }, lifetime()); } QSize StickersListWidget::boundingBoxSize() const { @@ -1419,11 +1448,6 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int section, if (sticker.animated && sticker.animated->ready()) { auto request = Lottie::FrameRequest(); request.box = boundingBoxSize() * cIntRetinaFactor(); - const auto paused = controller()->isGifPausedAtLeastFor( - Window::GifPauseReason::SavedGifs); - if (!paused) { - sticker.animated->markFrameShown(); - } const auto frame = sticker.animated->frame(request); p.drawImage( QRect(ppos, frame.size() / cIntRetinaFactor()), @@ -1787,7 +1811,7 @@ void StickersListWidget::refreshStickers() { refreshFavedStickers(); refreshRecentStickers(false); refreshMegagroupStickers(GroupStickersPlace::Visible); - for_const (auto setId, Auth().data().stickerSetsOrder()) { + for (const auto setId : Auth().data().stickerSetsOrder()) { const auto externalLayout = false; appendSet(_mySets, setId, externalLayout, AppendSkip::Archived); } @@ -1796,7 +1820,7 @@ void StickersListWidget::refreshStickers() { _featuredSets.clear(); _featuredSets.reserve(Auth().data().featuredStickerSetsOrder().size()); - for_const (auto setId, Auth().data().featuredStickerSetsOrder()) { + for (const auto setId : Auth().data().featuredStickerSetsOrder()) { const auto externalLayout = true; appendSet(_featuredSets, setId, externalLayout, AppendSkip::Installed); } @@ -2311,6 +2335,16 @@ void StickersListWidget::showPreview() { } } +auto StickersListWidget::getLottieRenderer() +-> std::shared_ptr { + if (auto result = _lottieRenderer.lock()) { + return result; + } + auto result = Lottie::MakeFrameRenderer(); + _lottieRenderer = result; + return result; +} + void StickersListWidget::showStickerSet(uint64 setId) { clearSelection(); diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h index 9f7495aa4..08eecaa78 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h @@ -22,7 +22,9 @@ class RippleAnimation; } // namespace Ui namespace Lottie { -class SinglePlayer; +class Animation; +class MultiPlayer; +class FrameRenderer; } // namespace Lottie namespace ChatHelpers { @@ -141,7 +143,7 @@ private: struct Sticker { not_null document; - std::unique_ptr animated; + Lottie::Animation *animated = nullptr; }; struct Set { @@ -165,6 +167,7 @@ private: ImagePtr thumbnail; std::vector stickers; std::unique_ptr ripple; + std::unique_ptr lottiePlayer; bool externalLayout = false; int count = 0; }; @@ -223,6 +226,8 @@ private: void paintMegagroupEmptySet(Painter &p, int y, bool buttonSelected); void paintSticker(Painter &p, Set &set, int y, int section, int index, bool selected, bool deleteSelected); void paintEmptySearchResults(Painter &p); + + void ensureLottiePlayer(Set &set); void setupLottie(Set &set, int section, int index); int stickersRight() const; @@ -265,6 +270,8 @@ private: void showPreview(); + std::shared_ptr getLottieRenderer(); + ChannelData *_megagroupSet = nullptr; uint64 _megagroupSetIdRequested = 0; std::vector _mySets; @@ -273,6 +280,7 @@ private: base::flat_set _installedLocallySets; std::vector _custom; base::flat_set> _favedStickersMap; + std::weak_ptr _lottieRenderer; Section _section = Section::Stickers;