diff --git a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp index 441a0b8ce9..050cb569be 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp @@ -124,19 +124,7 @@ EmojiPack::~EmojiPack() = default; bool EmojiPack::add(not_null item) { if (const auto custom = item->onlyCustomEmoji()) { - auto &ids = _onlyCustomItems[item]; - Assert(ids.empty()); - auto &manager = item->history()->owner().customEmojiManager(); - for (const auto &line : custom.lines) { - for (const auto &element : line) { - const auto &data = element.entityData; - const auto id = Data::ParseCustomEmojiData(data).id; - if (!manager.resolved(id, [] {})) { - ids.emplace(id); - _onlyCustomWaiting[id].emplace(item); - } - } - } + _onlyCustomItems.emplace(item); return true; } else if (const auto emoji = item->isolatedEmoji()) { _items[emoji].emplace(item); @@ -149,16 +137,7 @@ void EmojiPack::remove(not_null item) { Expects(item->isIsolatedEmoji() || item->isOnlyCustomEmoji()); if (item->isOnlyCustomEmoji()) { - if (const auto list = _onlyCustomItems.take(item)) { - for (const auto id : *list) { - const auto i = _onlyCustomWaiting.find(id); - Assert(i != end(_onlyCustomWaiting)); - i->second.remove(item); - if (i->second.empty()) { - _onlyCustomWaiting.erase(i); - } - } - } + _onlyCustomItems.remove(item); } else if (const auto emoji = item->isolatedEmoji()) { const auto i = _items.find(emoji); Assert(i != end(_items)); diff --git a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h index 7423764175..947cd0a3cb 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h @@ -107,12 +107,7 @@ private: base::flat_map> _images; mtpRequestId _requestId = 0; - base::flat_map< - not_null, - base::flat_set> _onlyCustomItems; - base::flat_map< - DocumentId, - base::flat_set>> _onlyCustomWaiting; + base::flat_set> _onlyCustomItems; base::flat_map< EmojiPtr, diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp index c55f59ee04..c1b4b71f80 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp @@ -446,22 +446,37 @@ std::unique_ptr CustomEmojiManager::create( }); } -bool CustomEmojiManager::resolved(QStringView data, Fn callback) { - return resolved(ParseCustomEmojiData(data).id, std::move(callback)); +void CustomEmojiManager::resolve( + QStringView data, + not_null listener) { + resolve(ParseCustomEmojiData(data).id, listener); } -bool CustomEmojiManager::resolved( +void CustomEmojiManager::resolve( DocumentId documentId, - Fn callback) { + not_null listener) { if (_owner->document(documentId)->sticker()) { - return true; + return; } - _resolvers[documentId].push_back(std::move(callback)); + _resolvers[documentId].emplace(listener); + _listeners[listener].emplace(documentId); _pendingForRequest.emplace(documentId); if (!_requestId && _pendingForRequest.size() == 1) { crl::on_main(this, [=] { request(); }); } - return false; +} + +void CustomEmojiManager::unregisterListener(not_null listener) { + if (const auto list = _listeners.take(listener)) { + for (const auto id : *list) { + const auto i = _resolvers.find(id); + if (i != end(_resolvers) + && i->second.remove(listener) + && i->second.empty()) { + _resolvers.erase(i); + } + } + } } std::unique_ptr CustomEmojiManager::createLoader( @@ -523,9 +538,15 @@ void CustomEmojiManager::request() { } } } - if (const auto callbacks = _resolvers.take(id)) { - for (const auto &callback : *callbacks) { - callback(); + if (const auto listeners = _resolvers.take(id)) { + for (const auto &listener : *listeners) { + const auto i = _listeners.find(listener); + if (i != end(_listeners) && i->second.remove(id)) { + if (i->second.empty()) { + _listeners.erase(i); + } + listener->customEmojiResolveDone(document); + } } } requestSetFor(document); diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.h b/Telegram/SourceFiles/data/stickers/data_custom_emoji.h index 1e8825f033..c8c3f9fa91 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.h +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.h @@ -54,8 +54,14 @@ public: Fn update, SizeTag tag = SizeTag::Normal); - bool resolved(QStringView data, Fn callback); - bool resolved(DocumentId documentId, Fn callback); + class Listener { + public: + virtual void customEmojiResolveDone( + not_null document) = 0; + }; + void resolve(QStringView data, not_null listener); + void resolve(DocumentId documentId, not_null listener); + void unregisterListener(not_null listener); [[nodiscard]] std::unique_ptr createLoader( not_null document, @@ -109,7 +115,12 @@ private: DocumentId, std::vector>>, kSizeCount> _loaders; - base::flat_map>> _resolvers; + base::flat_map< + DocumentId, + base::flat_set>> _resolvers; + base::flat_map< + not_null, + base::flat_set> _listeners; base::flat_set _pendingForRequest; mtpRequestId _requestId = 0; diff --git a/Telegram/SourceFiles/history/view/media/history_view_custom_emoji.cpp b/Telegram/SourceFiles/history/view/media/history_view_custom_emoji.cpp index 81045544b8..f4ea853390 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_custom_emoji.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_custom_emoji.cpp @@ -64,7 +64,6 @@ CustomEmoji::CustomEmoji( : _parent(parent) { Expects(!emoji.lines.empty()); - auto resolving = false; const auto owner = &parent->data()->history()->owner(); const auto manager = &owner->customEmojiManager(); const auto max = ranges::max_element( @@ -79,6 +78,9 @@ CustomEmoji::CustomEmoji( _singleSize = !useCustomEmoji ? int(base::SafeRound(i->second.scale * st::maxAnimatedEmojiSize)) : Data::FrameSizeFromTag(tag); + if (!useCustomEmoji) { + _cachingTag = i->second.tag; + } for (const auto &line : emoji.lines) { _lines.emplace_back(); for (const auto &element : line) { @@ -98,17 +100,35 @@ CustomEmoji::CustomEmoji( parent, document, skipPremiumEffect); - sticker->setCustomEmojiPart(_singleSize, i->second.tag); + sticker->setCustomEmojiPart(_singleSize, _cachingTag); _lines.back().push_back(std::move(sticker)); } else { - _lines.back().push_back(element.entityData); - resolving = true; + _lines.back().push_back(id); + manager->resolve(id, listener()); + _resolving = true; } } } } - if (resolving) { +} +void CustomEmoji::customEmojiResolveDone(not_null document) { + _resolving = false; + const auto id = document->id; + for (auto &line : _lines) { + for (auto &entry : line) { + if (entry == id) { + const auto skipPremiumEffect = false; + auto sticker = std::make_unique( + _parent, + document, + skipPremiumEffect); + sticker->setCustomEmojiPart(_singleSize, _cachingTag); + entry = std::move(sticker); + } else if (v::is(entry)) { + _resolving = true; + } + } } } @@ -117,6 +137,10 @@ CustomEmoji::~CustomEmoji() { unloadHeavyPart(); _parent->checkHeavyPart(); } + if (_resolving) { + const auto owner = &_parent->data()->history()->owner(); + owner->customEmojiManager().unregisterListener(listener()); + } } QSize CustomEmoji::countOptimalSize() { diff --git a/Telegram/SourceFiles/history/view/media/history_view_custom_emoji.h b/Telegram/SourceFiles/history/view/media/history_view_custom_emoji.h index 275a906092..a37196754a 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_custom_emoji.h +++ b/Telegram/SourceFiles/history/view/media/history_view_custom_emoji.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "history/view/media/history_view_media_unwrapped.h" +#include "data/stickers/data_custom_emoji.h" namespace Ui::Text { struct OnlyCustomEmoji; @@ -17,16 +18,22 @@ namespace Stickers { struct LargeEmojiImage; } // namespace Stickers +namespace ChatHelpers { +enum class StickerLottieSize : uint8; +} // namespace ChatHelpers + namespace HistoryView { class Sticker; using LargeCustomEmoji = std::variant< - QString, + DocumentId, std::unique_ptr, std::unique_ptr>; -class CustomEmoji final : public UnwrappedMedia::Content { +class CustomEmoji final + : public UnwrappedMedia::Content + , private Data::CustomEmojiManager::Listener { public: CustomEmoji( not_null parent, @@ -51,6 +58,9 @@ public: void unloadHeavyPart() override; private: + [[nodiscard]] not_null listener() { + return this; + } void paintElement( Painter &p, int x, @@ -73,11 +83,15 @@ private: const PaintContext &context, bool paused); + void customEmojiResolveDone(not_null document) override; + const not_null _parent; std::vector> _lines; QImage _selectedFrame; int _singleSize = 0; + ChatHelpers::StickerLottieSize _cachingTag = {}; bool _hasHeavyPart = false; + bool _resolving = false; };