diff --git a/Telegram/Resources/tl/api.tl b/Telegram/Resources/tl/api.tl index 97961c1ae..4d0e1a92e 100644 --- a/Telegram/Resources/tl/api.tl +++ b/Telegram/Resources/tl/api.tl @@ -323,7 +323,7 @@ updateDeleteChannelMessages#c32d5b12 channel_id:long messages:Vector pts:in updateChannelMessageViews#f226ac08 channel_id:long id:int views:int = Update; updateChatParticipantAdmin#d7ca61a2 chat_id:long user_id:long is_admin:Bool version:int = Update; updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; -updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector = Update; +updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Update; updateStickerSets#43ae3dec = Update; updateSavedGifs#9375341e = Update; updateBotInlineQuery#496f379c flags:# query_id:long user_id:long query:string geo:flags.0?GeoPoint peer_type:flags.1?InlineQueryPeerType offset:string = Update; @@ -533,6 +533,7 @@ documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true supports_strea documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeHasStickers#9801d2f7 = DocumentAttribute; +documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true alt:string stickerset:InputStickerSet = DocumentAttribute; messages.stickersNotModified#f1749a22 = messages.Stickers; messages.stickers#30a6ec7e hash:long stickers:Vector = messages.Stickers; @@ -577,7 +578,7 @@ inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; -stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int count:int hash:int = StickerSet; +stickerSet#d7df217a flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true videos:flags.6?true emojis:flags.7?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; messages.stickerSetNotModified#d3f924eb = messages.StickerSet; @@ -1575,7 +1576,7 @@ messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector increment:Bool messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool; messages.migrateChat#a2875319 chat_id:long = Updates; messages.searchGlobal#4bc6589a flags:# folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; -messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector = Bool; +messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Bool; messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document; messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs; messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; @@ -1595,7 +1596,7 @@ messages.readFeaturedStickers#5b118126 id:Vector = Bool; messages.getRecentStickers#9da9403b flags:# attached:flags.0?true hash:long = messages.RecentStickers; messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; -messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers; +messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true emojis:flags.1?true offset_id:long limit:int = messages.ArchivedStickers; messages.getMaskStickers#640f82b8 hash:long = messages.AllStickers; messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; @@ -1697,6 +1698,7 @@ messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:strin 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; +messages.getEmojiStickers#fbfca18f hash:long = messages.AllStickers; updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; @@ -1805,7 +1807,7 @@ payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStor payments.canPurchasePremium#aa6a90c8 = Bool; payments.requestRecurringPayment#146e958d user_id:InputUser recurring_init_charge:string invoice_media:InputMedia = Updates; -stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true animated:flags.1?true videos:flags.4?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; +stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true animated:flags.1?true videos:flags.4?true emojis:flags.5?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; diff --git a/Telegram/SourceFiles/api/api_hash.cpp b/Telegram/SourceFiles/api/api_hash.cpp index be5f9277c..3c43ee5cf 100644 --- a/Telegram/SourceFiles/api/api_hash.cpp +++ b/Telegram/SourceFiles/api/api_hash.cpp @@ -80,6 +80,15 @@ uint64 CountMasksHash( checkOutdatedInfo); } +uint64 CountCustomEmojiHash( + not_null session, + bool checkOutdatedInfo) { + return CountStickersOrderHash( + session, + session->data().stickers().emojiSetsOrder(), + checkOutdatedInfo); +} + uint64 CountRecentStickersHash( not_null session, bool attached) { diff --git a/Telegram/SourceFiles/api/api_hash.h b/Telegram/SourceFiles/api/api_hash.h index 81c9902a2..efd96d874 100644 --- a/Telegram/SourceFiles/api/api_hash.h +++ b/Telegram/SourceFiles/api/api_hash.h @@ -19,6 +19,9 @@ namespace Api { [[nodiscard]] uint64 CountMasksHash( not_null session, bool checkOutdatedInfo = false); +[[nodiscard]] uint64 CountCustomEmojiHash( + not_null session, + bool checkOutdatedInfo = false); [[nodiscard]] uint64 CountRecentStickersHash( not_null session, bool attached = false); diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 9cb3b2bf0..dfb2f0ccb 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -2298,6 +2298,7 @@ void Updates::feedUpdate(const MTPUpdate &update) { case mtpc_updateStickerSetsOrder: { auto &d = update.c_updateStickerSetsOrder(); auto &stickers = session().data().stickers(); + const auto isEmoji = d.is_emojis(); const auto isMasks = d.is_masks(); const auto &order = d.vorder().v; const auto &sets = stickers.sets(); @@ -2308,11 +2309,16 @@ void Updates::feedUpdate(const MTPUpdate &update) { } result.push_back(item.v); } - const auto localSize = isMasks + const auto localSize = isEmoji + ? stickers.emojiSetsOrder().size() + : isMasks ? stickers.maskSetsOrder().size() : stickers.setsOrder().size(); if ((result.size() != localSize) || (result.size() != order.size())) { - if (isMasks) { + if (isEmoji) { + stickers.setLastEmojiUpdate(0); + session().api().updateCustomEmoji(); + } else if (isMasks) { stickers.setLastMasksUpdate(0); session().api().updateMasks(); } else { @@ -2320,7 +2326,10 @@ void Updates::feedUpdate(const MTPUpdate &update) { session().api().updateStickers(); } } else { - if (isMasks) { + if (isEmoji) { + stickers.emojiSetsOrderRef() = std::move(result); + session().local().writeInstalledCustomEmoji(); + } else if (isMasks) { stickers.maskSetsOrderRef() = std::move(result); session().local().writeInstalledMasks(); } else { diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 77329cf08..635cb67ec 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -1419,12 +1419,16 @@ void ApiWrap::requestStickerSets() { void ApiWrap::saveStickerSets( const Data::StickersSetsOrder &localOrder, const Data::StickersSetsOrder &localRemoved, - bool setsMasks) { - auto &setDisenableRequests = setsMasks + Data::StickersType type) { + auto &setDisenableRequests = (type == Data::StickersType::Emoji) + ? _customEmojiSetDisenableRequests + : (type == Data::StickersType::Masks) ? _maskSetDisenableRequests : _stickerSetDisenableRequests; const auto reorderRequestId = [=]() -> mtpRequestId & { - return setsMasks + return (type == Data::StickersType::Emoji) + ? _customEmojiReorderRequestId + : (type == Data::StickersType::Masks) ? _masksReorderRequestId : _stickersReorderRequestId; }; @@ -1445,9 +1449,12 @@ void ApiWrap::saveStickerSets( mtpOrder.push_back(MTP_long(setId)); } - const auto flags = setsMasks - ? MTPmessages_ReorderStickerSets::Flag::f_masks - : MTPmessages_ReorderStickerSets::Flags(0); + using Flag = MTPmessages_ReorderStickerSets::Flag; + const auto flags = (type == Data::StickersType::Emoji) + ? Flag::f_emojis + : (type == Data::StickersType::Masks) + ? Flag::f_masks + : Flag(0); reorderRequestId() = request(MTPmessages_ReorderStickerSets( MTP_flags(flags), MTP_vector(mtpOrder) @@ -1455,7 +1462,10 @@ void ApiWrap::saveStickerSets( reorderRequestId() = 0; }).fail([=] { reorderRequestId() = 0; - if (setsMasks) { + if (type == Data::StickersType::Emoji) { + _session->data().stickers().setLastEmojiUpdate(0); + updateCustomEmoji(); + } else if (type == Data::StickersType::Masks) { _session->data().stickers().setLastMasksUpdate(0); updateMasks(); } else { @@ -1466,7 +1476,9 @@ void ApiWrap::saveStickerSets( }; const auto stickerSetDisenabled = [=](mtpRequestId requestId) { - auto &setDisenableRequests = setsMasks + auto &setDisenableRequests = (type == Data::StickersType::Emoji) + ? _customEmojiSetDisenableRequests + : (type == Data::StickersType::Masks) ? _maskSetDisenableRequests : _stickerSetDisenableRequests; setDisenableRequests.remove(requestId); @@ -1484,10 +1496,14 @@ void ApiWrap::saveStickerSets( auto &recent = _session->data().stickers().getRecentPack(); auto &sets = _session->data().stickers().setsRef(); - auto &order = setsMasks + auto &order = (type == Data::StickersType::Emoji) + ? _session->data().stickers().emojiSetsOrder() + : (type == Data::StickersType::Masks) ? _session->data().stickers().maskSetsOrder() : _session->data().stickers().setsOrder(); - auto &orderRef = setsMasks + auto &orderRef = (type == Data::StickersType::Emoji) + ? _session->data().stickers().emojiSetsOrderRef() + : (type == Data::StickersType::Masks) ? _session->data().stickers().maskSetsOrderRef() : _session->data().stickers().setsOrderRef(); @@ -1575,8 +1591,12 @@ void ApiWrap::saveStickerSets( // Clear all installed flags, set only for sets from order. for (auto &[id, set] : sets) { const auto archived = !!(set->flags & Flag::Archived); - const auto masks = !!(set->flags & Flag::Masks); - if (!archived && (setsMasks == masks)) { + const auto thatType = !!(set->flags & Flag::Emoji) + ? Data::StickersType::Emoji + : !!(set->flags & Flag::Masks) + ? Data::StickersType::Masks + : Data::StickersType::Stickers; + if (!archived && (type == thatType)) { set->flags &= ~Flag::Installed; } } @@ -1630,17 +1650,21 @@ void ApiWrap::saveStickerSets( } auto &storage = local(); - if (writeInstalled && !setsMasks) { - storage.writeInstalledStickers(); - } - if (writeInstalled && setsMasks) { - storage.writeInstalledMasks(); + if (writeInstalled) { + if (type == Data::StickersType::Emoji) { + storage.writeInstalledCustomEmoji(); + } else if (type == Data::StickersType::Masks) { + storage.writeInstalledMasks(); + } else { + storage.writeInstalledStickers(); + } } if (writeRecent) { session().saveSettings(); } if (writeArchived) { - if (setsMasks) { + if (type == Data::StickersType::Emoji) { + } else if (type == Data::StickersType::Masks) { storage.writeArchivedMasks(); } else { storage.writeArchivedStickers(); @@ -2511,6 +2535,11 @@ void ApiWrap::updateMasks() { requestRecentStickers(now, true); } +void ApiWrap::updateCustomEmoji() { + const auto now = crl::now(); + requestCustomEmoji(now); +} + void ApiWrap::requestRecentStickersForce(bool attached) { requestRecentStickersWithHash(0, attached); } @@ -2624,6 +2653,30 @@ void ApiWrap::requestMasks(TimeId now) { }).send(); } +void ApiWrap::requestCustomEmoji(TimeId now) { + if (!_session->data().stickers().emojiUpdateNeeded(now) + || _customEmojiUpdateRequest) { + return; + } + const auto done = [=](const MTPmessages_AllStickers &result) { + _session->data().stickers().setLastMasksUpdate(crl::now()); + _masksUpdateRequest = 0; + + result.match([&](const MTPDmessages_allStickersNotModified&) { + }, [&](const MTPDmessages_allStickers &data) { + _session->data().stickers().masksReceived( + data.vsets().v, + data.vhash().v); + }); + }; + _masksUpdateRequest = request(MTPmessages_GetEmojiStickers( + MTP_long(Api::CountCustomEmojiHash(_session, true)) + )).done(done).fail([=] { + LOG(("App Fail: Failed to get custom emoji!")); + done(MTP_messages_allStickersNotModified()); + }).send(); +} + void ApiWrap::requestRecentStickers(TimeId now, bool attached) { const auto needed = attached ? _session->data().stickers().recentAttachedUpdateNeeded(now) diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index be4b9f1c4..1f87488ff 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -31,6 +31,7 @@ struct UpdatedFileReferences; class WallPaper; struct ResolvedForwardDraft; enum class DefaultNotify; +enum class StickersType : uchar; } // namespace Data namespace InlineBots { @@ -229,9 +230,10 @@ public: void saveStickerSets( const Data::StickersSetsOrder &localOrder, const Data::StickersSetsOrder &localRemoved, - bool setsMasks); + Data::StickersType type); void updateStickers(); void updateMasks(); + void updateCustomEmoji(); void requestRecentStickersForce(bool attached = false); void setGroupStickerSet( not_null megagroup, @@ -435,6 +437,7 @@ private: void requestStickers(TimeId now); void requestMasks(TimeId now); + void requestCustomEmoji(TimeId now); void requestRecentStickers(TimeId now, bool attached = false); void requestRecentStickersWithHash(uint64 hash, bool attached = false); void requestFavedStickers(TimeId now); @@ -541,13 +544,16 @@ private: base::flat_set _stickerSetDisenableRequests; base::flat_set _maskSetDisenableRequests; + base::flat_set _customEmojiSetDisenableRequests; mtpRequestId _masksReorderRequestId = 0; + mtpRequestId _customEmojiReorderRequestId = 0; mtpRequestId _stickersReorderRequestId = 0; mtpRequestId _stickersClearRecentRequestId = 0; mtpRequestId _stickersClearRecentAttachedRequestId = 0; mtpRequestId _stickersUpdateRequest = 0; mtpRequestId _masksUpdateRequest = 0; + mtpRequestId _customEmojiUpdateRequest = 0; mtpRequestId _recentStickersUpdateRequest = 0; mtpRequestId _recentAttachedStickersUpdateRequest = 0; mtpRequestId _favedStickersUpdateRequest = 0; diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index d58dea06d..376918eaa 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -76,6 +76,19 @@ QString JoinStringList(const QStringList &list, const QString &separator) { return result; } +void UpdateStickerSetIdentifier( + StickerSetIdentifier &now, + const MTPInputStickerSet &from) { + now = from.match([&](const MTPDinputStickerSetID &data) { + return StickerSetIdentifier{ + .id = data.vid().v, + .accessHash = data.vaccess_hash().v, + }; + }, [](const auto &) { + return StickerSetIdentifier(); + }); +} + } // namespace QString FileNameUnsafe( @@ -334,26 +347,33 @@ void DocumentData::setattributes( _additional = std::make_unique(); } if (const auto info = sticker()) { + info->setType = data.is_mask() + ? Data::StickersType::Masks + : Data::StickersType::Stickers; if (was == VideoDocument) { info->type = StickerType::Webm; } info->alt = qs(data.valt()); - if (!info->set.id - || data.vstickerset().type() == mtpc_inputStickerSetID) { - info->set = data.vstickerset().match([&]( - const MTPDinputStickerSetID &data) { - return StickerSetIdentifier{ - .id = data.vid().v, - .accessHash = data.vaccess_hash().v, - }; - }, [&](const MTPDinputStickerSetShortName &data) { - return StickerSetIdentifier{ - .shortName = qs(data.vshort_name()), - }; - }, [](const auto &) { - return StickerSetIdentifier(); - }); + UpdateStickerSetIdentifier(info->set, data.vstickerset()); + } + }, [&](const MTPDdocumentAttributeCustomEmoji &data) { + const auto was = type; + if (type == FileDocument || type == VideoDocument) { + type = StickerDocument; + _additional = std::make_unique(); + } + if (const auto info = sticker()) { + info->setType = Data::StickersType::Emoji; + if (was == VideoDocument) { + info->type = StickerType::Webm; } + info->alt = qs(data.valt()); + if (data.is_free()) { + _flags &= ~Flag::PremiumSticker; + } else { + _flags |= Flag::PremiumSticker; + } + UpdateStickerSetIdentifier(info->set, data.vstickerset()); } }, [&](const MTPDdocumentAttributeVideo &data) { if (type == FileDocument) { @@ -476,10 +496,12 @@ void DocumentData::updateThumbnails( _flags &= ~Flag::InlineThumbnailIsPath; } } - if (isPremiumSticker) { - _flags |= Flag::PremiumSticker; - } else { - _flags &= ~Flag::PremiumSticker; + if (!sticker() || sticker()->setType != Data::StickersType::Emoji) { + if (isPremiumSticker) { + _flags |= Flag::PremiumSticker; + } else { + _flags &= ~Flag::PremiumSticker; + } } Data::UpdateCloudFile( _thumbnail, @@ -518,7 +540,19 @@ bool DocumentData::isPatternWallPaperSVG() const { } bool DocumentData::isPremiumSticker() const { - return (_flags & Flag::PremiumSticker); + if (!(_flags & Flag::PremiumSticker)) { + return false; + } + const auto info = sticker(); + return info && info->setType == Data::StickersType::Stickers; +} + +bool DocumentData::isPremiumEmoji() const { + if (!(_flags & Flag::PremiumSticker)) { + return false; + } + const auto info = sticker(); + return info && info->setType == Data::StickersType::Emoji; } bool DocumentData::hasThumbnail() const { @@ -1120,15 +1154,6 @@ bool DocumentData::isStickerSetInstalled() const { return (i != sets.cend()) && !(i->second->flags & SetFlag::Archived) && (i->second->flags & SetFlag::Installed); - } else if (!sticker()->set.shortName.isEmpty()) { - const auto name = sticker()->set.shortName.toLower(); - for (const auto &[id, set] : sets) { - if (set->shortName.toLower() == name) { - return !(set->flags & SetFlag::Archived) - && (set->flags & SetFlag::Installed); - } - } - return false; } else { return false; } diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index dcfa84b7f..3af5f7616 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -36,6 +36,7 @@ namespace Data { class Session; class DocumentMedia; class ReplyPreview; +enum class StickersType : uchar; } // namespace Data namespace Main { @@ -73,6 +74,7 @@ struct StickerData : public DocumentAdditionalData { QString alt; StickerSetIdentifier set; StickerType type = StickerType::Webp; + Data::StickersType setType = Data::StickersType(); }; struct SongData : public DocumentAdditionalData { @@ -174,6 +176,7 @@ public: [[nodiscard]] bool isPatternWallPaperPNG() const; [[nodiscard]] bool isPatternWallPaperSVG() const; [[nodiscard]] bool isPremiumSticker() const; + [[nodiscard]] bool isPremiumEmoji() const; [[nodiscard]] bool hasThumbnail() const; [[nodiscard]] bool thumbnailLoading() const; diff --git a/Telegram/SourceFiles/data/stickers/data_stickers.cpp b/Telegram/SourceFiles/data/stickers/data_stickers.cpp index b9dc3c694..eb56ccda1 100644 --- a/Telegram/SourceFiles/data/stickers/data_stickers.cpp +++ b/Telegram/SourceFiles/data/stickers/data_stickers.cpp @@ -1458,7 +1458,11 @@ void Stickers::newSetReceived(const MTPDmessages_stickerSet &set) { "updateNewStickerSet with archived flag.")); return; } - auto &order = s.is_masks() ? maskSetsOrderRef() : setsOrderRef(); + auto &order = s.is_emojis() + ? emojiSetsOrderRef() + : s.is_masks() + ? maskSetsOrderRef() + : setsOrderRef(); int32 insertAtIndex = 0, currentIndex = order.indexOf(s.vid().v); if (currentIndex != insertAtIndex) { if (currentIndex > 0) { diff --git a/Telegram/SourceFiles/data/stickers/data_stickers.h b/Telegram/SourceFiles/data/stickers/data_stickers.h index f484818eb..133a0aeae 100644 --- a/Telegram/SourceFiles/data/stickers/data_stickers.h +++ b/Telegram/SourceFiles/data/stickers/data_stickers.h @@ -27,6 +27,12 @@ namespace Data { class Session; class DocumentMedia; +enum class StickersType : uchar { + Stickers, + Masks, + Emoji, +}; + class Stickers final { public: explicit Stickers(not_null owner); @@ -91,6 +97,12 @@ public: void setLastMasksUpdate(crl::time update) { _lastMasksUpdate = update; } + bool emojiUpdateNeeded(crl::time now) const { + return updateNeeded(_lastEmojiUpdate, now); + } + void setLastEmojiUpdate(crl::time update) { + _lastEmojiUpdate = update; + } bool recentAttachedUpdateNeeded(crl::time now) const { return updateNeeded(_lastRecentAttachedUpdate, now); } @@ -145,6 +157,12 @@ public: StickersSetsOrder &maskSetsOrderRef() { return _maskSetsOrder; } + const StickersSetsOrder &emojiSetsOrder() const { + return _emojiSetsOrder; + } + StickersSetsOrder &emojiSetsOrderRef() { + return _emojiSetsOrder; + } const StickersSetsOrder &featuredSetsOrder() const { return _featuredSetsOrder; } @@ -188,6 +206,7 @@ public: void setsReceived(const QVector &data, uint64 hash); void masksReceived(const QVector &data, uint64 hash); + void emojiReceived(const QVector &data, uint64 hash); void specialSetReceived( uint64 setId, const QString &setTitle, @@ -244,10 +263,10 @@ private: StickersPack &&pack, const std::vector &&dates, const QVector &packs); - void setsOrMasksReceived( + void setsOrMasksOrEmojiReceived( const QVector &data, uint64 hash, - bool masks); + StickersType type); const not_null _owner; rpl::event_stream<> _updated; @@ -260,11 +279,13 @@ private: crl::time _lastFeaturedUpdate = 0; crl::time _lastSavedGifsUpdate = 0; crl::time _lastMasksUpdate = 0; + crl::time _lastEmojiUpdate = 0; crl::time _lastRecentAttachedUpdate = 0; rpl::variable _featuredSetsUnreadCount = 0; StickersSets _sets; StickersSetsOrder _setsOrder; StickersSetsOrder _maskSetsOrder; + StickersSetsOrder _emojiSetsOrder; StickersSetsOrder _featuredSetsOrder; StickersSetsOrder _archivedSetsOrder; StickersSetsOrder _archivedMaskSetsOrder; diff --git a/Telegram/SourceFiles/data/stickers/data_stickers_set.cpp b/Telegram/SourceFiles/data/stickers/data_stickers_set.cpp index cef854711..3e54047d2 100644 --- a/Telegram/SourceFiles/data/stickers/data_stickers_set.cpp +++ b/Telegram/SourceFiles/data/stickers/data_stickers_set.cpp @@ -49,6 +49,7 @@ StickersSetFlags ParseStickersSetFlags(const MTPDstickerSet &data) { return (data.is_archived() ? Flag::Archived : Flag()) | (data.is_official() ? Flag::Official : Flag()) | (data.is_masks() ? Flag::Masks : Flag()) + | (data.is_emojis() ? Flag::Emoji : Flag()) | (data.vinstalled_date() ? Flag::Installed : Flag()) | (data.is_videos() ? Flag::Webm : Flag()); } diff --git a/Telegram/SourceFiles/data/stickers/data_stickers_set.h b/Telegram/SourceFiles/data/stickers/data_stickers_set.h index 01ecbf581..66de1ea3b 100644 --- a/Telegram/SourceFiles/data/stickers/data_stickers_set.h +++ b/Telegram/SourceFiles/data/stickers/data_stickers_set.h @@ -55,6 +55,7 @@ enum class StickersSetFlag { Unread = (1 << 6), Special = (1 << 7), Webm = (1 << 8), + Emoji = (1 << 9), }; inline constexpr bool is_flag_type(StickersSetFlag) { return true; }; using StickersSetFlags = base::flags; diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp index ef4f44aba..29a9daed0 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.cpp +++ b/Telegram/SourceFiles/export/data/export_data_types.cpp @@ -284,6 +284,9 @@ void ParseAttributes( }, [&](const MTPDdocumentAttributeSticker &data) { result.isSticker = true; result.stickerEmoji = ParseString(data.valt()); + }, [&](const MTPDdocumentAttributeCustomEmoji &data) { + result.isSticker = true; + result.stickerEmoji = ParseString(data.valt()); }, [&](const MTPDdocumentAttributeVideo &data) { if (data.is_round_message()) { result.isVideoMessage = true; diff --git a/Telegram/SourceFiles/storage/serialize_document.cpp b/Telegram/SourceFiles/storage/serialize_document.cpp index 3eb74d3cb..47ae3f9dd 100644 --- a/Telegram/SourceFiles/storage/serialize_document.cpp +++ b/Telegram/SourceFiles/storage/serialize_document.cpp @@ -24,6 +24,8 @@ enum StickerSetType { StickerSetTypeEmpty = 0, StickerSetTypeID = 1, StickerSetTypeShortName = 2, + StickerSetTypeEmoji = 3, + StickerSetTypeMasks = 4, }; } // namespace @@ -45,11 +47,13 @@ void Document::writeToStream(QDataStream &stream, DocumentData *document) { << qint32(document->dimensions.height()) << qint32(document->type); if (const auto sticker = document->sticker()) { - stream << document->sticker()->alt; - if (document->sticker()->set.id) { + stream << sticker->alt; + if (sticker->setType == Data::StickersType::Emoji) { + stream << qint32(StickerSetTypeEmoji); + } else if (sticker->setType == Data::StickersType::Masks) { + stream << qint32(StickerSetTypeMasks); + } else if (sticker->set.id) { stream << qint32(StickerSetTypeID); - } else if (!document->sticker()->set.shortName.isEmpty()) { - stream << qint32(StickerSetTypeShortName); } else { stream << qint32(StickerSetTypeEmpty); } @@ -109,6 +113,12 @@ DocumentData *Document::readFromStreamHelper( QString alt; qint32 typeOfSet; stream >> alt >> typeOfSet; + if (version >= 3) { + stream >> duration; + if (version >= 4) { + stream >> isPremiumSticker; + } + } if (typeOfSet == StickerSetTypeEmpty) { attributes.push_back(MTP_documentAttributeSticker(MTP_flags(0), MTP_string(alt), MTP_inputStickerSetEmpty(), MTPMaskCoords())); } else if (info) { @@ -124,8 +134,18 @@ DocumentData *Document::readFromStreamHelper( case StickerSetTypeID: { attributes.push_back(MTP_documentAttributeSticker(MTP_flags(0), MTP_string(alt), MTP_inputStickerSetID(MTP_long(info->setId), MTP_long(info->accessHash)), MTPMaskCoords())); } break; - case StickerSetTypeShortName: { - attributes.push_back(MTP_documentAttributeSticker(MTP_flags(0), MTP_string(alt), MTP_inputStickerSetShortName(MTP_string(info->shortName)), MTPMaskCoords())); + case StickerSetTypeMasks: { + attributes.push_back(MTP_documentAttributeSticker(MTP_flags(MTPDdocumentAttributeSticker::Flag::f_mask), MTP_string(alt), MTP_inputStickerSetID(MTP_long(info->setId), MTP_long(info->accessHash)), MTPMaskCoords())); + } break; + case StickerSetTypeEmoji: { + using Flag = MTPDdocumentAttributeCustomEmoji::Flag; + attributes.push_back(MTP_documentAttributeCustomEmoji( + MTP_flags(isPremiumSticker ? Flag(0) : Flag::f_free), + MTP_string(alt), + MTP_inputStickerSetID( + MTP_long(info->setId), + MTP_long(info->accessHash)), + MTPMaskCoords())); } break; case StickerSetTypeEmpty: default: { @@ -133,12 +153,6 @@ DocumentData *Document::readFromStreamHelper( } break; } } - if (version >= 3) { - stream >> duration; - if (version >= 4) { - stream >> isPremiumSticker; - } - } } else { stream >> duration; if (type == AnimatedDocument) { diff --git a/Telegram/SourceFiles/storage/storage_account.h b/Telegram/SourceFiles/storage/storage_account.h index a99beda6b..e67cf53c3 100644 --- a/Telegram/SourceFiles/storage/storage_account.h +++ b/Telegram/SourceFiles/storage/storage_account.h @@ -135,6 +135,8 @@ public: void writeRecentMasks(); void readInstalledMasks(); void readRecentMasks(); + void writeInstalledCustomEmoji(); + void readInstalledCustomEmoji(); void writeRecentHashtagsAndBots(); void readRecentHashtagsAndBots(); diff --git a/Telegram/SourceFiles/ui/effects/premium_stars.cpp b/Telegram/SourceFiles/ui/effects/premium_stars.cpp index ff5c20e75..7593d3222 100644 --- a/Telegram/SourceFiles/ui/effects/premium_stars.cpp +++ b/Telegram/SourceFiles/ui/effects/premium_stars.cpp @@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/random.h" #include "ui/effects/animation_value_f.h" +#include + namespace Ui { namespace Premium {