diff --git a/Telegram/Resources/tl/api.tl b/Telegram/Resources/tl/api.tl index 0d0416776..97961c1ae 100644 --- a/Telegram/Resources/tl/api.tl +++ b/Telegram/Resources/tl/api.tl @@ -629,7 +629,7 @@ messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity; messageEntityBlockquote#20df5d0 offset:int length:int = MessageEntity; messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity; messageEntitySpoiler#32ca960f offset:int length:int = MessageEntity; -messageEntityCustomEmoji#d4a00ed5 offset:int length:int stickerset:InputStickerSet document_id:long = MessageEntity; +messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = MessageEntity; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; @@ -1696,6 +1696,7 @@ messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInl messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; messages.rateTranscribedAudio#7f1d072f peer:InputPeer msg_id:int transcription_id:long good:Bool = Bool; +messages.getCustomEmojiDocuments#d9ab0f54 document_id:Vector = Vector; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; @@ -1800,7 +1801,7 @@ payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?t payments.getBankCardData#2e79d779 number:string = payments.BankCardData; payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaymentPurpose = Updates; -payments.assignPlayMarketTransaction#f546d3fe purchase_token:string purpose:InputStorePaymentPurpose = Updates; +payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates; payments.canPurchasePremium#aa6a90c8 = Bool; payments.requestRecurringPayment#146e958d user_id:InputUser recurring_init_charge:string invoice_media:InputMedia = Updates; diff --git a/Telegram/SourceFiles/api/api_text_entities.cpp b/Telegram/SourceFiles/api/api_text_entities.cpp index f83c01a09..5bd25eb21 100644 --- a/Telegram/SourceFiles/api/api_text_entities.cpp +++ b/Telegram/SourceFiles/api/api_text_entities.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/stickers/data_custom_emoji.h" #include "data/stickers/data_stickers_set.h" #include "data/data_session.h" +#include "data/data_document.h" #include "data/data_user.h" namespace Api { @@ -24,7 +25,6 @@ using namespace TextUtilities; return Data::SerializeCustomEmojiId({ .selfId = session->userId().bare, .id = data.vdocument_id().v, - .set = Data::FromInputSet(data.vstickerset()), }); } @@ -37,11 +37,14 @@ using namespace TextUtilities; if (!parsed.id || parsed.selfId != session->userId().bare) { return {}; } + const auto document = session->data().document(parsed.id); + if (!document->sticker()) { + return {}; + } return MTP_messageEntityCustomEmoji( offset, length, - Data::InputStickerSet(parsed.set), - MTP_long(parsed.id)); + MTP_long(document->id)); } [[nodiscard]] std::optional MentionNameEntity( diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp index 8858ad405..0afbecd32 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp @@ -22,10 +22,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "data/stickers/data_stickers.h" +#include "ui/widgets/input_fields.h" +#include "ui/text/text_block.h" namespace Data { namespace { +constexpr auto kMaxPerRequest = 100; + using SizeTag = CustomEmojiManager::SizeTag; [[nodiscard]] ChatHelpers::StickerLottieSize LottieSizeFromTag(SizeTag tag) { @@ -306,7 +310,7 @@ auto CustomEmojiLoader::InitialState( const CustomEmojiId &id) -> std::variant { const auto document = owner->document(id.id); - if (!document->isNull()) { + if (document->sticker()) { return Lookup{ document }; } return Resolve{ .entityData = SerializeCustomEmojiId(id) }; @@ -353,15 +357,11 @@ std::unique_ptr CustomEmojiManager::create( QStringView data, Fn update) { const auto parsed = ParseCustomEmojiData(data); - if (!parsed.id || !parsed.set.id) { + if (!parsed.id) { return nullptr; } - auto i = _instances.find(parsed.set.id); + auto i = _instances.find(parsed.id); if (i == end(_instances)) { - i = _instances.emplace(parsed.set.id).first; - } - auto j = i->second.find(parsed.id); - if (j == end(i->second)) { using Loading = Ui::CustomEmoji::Loading; auto loader = std::make_unique( _owner, @@ -369,76 +369,69 @@ std::unique_ptr CustomEmojiManager::create( SizeTag::Normal); if (loader->resolving()) { _loaders[parsed.id].push_back(base::make_weak(loader.get())); + _pendingForRequest.emplace(parsed.id); + if (!_requestId && _pendingForRequest.size() == 1) { + crl::on_main(this, [=] { request(); }); + } } const auto repaint = [=]( not_null instance, Ui::CustomEmoji::RepaintRequest request) { repaintLater(instance, request); }; - j = i->second.emplace( + i = _instances.emplace( parsed.id, std::make_unique(Loading{ std::move(loader), Ui::CustomEmoji::Preview() }, std::move(repaint))).first; } - requestSetIfNeeded(parsed); return std::make_unique( - j->second.get(), + i->second.get(), std::move(update)); } -void CustomEmojiManager::requestSetIfNeeded(const CustomEmojiId &id) { - const auto setId = id.set.id; - auto i = _sets.find(setId); - if (i == end(_sets)) { - i = _sets.emplace(setId).first; +void CustomEmojiManager::request() { + auto ids = QVector(); + ids.reserve(std::min(kMaxPerRequest, int(_pendingForRequest.size()))); + while (!_pendingForRequest.empty() && ids.size() < kMaxPerRequest) { + const auto i = _pendingForRequest.end() - 1; + ids.push_back(MTP_long(*i)); + _pendingForRequest.erase(i); } - if (i->second.documents.contains(id.id)) { - return; - } else if (!i->second.waiting.emplace(id.id).second - || i->second.requestId) { + if (ids.isEmpty()) { return; } const auto api = &_owner->session().api(); - i->second.requestId = api->request(MTPmessages_GetStickerSet( - InputStickerSet(id.set), - MTP_int(i->second.hash) - )).done([=](const MTPmessages_StickerSet &result) { - const auto i = _sets.find(setId); - Assert(i != end(_sets)); - i->second.requestId = 0; - result.match([&](const MTPDmessages_stickerSet &data) { - data.vset().match([&](const MTPDstickerSet &data) { - i->second.hash = data.vhash().v; - }); - for (const auto &entry : data.vdocuments().v) { - const auto document = _owner->processDocument(entry); - const auto id = document->id; - i->second.documents.emplace(id); - i->second.waiting.remove(id); - if (const auto loaders = _loaders.take(id)) { - for (const auto &weak : *loaders) { - if (const auto strong = weak.get()) { - strong->resolved(document); - } + _requestId = api->request(MTPmessages_GetCustomEmojiDocuments( + MTP_vector(ids) + )).done([=](const MTPVector &result) { + for (const auto &entry : result.v) { + const auto document = _owner->processDocument(entry); + const auto id = document->id; + if (const auto loaders = _loaders.take(id)) { + for (const auto &weak : *loaders) { + if (const auto strong = weak.get()) { + strong->resolved(document); } } } - }, [&](const MTPDmessages_stickerSetNotModified &) { - }); - for (const auto &id : base::take(i->second.waiting)) { - DEBUG_LOG(("API Error: Sticker '%1' not found for emoji.").arg(id)); } + requestFinished(); }).fail([=] { - const auto i = _sets.find(setId); - Assert(i != end(_sets)); - i->second.requestId = 0; - LOG(("API Error: Failed getting set '%1' for emoji.").arg(setId)); + LOG(("API Error: Failed to get documents for emoji.")); + requestFinished(); }).send(); } +void CustomEmojiManager::requestFinished() { + _requestId = 0; + if (!_pendingForRequest.empty()) { + request(); + } +} + void CustomEmojiManager::repaintLater( not_null instance, Ui::CustomEmoji::RepaintRequest request) { @@ -506,45 +499,40 @@ Session &CustomEmojiManager::owner() const { } QString SerializeCustomEmojiId(const CustomEmojiId &id) { - return QString::number(id.set.id) - + '.' - + QString::number(id.set.accessHash) + return QString::number(id.id) + ':' - + QString::number(id.selfId) - + '/' - + QString::number(id.id); + + QString::number(id.selfId); } QString SerializeCustomEmojiId(not_null document) { - const auto sticker = document->sticker(); return SerializeCustomEmojiId({ .selfId = document->session().userId().bare, .id = document->id, - .set = sticker ? sticker->set : StickerSetIdentifier(), }); } CustomEmojiId ParseCustomEmojiData(QStringView data) { - const auto components = data.split('.'); + const auto components = data.split(':'); if (components.size() != 2) { return {}; } - const auto parts = components[1].split(':'); - if (parts.size() != 2) { - return {}; - } - const auto endings = parts[1].split('/'); - if (endings.size() != 2) { - return {}; - } return { - .selfId = endings[0].toULongLong(), - .id = endings[1].toULongLong(), - .set = { - .id = components[0].toULongLong(), - .accessHash = parts[0].toULongLong(), - }, + .selfId = components[1].toULongLong(), + .id = components[0].toULongLong(), }; } +void InsertCustomEmoji( + not_null field, + not_null document) { + const auto sticker = document->sticker(); + if (!sticker || sticker->alt.isEmpty()) { + return; + } + Ui::InsertCustomEmojiAtCursor( + field->textCursor(), + sticker->alt, + Ui::InputField::CustomEmojiLink(SerializeCustomEmojiId(document))); +} + } // namespace Data diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.h b/Telegram/SourceFiles/data/stickers/data_custom_emoji.h index 3a58a09de..1efd5a6ab 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.h +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.h @@ -26,7 +26,6 @@ class CustomEmojiLoader; struct CustomEmojiId { uint64 selfId = 0; uint64 id = 0; - StickerSetIdentifier set; }; class CustomEmojiManager final : public base::has_weak_ptr { @@ -47,18 +46,13 @@ public: [[nodiscard]] Session &owner() const; private: - struct Set { - int32 hash = 0; - mtpRequestId requestId = 0; - base::flat_set documents; - base::flat_set waiting; - }; struct RepaintBunch { crl::time when = 0; std::vector> instances; }; - void requestSetIfNeeded(const CustomEmojiId &id); + void request(); + void requestFinished(); void repaintLater( not_null instance, Ui::CustomEmoji::RepaintRequest request); @@ -67,13 +61,14 @@ private: const not_null _owner; - base::flat_map>> _instances; - base::flat_map _sets; + std::unique_ptr> _instances; base::flat_map< uint64, std::vector>> _loaders; + base::flat_set _pendingForRequest; + mtpRequestId _requestId = 0; base::flat_map _repaints; crl::time _repaintNext = 0; @@ -87,4 +82,8 @@ private: not_null document); [[nodiscard]] CustomEmojiId ParseCustomEmojiData(QStringView data); +void InsertCustomEmoji( + not_null field, + not_null document); + } // namespace Data diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 464c6a617..9cb7bb58f 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 464c6a61711fa7b66d45829bde582d36e23f0b1a +Subproject commit 9cb7bb58f658d7603f9493b9d051cf8a78a2cd41