Resolve custom emoji in OnlyCustomEmoji media.
This commit is contained in:
parent
f8e22210e7
commit
543bfab24a
|
@ -124,19 +124,7 @@ EmojiPack::~EmojiPack() = default;
|
|||
|
||||
bool EmojiPack::add(not_null<HistoryItem*> 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<const HistoryItem*> 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));
|
||||
|
|
|
@ -107,12 +107,7 @@ private:
|
|||
base::flat_map<EmojiPtr, std::weak_ptr<LargeEmojiImage>> _images;
|
||||
mtpRequestId _requestId = 0;
|
||||
|
||||
base::flat_map<
|
||||
not_null<HistoryItem*>,
|
||||
base::flat_set<DocumentId>> _onlyCustomItems;
|
||||
base::flat_map<
|
||||
DocumentId,
|
||||
base::flat_set<not_null<HistoryItem*>>> _onlyCustomWaiting;
|
||||
base::flat_set<not_null<HistoryItem*>> _onlyCustomItems;
|
||||
|
||||
base::flat_map<
|
||||
EmojiPtr,
|
||||
|
|
|
@ -446,22 +446,37 @@ std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
|||
});
|
||||
}
|
||||
|
||||
bool CustomEmojiManager::resolved(QStringView data, Fn<void()> callback) {
|
||||
return resolved(ParseCustomEmojiData(data).id, std::move(callback));
|
||||
void CustomEmojiManager::resolve(
|
||||
QStringView data,
|
||||
not_null<Listener*> listener) {
|
||||
resolve(ParseCustomEmojiData(data).id, listener);
|
||||
}
|
||||
|
||||
bool CustomEmojiManager::resolved(
|
||||
void CustomEmojiManager::resolve(
|
||||
DocumentId documentId,
|
||||
Fn<void()> callback) {
|
||||
not_null<Listener*> 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*> 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<Ui::CustomEmoji::Loader> 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);
|
||||
|
|
|
@ -54,8 +54,14 @@ public:
|
|||
Fn<void()> update,
|
||||
SizeTag tag = SizeTag::Normal);
|
||||
|
||||
bool resolved(QStringView data, Fn<void()> callback);
|
||||
bool resolved(DocumentId documentId, Fn<void()> callback);
|
||||
class Listener {
|
||||
public:
|
||||
virtual void customEmojiResolveDone(
|
||||
not_null<DocumentData*> document) = 0;
|
||||
};
|
||||
void resolve(QStringView data, not_null<Listener*> listener);
|
||||
void resolve(DocumentId documentId, not_null<Listener*> listener);
|
||||
void unregisterListener(not_null<Listener*> listener);
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Ui::CustomEmoji::Loader> createLoader(
|
||||
not_null<DocumentData*> document,
|
||||
|
@ -109,7 +115,12 @@ private:
|
|||
DocumentId,
|
||||
std::vector<base::weak_ptr<CustomEmojiLoader>>>,
|
||||
kSizeCount> _loaders;
|
||||
base::flat_map<DocumentId, std::vector<Fn<void()>>> _resolvers;
|
||||
base::flat_map<
|
||||
DocumentId,
|
||||
base::flat_set<not_null<Listener*>>> _resolvers;
|
||||
base::flat_map<
|
||||
not_null<Listener*>,
|
||||
base::flat_set<DocumentId>> _listeners;
|
||||
base::flat_set<DocumentId> _pendingForRequest;
|
||||
mtpRequestId _requestId = 0;
|
||||
|
||||
|
|
|
@ -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<DocumentData*> 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<Sticker>(
|
||||
_parent,
|
||||
document,
|
||||
skipPremiumEffect);
|
||||
sticker->setCustomEmojiPart(_singleSize, _cachingTag);
|
||||
entry = std::move(sticker);
|
||||
} else if (v::is<DocumentId>(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() {
|
||||
|
|
|
@ -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<Sticker>,
|
||||
std::unique_ptr<Ui::Text::CustomEmoji>>;
|
||||
|
||||
class CustomEmoji final : public UnwrappedMedia::Content {
|
||||
class CustomEmoji final
|
||||
: public UnwrappedMedia::Content
|
||||
, private Data::CustomEmojiManager::Listener {
|
||||
public:
|
||||
CustomEmoji(
|
||||
not_null<Element*> parent,
|
||||
|
@ -51,6 +58,9 @@ public:
|
|||
void unloadHeavyPart() override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] not_null<Data::CustomEmojiManager::Listener*> listener() {
|
||||
return this;
|
||||
}
|
||||
void paintElement(
|
||||
Painter &p,
|
||||
int x,
|
||||
|
@ -73,11 +83,15 @@ private:
|
|||
const PaintContext &context,
|
||||
bool paused);
|
||||
|
||||
void customEmojiResolveDone(not_null<DocumentData*> document) override;
|
||||
|
||||
const not_null<Element*> _parent;
|
||||
std::vector<std::vector<LargeCustomEmoji>> _lines;
|
||||
QImage _selectedFrame;
|
||||
int _singleSize = 0;
|
||||
ChatHelpers::StickerLottieSize _cachingTag = {};
|
||||
bool _hasHeavyPart = false;
|
||||
bool _resolving = false;
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue