From b4b55973b5d7a8ca29d995a1332613bb89aec5ef Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 22 Jul 2022 16:08:10 +0300 Subject: [PATCH] Request and cache featured emoji sets. --- Telegram/SourceFiles/api/api_hash.cpp | 37 +++++--- Telegram/SourceFiles/api/api_hash.h | 5 +- Telegram/SourceFiles/apiwrap.cpp | 36 +++++--- Telegram/SourceFiles/apiwrap.h | 2 + .../chat_helpers/emoji_list_widget.cpp | 13 ++- .../data/stickers/data_stickers.cpp | 91 ++++++++++++++----- .../SourceFiles/data/stickers/data_stickers.h | 24 ++++- Telegram/SourceFiles/main/main_session.cpp | 1 + .../SourceFiles/storage/storage_account.cpp | 42 +++++++-- .../SourceFiles/storage/storage_account.h | 4 +- 10 files changed, 185 insertions(+), 70 deletions(-) diff --git a/Telegram/SourceFiles/api/api_hash.cpp b/Telegram/SourceFiles/api/api_hash.cpp index 3c43ee5cfe..15aca8e296 100644 --- a/Telegram/SourceFiles/api/api_hash.cpp +++ b/Telegram/SourceFiles/api/api_hash.cpp @@ -60,6 +60,23 @@ namespace { : 0; } +[[nodiscard]] uint64 CountFeaturedHash( + not_null session, + const Data::StickersSetsOrder &order) { + auto result = HashInit(); + const auto &sets = session->data().stickers().sets(); + for (const auto setId : order) { + HashUpdate(result, setId); + + const auto it = sets.find(setId); + if (it != sets.cend() + && (it->second->flags & Data::StickersSetFlag::Unread)) { + HashUpdate(result, 1); + } + } + return HashFinalize(result); +} + } // namespace uint64 CountStickersHash( @@ -104,19 +121,15 @@ uint64 CountFavedStickersHash(not_null session) { } uint64 CountFeaturedStickersHash(not_null session) { - auto result = HashInit(); - const auto &sets = session->data().stickers().sets(); - const auto &featured = session->data().stickers().featuredSetsOrder(); - for (const auto setId : featured) { - HashUpdate(result, setId); + return CountFeaturedHash( + session, + session->data().stickers().featuredSetsOrder()); +} - const auto it = sets.find(setId); - if (it != sets.cend() - && (it->second->flags & Data::StickersSetFlag::Unread)) { - HashUpdate(result, 1); - } - } - return HashFinalize(result); +uint64 CountFeaturedEmojiHash(not_null session) { + return CountFeaturedHash( + session, + session->data().stickers().featuredEmojiSetsOrder()); } uint64 CountSavedGifsHash(not_null session) { diff --git a/Telegram/SourceFiles/api/api_hash.h b/Telegram/SourceFiles/api/api_hash.h index efd96d874b..3b459beb9e 100644 --- a/Telegram/SourceFiles/api/api_hash.h +++ b/Telegram/SourceFiles/api/api_hash.h @@ -25,9 +25,12 @@ namespace Api { [[nodiscard]] uint64 CountRecentStickersHash( not_null session, bool attached = false); -[[nodiscard]] uint64 CountFavedStickersHash(not_null session); +[[nodiscard]] uint64 CountFavedStickersHash( + not_null session); [[nodiscard]] uint64 CountFeaturedStickersHash( not_null session); +[[nodiscard]] uint64 CountFeaturedEmojiHash( + not_null session); [[nodiscard]] uint64 CountSavedGifsHash(not_null session); [[nodiscard]] inline uint64 HashInit() { diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 3e3ac54392..b9204877a1 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -2526,6 +2526,7 @@ void ApiWrap::updateStickers() { requestRecentStickers(now); requestFavedStickers(now); requestFeaturedStickers(now); + requestFeaturedEmoji(now); requestSavedGifs(now); } @@ -2778,28 +2779,33 @@ void ApiWrap::requestFeaturedStickers(TimeId now) { _featuredStickersUpdateRequest = request(MTPmessages_GetFeaturedStickers( MTP_long(Api::CountFeaturedStickersHash(_session)) )).done([=](const MTPmessages_FeaturedStickers &result) { - _session->data().stickers().setLastFeaturedUpdate(crl::now()); _featuredStickersUpdateRequest = 0; - - switch (result.type()) { - case mtpc_messages_featuredStickersNotModified: return; - case mtpc_messages_featuredStickers: { - auto &d = result.c_messages_featuredStickers(); - _session->data().stickers().featuredSetsReceived( - d.vsets().v, - d.vunread().v, - d.vhash().v); - } return; - default: Unexpected("Type in ApiWrap::featuredStickersDone()"); - } + _session->data().stickers().featuredSetsReceived(result); }).fail([=] { - _session->data().stickers().setLastFeaturedUpdate(crl::now()); _featuredStickersUpdateRequest = 0; - + _session->data().stickers().setLastFeaturedUpdate(crl::now()); LOG(("App Fail: Failed to get featured stickers!")); }).send(); } +void ApiWrap::requestFeaturedEmoji(TimeId now) { + if (!_session->data().stickers().featuredEmojiUpdateNeeded(now) + || _featuredEmojiUpdateRequest) { + return; + } + _featuredEmojiUpdateRequest = request( + MTPmessages_GetFeaturedEmojiStickers( + MTP_long(Api::CountFeaturedStickersHash(_session))) + ).done([=](const MTPmessages_FeaturedStickers &result) { + _featuredEmojiUpdateRequest = 0; + _session->data().stickers().featuredEmojiSetsReceived(result); + }).fail([=] { + _featuredEmojiUpdateRequest = 0; + _session->data().stickers().setLastFeaturedEmojiUpdate(crl::now()); + LOG(("App Fail: Failed to get featured emoji!")); + }).send(); +} + void ApiWrap::requestSavedGifs(TimeId now) { if (!_session->data().stickers().savedGifsUpdateNeeded(now) || _savedGifsUpdateRequest) { diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index e9886ef8e1..b67f1a586c 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -445,6 +445,7 @@ private: void requestRecentStickersWithHash(uint64 hash, bool attached = false); void requestFavedStickers(TimeId now); void requestFeaturedStickers(TimeId now); + void requestFeaturedEmoji(TimeId now); void requestSavedGifs(TimeId now); void readFeaturedSets(); @@ -564,6 +565,7 @@ private: mtpRequestId _recentAttachedStickersUpdateRequest = 0; mtpRequestId _favedStickersUpdateRequest = 0; mtpRequestId _featuredStickersUpdateRequest = 0; + mtpRequestId _featuredEmojiUpdateRequest = 0; mtpRequestId _savedGifsUpdateRequest = 0; base::Timer _featuredSetsReadTimer; diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp index d0f733f05b..e331425e43 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp @@ -392,10 +392,12 @@ EmojiListWidget::EmojiListWidget( resizeToWidth(width()); }, lifetime()); - Data::AmPremiumValue( - &controller->session() - ) | rpl::start_with_next([=] { - update(); + rpl::combine( + Data::AmPremiumValue(&controller->session()), + controller->session().premiumPossibleValue() + ) | rpl::skip(1) | rpl::start_with_next([=] { + refreshCustom(); + resizeToWidth(width()); }, lifetime()); } @@ -1221,8 +1223,9 @@ void EmojiListWidget::refreshCustom() { auto old = base::take(_custom); const auto owner = &controller()->session().data(); const auto &order = owner->stickers().emojiSetsOrder(); + const auto &featured = owner->stickers().featuredEmojiSetsOrder(); const auto &sets = owner->stickers().sets(); - for (const auto setId : order) { + for (const auto setId : ranges::views::concat(order, featured)) { auto it = sets.find(setId); if (it == sets.cend() || it->second->stickers.isEmpty()) { continue; diff --git a/Telegram/SourceFiles/data/stickers/data_stickers.cpp b/Telegram/SourceFiles/data/stickers/data_stickers.cpp index b47fbbbe53..42d88ea4df 100644 --- a/Telegram/SourceFiles/data/stickers/data_stickers.cpp +++ b/Telegram/SourceFiles/data/stickers/data_stickers.cpp @@ -401,14 +401,19 @@ void Stickers::installLocally(uint64 setId) { } const auto set = it->second.get(); - auto flags = set->flags; + const auto flags = set->flags; set->flags &= ~(SetFlag::Archived | SetFlag::Unread); set->flags |= SetFlag::Installed; set->installDate = base::unixtime::now(); auto changedFlags = flags ^ set->flags; - const auto masks = !!(flags & SetFlag::Masks); - auto &order = masks ? maskSetsOrderRef() : setsOrderRef(); + const auto isMasks = (set->type() == StickersType::Masks); + const auto isEmoji = (set->type() == StickersType::Emoji); + auto &order = isEmoji + ? emojiSetsOrderRef() + : isMasks + ? maskSetsOrderRef() + : setsOrderRef(); int insertAtIndex = 0, currentIndex = order.indexOf(setId); if (currentIndex != insertAtIndex) { if (currentIndex > 0) { @@ -429,17 +434,21 @@ void Stickers::installLocally(uint64 setId) { } } session().local().writeInstalledStickers(); - if (changedFlags & SetFlag::Unread) { - session().local().writeFeaturedStickers(); + if (!isMasks && (changedFlags & SetFlag::Unread)) { + if (isEmoji) { + session().local().writeFeaturedCustomEmoji(); + } else { + session().local().writeFeaturedStickers(); + } } - if (changedFlags & SetFlag::Archived) { - auto &archivedOrder = masks + if (!isEmoji && (changedFlags & SetFlag::Archived)) { + auto &archivedOrder = isMasks ? archivedMaskSetsOrderRef() : archivedSetsOrderRef(); const auto index = archivedOrder.indexOf(setId); if (index >= 0) { archivedOrder.removeAt(index); - if (masks) { + if (isMasks) { session().local().writeArchivedMasks(); } else { session().local().writeArchivedStickers(); @@ -922,27 +931,51 @@ void Stickers::specialSetReceived( } void Stickers::featuredSetsReceived( - const QVector &list, - const QVector &unread, - uint64 hash) { + const MTPmessages_FeaturedStickers &result) { + setLastFeaturedUpdate(crl::now()); + result.match([](const MTPDmessages_featuredStickersNotModified &) { + }, [&](const MTPDmessages_featuredStickers &data) { + featuredReceived(data, StickersType::Stickers); + }); +} + +void Stickers::featuredEmojiSetsReceived( + const MTPmessages_FeaturedStickers &result) { + setLastFeaturedEmojiUpdate(crl::now()); + result.match([](const MTPDmessages_featuredStickersNotModified &) { + }, [&](const MTPDmessages_featuredStickers &data) { + featuredReceived(data, StickersType::Emoji); + }); +} + +void Stickers::featuredReceived( + const MTPDmessages_featuredStickers &data, + StickersType type) { + const auto &list = data.vsets().v; + const auto &unread = data.vunread().v; + const auto hash = data.vhash().v; + auto &&unreadIds = ranges::views::all( unread - ) | ranges::views::transform([](const MTPlong &id) { - return id.v; - }); + ) | ranges::views::transform(&MTPlong::v); const auto unreadMap = base::flat_set{ unreadIds.begin(), unreadIds.end() }; - auto &setsOrder = featuredSetsOrderRef(); + const auto isEmoji = (type == StickersType::Emoji); + auto &setsOrder = isEmoji + ? featuredEmojiSetsOrderRef() + : featuredSetsOrderRef(); setsOrder.clear(); auto &sets = setsRef(); auto setsToRequest = base::flat_map(); for (auto &[id, set] : sets) { // Mark for removing. - set->flags &= ~SetFlag::Featured; + if (set->type() == type) { + set->flags &= ~SetFlag::Featured; + } } for (const auto &entry : list) { const auto data = entry.match([&](const auto &data) { @@ -1015,7 +1048,9 @@ void Stickers::featuredSetsReceived( bool archived = (set->flags & SetFlag::Archived); if (installed || featured || special || archived) { if (featured && (set->flags & SetFlag::Unread)) { - ++unreadCount; + if (!(set->flags & SetFlag::Emoji)) { + ++unreadCount; + } } ++it; } else { @@ -1024,7 +1059,9 @@ void Stickers::featuredSetsReceived( } setFeaturedSetsUnreadCount(unreadCount); - const auto counted = Api::CountFeaturedStickersHash(&session()); + const auto counted = isEmoji + ? Api::CountFeaturedEmojiHash(&session()) + : Api::CountFeaturedStickersHash(&session()); if (counted != hash) { LOG(("API Error: " "received featured stickers hash %1 while counted hash is %2" @@ -1039,8 +1076,11 @@ void Stickers::featuredSetsReceived( } api.requestStickerSets(); } - - session().local().writeFeaturedStickers(); + if (isEmoji) { + session().local().writeFeaturedCustomEmoji(); + } else { + session().local().writeFeaturedStickers(); + } notifyUpdated(); } @@ -1411,8 +1451,8 @@ void Stickers::feedSetStickers( } } - const auto isEmoji = !!(set->flags & SetFlag::Emoji); - const auto isMasks = !!(set->flags & SetFlag::Masks); + const auto isEmoji = (set->type() == StickersType::Emoji); + const auto isMasks = (set->type() == StickersType::Masks); set->stickers = pack; set->emoji.clear(); for (auto i = 0, l = int(packs.size()); i != l; ++i) { @@ -1449,7 +1489,12 @@ void Stickers::feedSetStickers( } } if (set->flags & SetFlag::Featured) { - session().local().writeFeaturedStickers(); + if (isEmoji) { + session().local().writeFeaturedCustomEmoji(); + } else if (isMasks) { + } else { + session().local().writeFeaturedStickers(); + } } if (wasArchived != isArchived) { if (isEmoji) { diff --git a/Telegram/SourceFiles/data/stickers/data_stickers.h b/Telegram/SourceFiles/data/stickers/data_stickers.h index ac502aa322..782d879039 100644 --- a/Telegram/SourceFiles/data/stickers/data_stickers.h +++ b/Telegram/SourceFiles/data/stickers/data_stickers.h @@ -126,6 +126,12 @@ public: void setLastFeaturedUpdate(crl::time update) { _lastFeaturedUpdate = update; } + bool featuredEmojiUpdateNeeded(crl::time now) const { + return updateNeeded(_lastFeaturedEmojiUpdate, now); + } + void setLastFeaturedEmojiUpdate(crl::time update) { + _lastFeaturedEmojiUpdate = update; + } bool savedGifsUpdateNeeded(crl::time now) const { return updateNeeded(_lastSavedGifsUpdate, now); } @@ -171,6 +177,12 @@ public: StickersSetsOrder &featuredSetsOrderRef() { return _featuredSetsOrder; } + const StickersSetsOrder &featuredEmojiSetsOrder() const { + return _featuredEmojiSetsOrder; + } + StickersSetsOrder &featuredEmojiSetsOrderRef() { + return _featuredEmojiSetsOrder; + } const StickersSetsOrder &archivedSetsOrder() const { return _archivedSetsOrder; } @@ -216,10 +228,9 @@ public: uint64 hash, const QVector &packs = QVector(), const QVector &usageDates = QVector()); - void featuredSetsReceived( - const QVector &list, - const QVector &unread, - uint64 hash); + void featuredSetsReceived(const MTPmessages_FeaturedStickers &result); + void featuredEmojiSetsReceived( + const MTPmessages_FeaturedStickers &result); void gifsReceived(const QVector &items, uint64 hash); std::vector> getListByEmoji( @@ -277,6 +288,9 @@ private: const QVector &list, uint64 hash, StickersType type); + void featuredReceived( + const MTPDmessages_featuredStickers &data, + StickersType type); const not_null _owner; rpl::event_stream<> _updated; @@ -291,6 +305,7 @@ private: crl::time _lastSavedGifsUpdate = 0; crl::time _lastMasksUpdate = 0; crl::time _lastEmojiUpdate = 0; + crl::time _lastFeaturedEmojiUpdate = 0; crl::time _lastRecentAttachedUpdate = 0; rpl::variable _featuredSetsUnreadCount = 0; StickersSets _sets; @@ -298,6 +313,7 @@ private: StickersSetsOrder _maskSetsOrder; StickersSetsOrder _emojiSetsOrder; StickersSetsOrder _featuredSetsOrder; + StickersSetsOrder _featuredEmojiSetsOrder; StickersSetsOrder _archivedSetsOrder; StickersSetsOrder _archivedMaskSetsOrder; SavedGifs _savedGifs; diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 2b02b2fb78..02144bc47c 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -159,6 +159,7 @@ Session::Session( local().readInstalledMasks(); local().readInstalledCustomEmoji(); local().readFeaturedStickers(); + local().readFeaturedCustomEmoji(); local().readRecentStickers(); local().readRecentMasks(); local().readFavedStickers(); diff --git a/Telegram/SourceFiles/storage/storage_account.cpp b/Telegram/SourceFiles/storage/storage_account.cpp index f676a75732..de5614bff7 100644 --- a/Telegram/SourceFiles/storage/storage_account.cpp +++ b/Telegram/SourceFiles/storage/storage_account.cpp @@ -205,7 +205,7 @@ base::flat_set Account::collectGoodNames() const { _recentMasksKey, _archivedMasksKey, _installedCustomEmojiKey, - _recentCustomEmojiKey, + _featuredCustomEmojiKey, _archivedCustomEmojiKey, }; auto result = base::flat_set{ @@ -288,7 +288,7 @@ Account::ReadMapResult Account::readMapWith( quint64 recentStickersKeyOld = 0; quint64 installedStickersKey = 0, featuredStickersKey = 0, recentStickersKey = 0, favedStickersKey = 0, archivedStickersKey = 0; quint64 installedMasksKey = 0, recentMasksKey = 0, archivedMasksKey = 0; - quint64 installedCustomEmojiKey = 0, recentCustomEmojiKey = 0, archivedCustomEmojiKey = 0; + quint64 installedCustomEmojiKey = 0, featuredCustomEmojiKey = 0, archivedCustomEmojiKey = 0; quint64 savedGifsKey = 0; quint64 legacyBackgroundKeyDay = 0, legacyBackgroundKeyNight = 0; quint64 userSettingsKey = 0, recentHashtagsAndBotsKey = 0, exportSettingsKey = 0; @@ -394,7 +394,7 @@ Account::ReadMapResult Account::readMapWith( case lskCustomEmojiKeys: { map.stream >> installedCustomEmojiKey - >> recentCustomEmojiKey + >> featuredCustomEmojiKey >> archivedCustomEmojiKey; } break; default: @@ -425,7 +425,7 @@ Account::ReadMapResult Account::readMapWith( _recentMasksKey = recentMasksKey; _archivedMasksKey = archivedMasksKey; _installedCustomEmojiKey = installedCustomEmojiKey; - _recentCustomEmojiKey = recentCustomEmojiKey; + _featuredCustomEmojiKey = featuredCustomEmojiKey; _archivedCustomEmojiKey = archivedCustomEmojiKey; _legacyBackgroundKeyDay = legacyBackgroundKeyDay; _legacyBackgroundKeyNight = legacyBackgroundKeyNight; @@ -534,7 +534,7 @@ void Account::writeMap() { if (_installedMasksKey || _recentMasksKey || _archivedMasksKey) { mapSize += sizeof(quint32) + 3 * sizeof(quint64); } - if (_installedCustomEmojiKey || _recentCustomEmojiKey || _archivedCustomEmojiKey) { + if (_installedCustomEmojiKey || _featuredCustomEmojiKey || _archivedCustomEmojiKey) { mapSize += sizeof(quint32) + 3 * sizeof(quint64); } @@ -589,11 +589,11 @@ void Account::writeMap() { << quint64(_recentMasksKey) << quint64(_archivedMasksKey); } - if (_installedCustomEmojiKey || _recentCustomEmojiKey || _archivedCustomEmojiKey) { + if (_installedCustomEmojiKey || _featuredCustomEmojiKey || _archivedCustomEmojiKey) { mapData.stream << quint32(lskCustomEmojiKeys); mapData.stream << quint64(_installedCustomEmojiKey) - << quint64(_recentCustomEmojiKey) + << quint64(_featuredCustomEmojiKey) << quint64(_archivedCustomEmojiKey); } map.writeEncrypted(mapData, _localKey); @@ -618,7 +618,7 @@ void Account::reset() { _recentMasksKey = 0; _archivedMasksKey = 0; _installedCustomEmojiKey = 0; - _recentCustomEmojiKey = 0; + _featuredCustomEmojiKey = 0; _archivedCustomEmojiKey = 0; _legacyBackgroundKeyDay = _legacyBackgroundKeyNight = 0; _settingsKey = _recentHashtagsAndBotsKey = _exportSettingsKey = 0; @@ -2042,7 +2042,7 @@ void Account::writeFeaturedStickers() { || set.id == Data::Stickers::CloudRecentAttachedSetId) { // separate files for them return StickerSetCheckResult::Skip; - } else if (set.flags & SetFlag::Special) { + } else if (set.flags & (SetFlag::Special | SetFlag::Emoji)) { return StickerSetCheckResult::Skip; } else if (!(set.flags & SetFlag::Featured)) { return StickerSetCheckResult::Skip; @@ -2055,6 +2055,23 @@ void Account::writeFeaturedStickers() { }, _owner->session().data().stickers().featuredSetsOrder()); } +void Account::writeFeaturedCustomEmoji() { + using SetFlag = Data::StickersSetFlag; + + writeStickerSets(_featuredCustomEmojiKey, [](const Data::StickersSet &set) { + if (!(set.flags & SetFlag::Emoji)) { + return StickerSetCheckResult::Skip; + } else if (!(set.flags & SetFlag::Featured)) { + return StickerSetCheckResult::Skip; + } else if (set.flags & SetFlag::NotLoaded) { // waiting to receive + return StickerSetCheckResult::Abort; + } else if (set.stickers.isEmpty()) { + return StickerSetCheckResult::Skip; + } + return StickerSetCheckResult::Write; + }, _owner->session().data().stickers().featuredEmojiSetsOrder()); +} + void Account::writeRecentStickers() { writeStickerSets(_recentStickersKey, [](const Data::StickersSet &set) { if (set.id != Data::Stickers::CloudRecentSetId @@ -2293,6 +2310,13 @@ void Account::readFeaturedStickers() { _owner->session().data().stickers().setFeaturedSetsUnreadCount(unreadCount); } +void Account::readFeaturedCustomEmoji() { + readStickerSets( + _featuredCustomEmojiKey, + &_owner->session().data().stickers().featuredEmojiSetsOrderRef(), + Data::StickersSetFlag::Featured); +} + void Account::readRecentStickers() { readStickerSets(_recentStickersKey); } diff --git a/Telegram/SourceFiles/storage/storage_account.h b/Telegram/SourceFiles/storage/storage_account.h index d8cfb4a842..c96ba84f89 100644 --- a/Telegram/SourceFiles/storage/storage_account.h +++ b/Telegram/SourceFiles/storage/storage_account.h @@ -136,7 +136,9 @@ public: void readInstalledMasks(); void readRecentMasks(); void writeInstalledCustomEmoji(); + void writeFeaturedCustomEmoji(); void readInstalledCustomEmoji(); + void readFeaturedCustomEmoji(); void writeRecentHashtagsAndBots(); void readRecentHashtagsAndBots(); @@ -287,7 +289,7 @@ private: FileKey _installedMasksKey = 0; FileKey _recentMasksKey = 0; FileKey _installedCustomEmojiKey = 0; - FileKey _recentCustomEmojiKey = 0; + FileKey _featuredCustomEmojiKey = 0; FileKey _archivedCustomEmojiKey = 0; qint64 _cacheTotalSizeLimit = 0;