diff --git a/Telegram/Resources/tl/api.tl b/Telegram/Resources/tl/api.tl index 96e0b2fc8f..3298ffc762 100644 --- a/Telegram/Resources/tl/api.tl +++ b/Telegram/Resources/tl/api.tl @@ -628,6 +628,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; inputChannelEmpty#ee8c1e86 = InputChannel; inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; @@ -742,7 +743,7 @@ draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector date:int = DraftMessage; messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; -messages.featuredStickers#84c02310 hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; +messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; messages.recentStickersNotModified#b17f890 = messages.RecentStickers; messages.recentStickers#88d37c56 hash:long packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; @@ -1792,9 +1793,8 @@ payments.getSavedInfo#227d824b = payments.SavedInfo; payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; payments.getBankCardData#2e79d779 number:string = payments.BankCardData; payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; -payments.assignAppStoreTransaction#fec13c6 flags:# restore:flags.0?true transaction_id:string receipt:bytes = Updates; +payments.assignAppStoreTransaction#d5ccfd0 flags:# restore:flags.0?true receipt:bytes = Updates; payments.assignPlayMarketTransaction#4faa4aed purchase_token:string = Updates; -payments.restorePlayMarketReceipt#d164e36a receipt:bytes = Updates; payments.canPurchasePremium#aa6a90c8 = Bool; payments.requestRecurringPayment#146e958d user_id:InputUser recurring_init_charge:string invoice_media:InputMedia = Updates; @@ -1853,4 +1853,4 @@ stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; -// LAYER 143 +// LAYER 144 diff --git a/Telegram/SourceFiles/api/api_text_entities.cpp b/Telegram/SourceFiles/api/api_text_entities.cpp index a867445948..f83c01a09e 100644 --- a/Telegram/SourceFiles/api/api_text_entities.cpp +++ b/Telegram/SourceFiles/api/api_text_entities.cpp @@ -8,15 +8,61 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_text_entities.h" #include "main/main_session.h" +#include "data/stickers/data_custom_emoji.h" +#include "data/stickers/data_stickers_set.h" #include "data/data_session.h" #include "data/data_user.h" - namespace Api { namespace { using namespace TextUtilities; +[[nodiscard]] QString CustomEmojiEntityData( + not_null session, + const MTPDmessageEntityCustomEmoji &data) { + return Data::SerializeCustomEmojiId({ + .selfId = session->userId().bare, + .id = data.vdocument_id().v, + .set = Data::FromInputSet(data.vstickerset()), + }); +} + +[[nodiscard]] std::optional CustomEmojiEntity( + not_null session, + MTPint offset, + MTPint length, + const QString &data) { + const auto parsed = Data::ParseCustomEmojiData(data); + if (!parsed.id || parsed.selfId != session->userId().bare) { + return {}; + } + return MTP_messageEntityCustomEmoji( + offset, + length, + Data::InputStickerSet(parsed.set), + MTP_long(parsed.id)); +} + +[[nodiscard]] std::optional MentionNameEntity( + not_null session, + MTPint offset, + MTPint length, + const QString &data) { + const auto parsed = MentionNameDataToFields(data); + if (!parsed.userId || parsed.selfId != session->userId().bare) { + return {}; + } + return MTP_inputMessageEntityMentionName( + offset, + length, + (parsed.userId == parsed.selfId + ? MTP_inputUserSelf() + : MTP_inputUser( + MTP_long(parsed.userId), + MTP_long(parsed.accessHash)))); +} + } // namespace EntitiesInText EntitiesFromMTP( @@ -34,34 +80,35 @@ EntitiesInText EntitiesFromMTP( case mtpc_messageEntityCashtag: { auto &d = entity.c_messageEntityCashtag(); result.push_back({ EntityType::Cashtag, d.voffset().v, d.vlength().v }); } break; case mtpc_messageEntityPhone: break; // Skipping phones. case mtpc_messageEntityMention: { auto &d = entity.c_messageEntityMention(); result.push_back({ EntityType::Mention, d.voffset().v, d.vlength().v }); } break; - case mtpc_messageEntityMentionName: { + case mtpc_messageEntityMentionName: if (session) { const auto &d = entity.c_messageEntityMentionName(); const auto userId = UserId(d.vuser_id()); - const auto data = [&] { - if (session) { - if (const auto user = session->data().userLoaded(userId)) { - return MentionNameDataFromFields({ - userId.bare, - user->accessHash() - }); - } - } - return MentionNameDataFromFields(userId.bare); - }(); + const auto user = session->data().userLoaded(userId); + const auto data = MentionNameDataFromFields({ + .selfId = session->userId().bare, + .userId = userId.bare, + .accessHash = user ? user->accessHash() : 0, + }); result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data }); } break; - case mtpc_inputMessageEntityMentionName: { + case mtpc_inputMessageEntityMentionName: if (session) { const auto &d = entity.c_inputMessageEntityMentionName(); - const auto data = [&] { - if (session && d.vuser_id().type() == mtpc_inputUserSelf) { - return MentionNameDataFromFields(session->userId().bare); - } else if (d.vuser_id().type() == mtpc_inputUser) { - auto &user = d.vuser_id().c_inputUser(); - const auto userId = UserId(user.vuser_id()); - return MentionNameDataFromFields({ userId.bare, user.vaccess_hash().v }); - } + const auto data = d.vuser_id().match([&]( + const MTPDinputUserSelf &) { + return MentionNameDataFromFields({ + .selfId = session->userId().bare, + .userId = session->userId().bare, + .accessHash = session->user()->accessHash(), + }); + }, [&](const MTPDinputUser &data) { + return MentionNameDataFromFields({ + .selfId = session->userId().bare, + .userId = UserId(data.vuser_id()).bare, + .accessHash = data.vaccess_hash().v, + }); + }, [&](const auto &) { return QString(); - }(); + }); if (!data.isEmpty()) { result.push_back({ EntityType::MentionName, d.voffset().v, d.vlength().v, data }); } @@ -73,9 +120,12 @@ EntitiesInText EntitiesFromMTP( case mtpc_messageEntityStrike: { auto &d = entity.c_messageEntityStrike(); result.push_back({ EntityType::StrikeOut, d.voffset().v, d.vlength().v }); } break; case mtpc_messageEntityCode: { auto &d = entity.c_messageEntityCode(); result.push_back({ EntityType::Code, d.voffset().v, d.vlength().v }); } break; case mtpc_messageEntityPre: { auto &d = entity.c_messageEntityPre(); result.push_back({ EntityType::Pre, d.voffset().v, d.vlength().v, qs(d.vlanguage()) }); } break; - case mtpc_messageEntityBankCard: break; // Skipping cards. + case mtpc_messageEntityBankCard: break; // Skipping cards. // #TODO entities case mtpc_messageEntitySpoiler: { auto &d = entity.c_messageEntitySpoiler(); result.push_back({ EntityType::Spoiler, d.voffset().v, d.vlength().v }); } break; - // #TODO entities + case mtpc_messageEntityCustomEmoji: if (session) { + const auto &d = entity.c_messageEntityCustomEmoji(); + result.push_back({ EntityType::CustomEmoji, d.voffset().v, d.vlength().v, CustomEmojiEntityData(session, d) }); + } break; } } } @@ -100,7 +150,8 @@ MTPVector EntitiesToMTP( && entity.type() != EntityType::Pre && entity.type() != EntityType::Spoiler && entity.type() != EntityType::MentionName - && entity.type() != EntityType::CustomUrl) { + && entity.type() != EntityType::CustomUrl + && entity.type() != EntityType::CustomEmoji) { continue; } @@ -114,17 +165,8 @@ MTPVector EntitiesToMTP( case EntityType::Cashtag: v.push_back(MTP_messageEntityCashtag(offset, length)); break; case EntityType::Mention: v.push_back(MTP_messageEntityMention(offset, length)); break; case EntityType::MentionName: { - auto inputUser = [&](const QString &data) -> MTPInputUser { - auto fields = MentionNameDataToFields(data); - if (session && fields.userId == session->userId().bare) { - return MTP_inputUserSelf(); - } else if (fields.userId) { - return MTP_inputUser(MTP_long(fields.userId), MTP_long(fields.accessHash)); - } - return MTP_inputUserEmpty(); - }(entity.data()); - if (inputUser.type() != mtpc_inputUserEmpty) { - v.push_back(MTP_inputMessageEntityMentionName(offset, length, inputUser)); + if (const auto valid = MentionNameEntity(session, offset, length, entity.data())) { + v.push_back(*valid); } } break; case EntityType::BotCommand: v.push_back(MTP_messageEntityBotCommand(offset, length)); break; @@ -135,6 +177,11 @@ MTPVector EntitiesToMTP( case EntityType::Code: v.push_back(MTP_messageEntityCode(offset, length)); break; // #TODO entities case EntityType::Pre: v.push_back(MTP_messageEntityPre(offset, length, MTP_string(entity.data()))); break; case EntityType::Spoiler: v.push_back(MTP_messageEntitySpoiler(offset, length)); break; + case EntityType::CustomEmoji: { + if (const auto valid = CustomEmojiEntity(session, offset, length, entity.data())) { + v.push_back(*valid); + } + } break; } } return MTP_vector(std::move(v)); diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 6b9cf7e0b6..3194d84b6c 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/ui_utility.h" #include "data/data_session.h" #include "data/data_user.h" +#include "data/stickers/data_custom_emoji.h" #include "chat_helpers/emoji_suggestions_widget.h" #include "window/window_session_controller.h" #include "lang/lang_keys.h" @@ -48,13 +49,14 @@ using EditLinkSelection = Ui::InputField::EditLinkSelection; constexpr auto kParseLinksTimeout = crl::time(1000); -// For mention tags save and validate userId, ignore tags for different userId. -class FieldTagMimeProcessor : public Ui::InputField::TagMimeProcessor { +// For mention / custom emoji tags save and validate selfId, +// ignore tags for different users. +class FieldTagMimeProcessor final { public: explicit FieldTagMimeProcessor( not_null controller); - QString tagFromMimeTag(const QString &mimeTag) override; + QString operator()(QStringView mimeTag); private: const not_null _controller; @@ -66,17 +68,23 @@ FieldTagMimeProcessor::FieldTagMimeProcessor( : _controller(controller) { } -QString FieldTagMimeProcessor::tagFromMimeTag(const QString &mimeTag) { - if (TextUtilities::IsMentionLink(mimeTag)) { - const auto userId = _controller->session().userId(); - auto match = QRegularExpression(":(\\d+)$").match(mimeTag); - if (!match.hasMatch() - || match.capturedView(1).toULongLong() != userId.bare) { - return QString(); +QString FieldTagMimeProcessor::operator()(QStringView mimeTag) { + const auto id = _controller->session().userId().bare; + auto all = TextUtilities::SplitTags(mimeTag); + for (auto i = all.begin(); i != all.end();) { + const auto tag = *i; + if (TextUtilities::IsMentionLink(tag) + && TextUtilities::MentionNameDataToFields(tag).selfId != id) { + i = all.erase(i); + } else if (Ui::InputField::IsCustomEmojiLink(tag) + && Data::ParseCustomEmojiData( + Ui::InputField::CustomEmojiEntityData(tag)).selfId != id) { + i = all.erase(i); + } else { + ++i; } - return mimeTag.mid(0, mimeTag.size() - match.capturedLength()); } - return mimeTag; + return TextUtilities::JoinTag(all); } //bool ValidateUrl(const QString &value) { @@ -225,7 +233,9 @@ QString PrepareMentionTag(not_null user) { return TextUtilities::kMentionTagStart + QString::number(user->id.value) + '.' - + QString::number(user->accessHash()); + + QString::number(user->accessHash()) + + ':' + + QString::number(user->session().userId().bare); } TextWithTags PrepareEditText(not_null item) { @@ -279,11 +289,19 @@ Fn controller, not_null field) { - field->setMinHeight(st::historySendSize.height() - 2 * st::historySendPadding); + field->setMinHeight( + st::historySendSize.height() - 2 * st::historySendPadding); field->setMaxHeight(st::historyComposeFieldMaxHeight); - field->setTagMimeProcessor( - std::make_unique(controller)); + field->setTagMimeProcessor(FieldTagMimeProcessor(controller)); + field->setCustomEmojiFactory([=](QStringView data, Fn update) { + return controller->session().data().customEmojiManager().create( + data, + std::move(update)); + }, [=] { + return controller->isGifPausedAtLeastFor( + Window::GifPauseReason::Any); + }); field->document()->setDocumentMargin(4.); field->setAdditionalMargin(style::ConvertScale(4) - 4); diff --git a/Telegram/SourceFiles/core/ui_integration.cpp b/Telegram/SourceFiles/core/ui_integration.cpp index a052ef6a72..067f994532 100644 --- a/Telegram/SourceFiles/core/ui_integration.cpp +++ b/Telegram/SourceFiles/core/ui_integration.cpp @@ -258,15 +258,6 @@ rpl::producer<> UiIntegration::forcePopupMenuHideRequests() { return Core::App().passcodeLockChanges() | rpl::to_empty; } -QString UiIntegration::convertTagToMimeTag(const QString &tagId) { - if (TextUtilities::IsMentionLink(tagId)) { - if (const auto session = Core::App().activeAccount().maybeSession()) { - return tagId + ':' + QString::number(session->userId().bare); - } - } - return tagId; -} - const Ui::Emoji::One *UiIntegration::defaultEmojiVariant( const Ui::Emoji::One *emoji) { if (!emoji || !emoji->hasVariants()) { diff --git a/Telegram/SourceFiles/core/ui_integration.h b/Telegram/SourceFiles/core/ui_integration.h index 87b5a2f780..7e61e10606 100644 --- a/Telegram/SourceFiles/core/ui_integration.h +++ b/Telegram/SourceFiles/core/ui_integration.h @@ -54,7 +54,6 @@ public: const QString &url, const QVariant &context) override; rpl::producer<> forcePopupMenuHideRequests() override; - QString convertTagToMimeTag(const QString &tagId) override; const Ui::Emoji::One *defaultEmojiVariant( const Ui::Emoji::One *emoji) override; std::unique_ptr createCustomEmoji( diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp index a80274b446..47fb2bdc17 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp @@ -22,15 +22,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "data/stickers/data_stickers.h" -#include "data/stickers/data_stickers_set.h" namespace Data { - -struct CustomEmojiId { - StickerSetIdentifier set; - uint64 id = 0; -}; - namespace { using SizeTag = CustomEmojiManager::SizeTag; @@ -52,42 +45,6 @@ using SizeTag = CustomEmojiManager::SizeTag; Unexpected("SizeTag value in CustomEmojiManager-SizeFromTag."); } -[[nodiscard]] QString SerializeCustomEmojiId(const CustomEmojiId &id) { - return QString::number(id.id) - + '@' - + QString::number(id.set.id) - + ':' - + QString::number(id.set.accessHash); -} - -[[nodiscard]] QString SerializeCustomEmojiId( - not_null document) { - const auto sticker = document->sticker(); - return SerializeCustomEmojiId({ - sticker ? sticker->set : StickerSetIdentifier(), - document->id, - }); -} - -[[nodiscard]] CustomEmojiId ParseCustomEmojiData(QStringView data) { - const auto parts = data.split('@'); - if (parts.size() != 2) { - return {}; - } - const auto id = parts[0].toULongLong(); - if (!id) { - return {}; - } - const auto second = parts[1].split(':'); - return { - .set = { - .id = second[0].toULongLong(), - .accessHash = second[1].toULongLong(), - }, - .id = id - }; -} - } // namespace class CustomEmojiLoader final @@ -392,7 +349,7 @@ CustomEmojiManager::CustomEmojiManager(not_null owner) CustomEmojiManager::~CustomEmojiManager() = default; std::unique_ptr CustomEmojiManager::create( - const QString &data, + QStringView data, Fn update) { const auto parsed = ParseCustomEmojiData(data); if (!parsed.id || !parsed.set.id) { @@ -547,56 +504,46 @@ Session &CustomEmojiManager::owner() const { return *_owner; } -void FillTestCustomEmoji( - not_null session, - TextWithEntities &text) { - auto &sets = session->data().stickers().sets(); - auto recentIt = sets.find(Data::Stickers::CloudRecentSetId); - const auto pack = &session->emojiStickersPack(); - const auto begin = text.text.constData(), end = begin + text.text.size(); - for (auto ch = begin; ch != end;) { - auto length = 0; - if (const auto emoji = Ui::Emoji::Find(ch, end, &length)) { - auto replace = (DocumentData*)nullptr; - if (recentIt != sets.end()) { - for (const auto document : recentIt->second->stickers) { - if (const auto sticker = document->sticker()) { - if (Ui::Emoji::Find(sticker->alt) == emoji) { - replace = document; - } - } - } - } - if (const auto found = pack->stickerForEmoji(emoji)) { - Assert(found.document->sticker() != nullptr); - if (!replace && found.document->sticker()->set.id) { - replace = found.document; - } - } - if (replace) { - text.entities.push_back({ - EntityType::CustomEmoji, - (ch - begin), - length, - SerializeCustomEmojiId({ - replace->sticker()->set, - replace->id, - }), - }); - } - ch += length; - } else if (ch->isHighSurrogate() - && (ch + 1 != end) - && (ch + 1)->isLowSurrogate()) { - ch += 2; - } else { - ++ch; - } +QString SerializeCustomEmojiId(const CustomEmojiId &id) { + return QString::number(id.set.id) + + '.' + + QString::number(id.set.accessHash) + + ':' + + QString::number(id.selfId) + + '/' + + QString::number(id.id); +} + +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('.'); + if (components.size() != 2) { + return {}; } - ranges::stable_sort( - text.entities, - ranges::less(), - &EntityInText::offset); + 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(), + }, + }; } } // namespace Data diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.h b/Telegram/SourceFiles/data/stickers/data_custom_emoji.h index 9b8bcbde41..3a58a09def 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.h +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "data/stickers/data_stickers_set.h" #include "ui/text/custom_emoji_instance.h" #include "base/timer.h" #include "base/weak_ptr.h" @@ -20,9 +21,14 @@ class Session; namespace Data { class Session; -struct CustomEmojiId; class CustomEmojiLoader; +struct CustomEmojiId { + uint64 selfId = 0; + uint64 id = 0; + StickerSetIdentifier set; +}; + class CustomEmojiManager final : public base::has_weak_ptr { public: enum class SizeTag { @@ -34,7 +40,7 @@ public: ~CustomEmojiManager(); [[nodiscard]] std::unique_ptr create( - const QString &data, + QStringView data, Fn update); [[nodiscard]] Main::Session &session() const; @@ -76,8 +82,9 @@ private: }; -void FillTestCustomEmoji( - not_null session, - TextWithEntities &text); +[[nodiscard]] QString SerializeCustomEmojiId(const CustomEmojiId &id); +[[nodiscard]] QString SerializeCustomEmojiId( + not_null document); +[[nodiscard]] CustomEmojiId ParseCustomEmojiData(QStringView data); } // namespace Data diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp index 62ab448030..b4894c1bdf 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.cpp +++ b/Telegram/SourceFiles/export/data/export_data_types.cpp @@ -155,7 +155,8 @@ std::vector ParseText( [](const MTPDmessageEntityBlockquote&) { return Type::Blockquote; }, [](const MTPDmessageEntityBankCard&) { return Type::BankCard; }, - [](const MTPDmessageEntitySpoiler&) { return Type::Spoiler; }); + [](const MTPDmessageEntitySpoiler&) { return Type::Spoiler; }, + [](const MTPDmessageEntityCustomEmoji&) { return Type::CustomEmoji; }); part.text = mid(start, length); part.additional = entity.match( [](const MTPDmessageEntityPre &data) { @@ -164,6 +165,8 @@ std::vector ParseText( return ParseString(data.vurl()); }, [](const MTPDmessageEntityMentionName &data) { return NumberToString(data.vuser_id().v); + }, [](const MTPDmessageEntityCustomEmoji &data) { + return NumberToString(data.vdocument_id().v); }, [](const auto &) { return Utf8String(); }); result.push_back(std::move(part)); diff --git a/Telegram/SourceFiles/export/data/export_data_types.h b/Telegram/SourceFiles/export/data/export_data_types.h index 3fba59a821..1bbdba19ae 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.h +++ b/Telegram/SourceFiles/export/data/export_data_types.h @@ -549,6 +549,7 @@ struct TextPart { Blockquote, BankCard, Spoiler, + CustomEmoji, }; Type type = Type::Text; Utf8String text; diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp index 4503926dcd..49cdedc46d 100644 --- a/Telegram/SourceFiles/export/output/export_output_html.cpp +++ b/Telegram/SourceFiles/export/output/export_output_html.cpp @@ -274,6 +274,9 @@ QByteArray FormatText( "onclick=\"ShowSpoiler(this)\">" "" + text + ""; + case Type::CustomEmoji: return SerializeString("{custom_emoji}") + + text // TODO custom-emoji + + SerializeString("{/custom_emoji}"); } Unexpected("Type in text entities serialization."); }) | ranges::to_vector); diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp index 62baaf4c74..a529a018f3 100644 --- a/Telegram/SourceFiles/export/output/export_output_json.cpp +++ b/Telegram/SourceFiles/export/output/export_output_json.cpp @@ -181,17 +181,21 @@ QByteArray SerializeText( case Type::Blockquote: return "blockquote"; case Type::BankCard: return "bank_card"; case Type::Spoiler: return "spoiler"; + case Type::CustomEmoji: return "custom_emoji"; } Unexpected("Type in SerializeText."); }(); const auto additionalName = (part.type == Type::MentionName) ? "user_id" + : (part.type == Type::CustomEmoji) + ? "document_id" : (part.type == Type::Pre) ? "language" : (part.type == Type::TextUrl) ? "href" : "none"; - const auto additionalValue = (part.type == Type::MentionName) + const auto additionalValue = (part.type == Type::MentionName + || part.type == Type::CustomEmoji) ? part.additional : (part.type == Type::Pre || part.type == Type::TextUrl) ? SerializeString(part.additional) diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 7b4f894093..3bec4519f9 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -337,7 +337,6 @@ HistoryMessage::HistoryMessage( &history->session(), data.ventities().value_or_empty()) }; - Data::FillTestCustomEmoji(&history->session(), textWithEntities); setText(_media ? textWithEntities : EnsureNonEmpty(textWithEntities)); if (const auto groupedId = data.vgrouped_id()) { setGroupId( diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_loader.h b/Telegram/SourceFiles/media/streaming/media_streaming_loader.h index 2ee08f9302..55845c5200 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_loader.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_loader.h @@ -25,7 +25,7 @@ struct LoadedPart { class Loader { public: - static constexpr auto kPartSize = 128 * 1024; + static constexpr auto kPartSize = int64(128 * 1024); [[nodiscard]] virtual Storage::Cache::Key baseCacheKey() const = 0; [[nodiscard]] virtual int64 size() const = 0; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_reader.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_reader.cpp index 44c163f085..d2b8b2157c 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_reader.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_reader.cpp @@ -127,7 +127,7 @@ bytes::const_span ParseCachedMap( if (size > maxSize) { return {}; } - for (auto offset = 0; offset < size; offset += kPartSize) { + for (auto offset = int64(); offset < size; offset += kPartSize) { const auto part = data.subspan( offset, std::min(kPartSize, size - offset)); diff --git a/Telegram/SourceFiles/storage/streamed_file_downloader.cpp b/Telegram/SourceFiles/storage/streamed_file_downloader.cpp index 71b9016799..97c3c49697 100644 --- a/Telegram/SourceFiles/storage/streamed_file_downloader.cpp +++ b/Telegram/SourceFiles/storage/streamed_file_downloader.cpp @@ -107,7 +107,7 @@ void StreamedFileDownloader::requestPart() { ++_partsRequested; } -QByteArray StreamedFileDownloader::readLoadedPart(int offset) { +QByteArray StreamedFileDownloader::readLoadedPart(int64 offset) { Expects(offset >= 0 && offset < _fullSize); Expects(!(offset % kPartSize)); diff --git a/Telegram/SourceFiles/storage/streamed_file_downloader.h b/Telegram/SourceFiles/storage/streamed_file_downloader.h index 4dd2e9b129..5b3b7fdee4 100644 --- a/Telegram/SourceFiles/storage/streamed_file_downloader.h +++ b/Telegram/SourceFiles/storage/streamed_file_downloader.h @@ -45,7 +45,7 @@ public: uint64 objId() const override; Data::FileOrigin fileOrigin() const override; - QByteArray readLoadedPart(int offset); + QByteArray readLoadedPart(int64 offset); private: void startLoading() override; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 32cf0968a1..6bd7518109 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 32cf0968a14f7ef7756834f72500fc58fef50c6d +Subproject commit 6bd7518109850d650a174b74e5582367555390da