Use Lottie::MultiPlayer in StickersListWidget.

This commit is contained in:
John Preston 2019-06-28 16:26:03 +02:00
parent 09c9f4ef9a
commit ad1816cb7c
4 changed files with 96 additions and 22 deletions

View File

@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
#include "ui/emoji_config.h" #include "ui/emoji_config.h"
#include "lottie/lottie_single_player.h" #include "lottie/lottie_single_player.h"
#include "lottie/lottie_multi_player.h"
#include "styles/style_chat_helpers.h" #include "styles/style_chat_helpers.h"
namespace Stickers { namespace Stickers {
@ -1092,7 +1093,9 @@ RecentStickerPack &GetRecentPack() {
return cRefRecentStickers(); return cRefRecentStickers();
} }
std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument( template <typename Method>
auto LottieFromDocument(
Method &&method,
not_null<DocumentData*> document, not_null<DocumentData*> document,
LottieSize sizeTag, LottieSize sizeTag,
QSize box) { QSize box) {
@ -1100,7 +1103,7 @@ std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
const auto filepath = document->filepath(); const auto filepath = document->filepath();
if (box.width() & box.height() > kDontCacheLottieAfterArea) { if (box.width() & box.height() > kDontCacheLottieAfterArea) {
// Don't use frame caching for large stickers. // Don't use frame caching for large stickers.
return std::make_unique<Lottie::SinglePlayer>( return method(
Lottie::ReadContent(data, filepath), Lottie::ReadContent(data, filepath),
Lottie::FrameRequest{ box }); Lottie::FrameRequest{ box });
} }
@ -1120,15 +1123,37 @@ std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
weak->data().cacheBigFile().put(key, std::move(data)); weak->data().cacheBigFile().put(key, std::move(data));
}); });
}; };
return std::make_unique<Lottie::SinglePlayer>( return method(
get, get,
put, put,
Lottie::ReadContent(data, filepath), Lottie::ReadContent(data, filepath),
Lottie::FrameRequest{ box }); Lottie::FrameRequest{ box });
} }
return std::make_unique<Lottie::SinglePlayer>( return method(
Lottie::ReadContent(data, filepath), Lottie::ReadContent(data, filepath),
Lottie::FrameRequest{ box }); Lottie::FrameRequest{ box });
} }
std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
not_null<DocumentData*> document,
LottieSize sizeTag,
QSize box) {
const auto method = [](auto &&...args) {
return std::make_unique<Lottie::SinglePlayer>(
std::forward<decltype(args)>(args)...);
};
return LottieFromDocument(method, document, sizeTag, box);
}
not_null<Lottie::Animation*> LottieAnimationFromDocument(
not_null<Lottie::MultiPlayer*> player,
not_null<DocumentData*> document,
LottieSize sizeTag,
QSize box) {
const auto method = [&](auto &&...args) {
return player->append(std::forward<decltype(args)>(args)...);
};
return LottieFromDocument(method, document, sizeTag, box);
}
} // namespace Stickers } // namespace Stickers

View File

@ -13,6 +13,8 @@ class DocumentData;
namespace Lottie { namespace Lottie {
class SinglePlayer; class SinglePlayer;
class MultiPlayer;
class Animation;
} // namespace Lottie } // namespace Lottie
namespace Stickers { namespace Stickers {
@ -119,5 +121,10 @@ std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
not_null<DocumentData*> document, not_null<DocumentData*> document,
LottieSize sizeTag, LottieSize sizeTag,
QSize box); QSize box);
not_null<Lottie::Animation*> LottieAnimationFromDocument(
not_null<Lottie::MultiPlayer*> player,
not_null<DocumentData*> document,
LottieSize sizeTag,
QSize box);
} // namespace Stickers } // namespace Stickers

View File

@ -14,7 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "ui/image/image.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 "boxes/stickers_box.h"
#include "inline_bots/inline_bot_result.h" #include "inline_bots/inline_bot_result.h"
#include "chat_helpers/stickers.h" #include "chat_helpers/stickers.h"
@ -839,6 +840,7 @@ bool StickersListWidget::enumerateSections(Callback callback) const {
StickersListWidget::SectionInfo StickersListWidget::sectionInfo(int section) const { StickersListWidget::SectionInfo StickersListWidget::sectionInfo(int section) const {
Expects(section >= 0 && section < shownSets().size()); Expects(section >= 0 && section < shownSets().size());
auto result = SectionInfo(); auto result = SectionInfo();
enumerateSections([searchForSection = section, &result](const SectionInfo &info) { enumerateSections([searchForSection = section, &result](const SectionInfo &info) {
if (info.section == searchForSection) { if (info.section == searchForSection) {
@ -1200,6 +1202,13 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
return false; return false;
} }
auto &set = sets[info.section]; 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) { if (set.externalLayout) {
const auto size = (set.flags const auto size = (set.flags
& MTPDstickerSet_ClientFlag::f_not_loaded) & 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); 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<Lottie::MultiPlayer>(
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) { void StickersListWidget::setupLottie(Set &set, int section, int index) {
auto &sticker = set.stickers[index]; auto &sticker = set.stickers[index];
const auto document = sticker.document; const auto document = sticker.document;
sticker.animated = Stickers::LottiePlayerFromDocument( ensureLottiePlayer(set);
sticker.animated = Stickers::LottieAnimationFromDocument(
set.lottiePlayer.get(),
document, document,
Stickers::LottieSize::StickersPanel, Stickers::LottieSize::StickersPanel,
boundingBoxSize() * cIntRetinaFactor()); 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 { 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()) { if (sticker.animated && sticker.animated->ready()) {
auto request = Lottie::FrameRequest(); auto request = Lottie::FrameRequest();
request.box = boundingBoxSize() * cIntRetinaFactor(); request.box = boundingBoxSize() * cIntRetinaFactor();
const auto paused = controller()->isGifPausedAtLeastFor(
Window::GifPauseReason::SavedGifs);
if (!paused) {
sticker.animated->markFrameShown();
}
const auto frame = sticker.animated->frame(request); const auto frame = sticker.animated->frame(request);
p.drawImage( p.drawImage(
QRect(ppos, frame.size() / cIntRetinaFactor()), QRect(ppos, frame.size() / cIntRetinaFactor()),
@ -1787,7 +1811,7 @@ void StickersListWidget::refreshStickers() {
refreshFavedStickers(); refreshFavedStickers();
refreshRecentStickers(false); refreshRecentStickers(false);
refreshMegagroupStickers(GroupStickersPlace::Visible); refreshMegagroupStickers(GroupStickersPlace::Visible);
for_const (auto setId, Auth().data().stickerSetsOrder()) { for (const auto setId : Auth().data().stickerSetsOrder()) {
const auto externalLayout = false; const auto externalLayout = false;
appendSet(_mySets, setId, externalLayout, AppendSkip::Archived); appendSet(_mySets, setId, externalLayout, AppendSkip::Archived);
} }
@ -1796,7 +1820,7 @@ void StickersListWidget::refreshStickers() {
_featuredSets.clear(); _featuredSets.clear();
_featuredSets.reserve(Auth().data().featuredStickerSetsOrder().size()); _featuredSets.reserve(Auth().data().featuredStickerSetsOrder().size());
for_const (auto setId, Auth().data().featuredStickerSetsOrder()) { for (const auto setId : Auth().data().featuredStickerSetsOrder()) {
const auto externalLayout = true; const auto externalLayout = true;
appendSet(_featuredSets, setId, externalLayout, AppendSkip::Installed); appendSet(_featuredSets, setId, externalLayout, AppendSkip::Installed);
} }
@ -2311,6 +2335,16 @@ void StickersListWidget::showPreview() {
} }
} }
auto StickersListWidget::getLottieRenderer()
-> std::shared_ptr<Lottie::FrameRenderer> {
if (auto result = _lottieRenderer.lock()) {
return result;
}
auto result = Lottie::MakeFrameRenderer();
_lottieRenderer = result;
return result;
}
void StickersListWidget::showStickerSet(uint64 setId) { void StickersListWidget::showStickerSet(uint64 setId) {
clearSelection(); clearSelection();

View File

@ -22,7 +22,9 @@ class RippleAnimation;
} // namespace Ui } // namespace Ui
namespace Lottie { namespace Lottie {
class SinglePlayer; class Animation;
class MultiPlayer;
class FrameRenderer;
} // namespace Lottie } // namespace Lottie
namespace ChatHelpers { namespace ChatHelpers {
@ -141,7 +143,7 @@ private:
struct Sticker { struct Sticker {
not_null<DocumentData*> document; not_null<DocumentData*> document;
std::unique_ptr<Lottie::SinglePlayer> animated; Lottie::Animation *animated = nullptr;
}; };
struct Set { struct Set {
@ -165,6 +167,7 @@ private:
ImagePtr thumbnail; ImagePtr thumbnail;
std::vector<Sticker> stickers; std::vector<Sticker> stickers;
std::unique_ptr<Ui::RippleAnimation> ripple; std::unique_ptr<Ui::RippleAnimation> ripple;
std::unique_ptr<Lottie::MultiPlayer> lottiePlayer;
bool externalLayout = false; bool externalLayout = false;
int count = 0; int count = 0;
}; };
@ -223,6 +226,8 @@ private:
void paintMegagroupEmptySet(Painter &p, int y, bool buttonSelected); 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 paintSticker(Painter &p, Set &set, int y, int section, int index, bool selected, bool deleteSelected);
void paintEmptySearchResults(Painter &p); void paintEmptySearchResults(Painter &p);
void ensureLottiePlayer(Set &set);
void setupLottie(Set &set, int section, int index); void setupLottie(Set &set, int section, int index);
int stickersRight() const; int stickersRight() const;
@ -265,6 +270,8 @@ private:
void showPreview(); void showPreview();
std::shared_ptr<Lottie::FrameRenderer> getLottieRenderer();
ChannelData *_megagroupSet = nullptr; ChannelData *_megagroupSet = nullptr;
uint64 _megagroupSetIdRequested = 0; uint64 _megagroupSetIdRequested = 0;
std::vector<Set> _mySets; std::vector<Set> _mySets;
@ -273,6 +280,7 @@ private:
base::flat_set<uint64> _installedLocallySets; base::flat_set<uint64> _installedLocallySets;
std::vector<bool> _custom; std::vector<bool> _custom;
base::flat_set<not_null<DocumentData*>> _favedStickersMap; base::flat_set<not_null<DocumentData*>> _favedStickersMap;
std::weak_ptr<Lottie::FrameRenderer> _lottieRenderer;
Section _section = Section::Stickers; Section _section = Section::Stickers;