diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index ef6863c78..bf669ac52 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_document.h" #include "data/data_document_media.h" #include "data/data_changes.h" +#include "lottie/lottie_icon.h" #include "base/timer_rpl.h" #include "apiwrap.h" #include "styles/style_chat.h" @@ -25,6 +26,7 @@ namespace { constexpr auto kRefreshFullListEach = 60 * 60 * crl::time(1000); constexpr auto kPollEach = 20 * crl::time(1000); +constexpr auto kSizeForDownscale = 128; } // namespace @@ -49,6 +51,8 @@ Reactions::Reactions(not_null owner) }, _lifetime); } +Reactions::~Reactions() = default; + void Reactions::refresh() { request(); } @@ -82,7 +86,7 @@ void Reactions::preloadImageFor(const QString &emoji) { auto &set = _images.emplace(emoji).first->second; const auto i = ranges::find(_available, emoji, &Reaction::emoji); const auto document = (i != end(_available)) - ? i->staticIcon.get() + ? i->centerIcon.get() : nullptr; if (document) { loadImage(set, document); @@ -100,6 +104,20 @@ QImage Reactions::resolveImageFor( preloadImageFor(emoji); } auto &set = (i != end(_images)) ? i->second : _images[emoji]; + const auto resolve = [&](QImage &image, int size) { + const auto factor = style::DevicePixelRatio(); + image = set.icon->frame().scaled( + size * factor, + size * factor, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); + image.setDevicePixelRatio(factor); + }; + if (set.bottomInfo.isNull() && set.icon) { + resolve(set.bottomInfo, st::reactionInfoSize); + resolve(set.inlineList, st::reactionBottomSize); + crl::async([icon = std::move(set.icon)]{}); + } switch (size) { case ImageSize::BottomInfo: return set.bottomInfo; case ImageSize::InlineList: return set.inlineList; @@ -109,12 +127,12 @@ QImage Reactions::resolveImageFor( void Reactions::resolveImages() { for (auto &[emoji, set] : _images) { - if (!set.bottomInfo.isNull() || set.media) { + if (!set.bottomInfo.isNull() || set.icon || set.media) { continue; } const auto i = ranges::find(_available, emoji, &Reaction::emoji); const auto document = (i != end(_available)) - ? i->staticIcon.get() + ? i->centerIcon.get() : nullptr; if (document) { loadImage(set, document); @@ -128,13 +146,14 @@ void Reactions::resolveImages() { void Reactions::loadImage( ImageSet &set, not_null document) { - if (!set.bottomInfo.isNull()) { + if (!set.bottomInfo.isNull() || set.icon) { return; } else if (!set.media) { set.media = document->createMediaView(); + set.media->checkStickerLarge(); } - if (const auto image = set.media->getStickerLarge()) { - setImage(set, image->original()); + if (set.media->loaded()) { + setLottie(set); } else if (!_imagesLoadLifetime) { document->session().downloaderTaskFinished( ) | rpl::start_with_next([=] { @@ -143,20 +162,15 @@ void Reactions::loadImage( } } -void Reactions::setImage(ImageSet &set, QImage large) { +void Reactions::setLottie(ImageSet &set) { + const auto size = kSizeForDownscale / style::DevicePixelRatio(); + set.icon = std::make_unique(Lottie::IconDescriptor{ + .path = set.media->owner()->filepath(true), + .json = set.media->bytes(), + .sizeOverride = QSize(size, size), + .frame = -1, + }); set.media = nullptr; - const auto scale = [&](int size) { - const auto factor = style::DevicePixelRatio(); - return Images::prepare( - large, - size * factor, - size * factor, - Images::Option::Smooth, - size, - size); - }; - set.bottomInfo = scale(st::reactionInfoSize); - set.inlineList = scale(st::reactionBottomSize); } void Reactions::downloadTaskFinished() { @@ -164,8 +178,8 @@ void Reactions::downloadTaskFinished() { for (auto &[emoji, set] : _images) { if (!set.media) { continue; - } else if (const auto image = set.media->getStickerLarge()) { - setImage(set, image->original()); + } else if (set.media->loaded()) { + setLottie(set); } else { hasOne = true; } @@ -249,6 +263,8 @@ std::optional Reactions::parse(const MTPAvailableReaction &entry) { if (!known) { LOG(("API Error: Unknown emoji in reactions: %1").arg(emoji)); } + const auto selectAnimation = _owner->processDocument( + data.vselect_animation()); return known ? std::make_optional(Reaction{ .emoji = emoji, @@ -256,19 +272,18 @@ std::optional Reactions::parse(const MTPAvailableReaction &entry) { .staticIcon = _owner->processDocument(data.vstatic_icon()), .appearAnimation = _owner->processDocument( data.vappear_animation()), - .selectAnimation = _owner->processDocument( - data.vselect_animation()), + .selectAnimation = selectAnimation, .activateAnimation = _owner->processDocument( data.vactivate_animation()), .activateEffects = _owner->processDocument( data.veffect_animation()), + .centerIcon = (data.vcenter_icon() + ? _owner->processDocument(*data.vcenter_icon()) + : selectAnimation), .aroundAnimation = (data.varound_animation() ? _owner->processDocument( *data.varound_animation()).get() : nullptr), - .centerIcon = (data.vcenter_icon() - ? _owner->processDocument(*data.vcenter_icon()).get() - : nullptr), .active = !data.is_inactive(), }) : std::nullopt; diff --git a/Telegram/SourceFiles/data/data_message_reactions.h b/Telegram/SourceFiles/data/data_message_reactions.h index b17d722ed..cfa284bd1 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.h +++ b/Telegram/SourceFiles/data/data_message_reactions.h @@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/timer.h" +namespace Lottie { +class Icon; +} // namespace Lottie + namespace Data { class DocumentMedia; @@ -22,14 +26,15 @@ struct Reaction { not_null selectAnimation; not_null activateAnimation; not_null activateEffects; + not_null centerIcon; DocumentData *aroundAnimation = nullptr; - DocumentData *centerIcon = nullptr; bool active = false; }; class Reactions final { public: explicit Reactions(not_null owner); + ~Reactions(); void refresh(); @@ -72,6 +77,7 @@ private: QImage bottomInfo; QImage inlineList; std::shared_ptr media; + std::unique_ptr icon; }; void request(); @@ -80,7 +86,7 @@ private: const MTPAvailableReaction &entry); void loadImage(ImageSet &set, not_null document); - void setImage(ImageSet &set, QImage large); + void setLottie(ImageSet &set); void resolveImages(); void downloadTaskFinished();