From bb6fd4bc4dbe36f3988d0baf5a60a32893d874f1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 30 Apr 2024 22:30:39 +0400 Subject: [PATCH] Update scheme, new sticker categories. --- Telegram/SourceFiles/api/api_statistics.cpp | 8 +- .../chat_helpers/emoji_list_widget.cpp | 7 +- .../chat_helpers/gifs_list_widget.cpp | 2 +- .../chat_helpers/stickers_list_widget.cpp | 30 +++- .../chat_helpers/tabbed_selector.cpp | 9 +- .../chat_helpers/tabbed_selector.h | 9 +- .../SourceFiles/data/data_emoji_statuses.cpp | 38 +++-- .../SourceFiles/data/data_emoji_statuses.h | 3 + .../data/stickers/data_stickers.cpp | 135 ++++++++++++++++++ .../SourceFiles/data/stickers/data_stickers.h | 2 + Telegram/SourceFiles/mtproto/scheme/api.tl | 7 +- .../SourceFiles/ui/controls/tabbed_search.cpp | 9 +- .../SourceFiles/ui/controls/tabbed_search.h | 9 ++ 13 files changed, 238 insertions(+), 30 deletions(-) diff --git a/Telegram/SourceFiles/api/api_statistics.cpp b/Telegram/SourceFiles/api/api_statistics.cpp index 7139c5ebb..ce1966623 100644 --- a/Telegram/SourceFiles/api/api_statistics.cpp +++ b/Telegram/SourceFiles/api/api_statistics.cpp @@ -760,14 +760,14 @@ rpl::producer EarnStatistics::request() { channel()->inputChannel )).done([=](const MTPstats_BroadcastRevenueStats &result) { const auto &data = result.data(); - + const auto &balances = data.vbalances().data(); _data = Data::EarnStatistics{ .topHoursGraph = StatisticalGraphFromTL( data.vtop_hours_graph()), .revenueGraph = StatisticalGraphFromTL(data.vrevenue_graph()), - .currentBalance = data.vcurrent_balance().v, - .availableBalance = data.vavailable_balance().v, - .overallRevenue = data.voverall_revenue().v, + .currentBalance = balances.vcurrent_balance().v, + .availableBalance = balances.vavailable_balance().v, + .overallRevenue = balances.voverall_revenue().v, .usdRate = data.vusd_rate().v, }; diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp index c8148ae8e..2157e9168 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp @@ -573,12 +573,17 @@ EmojiListWidget::~EmojiListWidget() { void EmojiListWidget::setupSearch() { const auto session = &_show->session(); + const auto type = (_mode == Mode::EmojiStatus) + ? TabbedSearchType::Status + : (_mode == Mode::UserpicBuilder) + ? TabbedSearchType::ProfilePhoto + : TabbedSearchType::Emoji; _search = MakeSearch(this, st(), [=](std::vector &&query) { _nextSearchQuery = std::move(query); InvokeQueued(this, [=] { applyNextSearchQuery(); }); - }, session, (_mode == Mode::EmojiStatus), _mode == Mode::UserpicBuilder); + }, session, type); } void EmojiListWidget::applyNextSearchQuery() { diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp index 72794de39..609f21989 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp @@ -820,7 +820,7 @@ void GifsListWidget::setupSearch() { : SearchEmojiSectionSetId(); refreshIcons(); searchForGifs(accumulated); - }, session); + }, session, TabbedSearchType::Emoji); } int32 GifsListWidget::showInlineRows(bool newResults) { diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index 42ea6b934..07a02caa9 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -547,6 +547,15 @@ void StickersListWidget::sendSearchRequest() { } _search->setLoading(true); + + if (_searchQuery == Ui::PremiumGroupFakeEmoticon()) { + _search->setLoading(false); + _searchRequestId = 0; + _searchCache.emplace(_searchQuery, std::vector()); + showSearchResults(); + return; + } + const auto hash = uint64(0); _searchRequestId = _api.request(MTPmessages_SearchStickerSets( MTP_flags(0), @@ -570,10 +579,14 @@ void StickersListWidget::searchForSets( return; } - _filteredStickers = session().data().stickers().getListByEmoji( - std::move(emoji), - 0, - true); + if (query == Ui::PremiumGroupFakeEmoticon()) { + _filteredStickers = session().data().stickers().getPremiumList(0); + } else { + _filteredStickers = session().data().stickers().getListByEmoji( + std::move(emoji), + 0, + true); + } if (_searchQuery != cleaned) { _search->setLoading(false); if (const auto requestId = base::take(_searchRequestId)) { @@ -2604,15 +2617,18 @@ void StickersListWidget::beforeHiding() { void StickersListWidget::setupSearch() { const auto session = &_show->session(); + const auto type = (_mode == Mode::UserpicBuilder) + ? TabbedSearchType::ProfilePhoto + : TabbedSearchType::Stickers; _search = MakeSearch(this, st(), [=](std::vector &&query) { auto set = base::flat_set(); auto text = ranges::accumulate(query, QString(), []( - QString a, - QString b) { + QString a, + QString b) { return a.isEmpty() ? b : (a + ' ' + b); }); searchForSets(std::move(text), SearchEmoji(query, set)); - }, session, false, (_mode == Mode::UserpicBuilder)); + }, session, type); } void StickersListWidget::displaySet(uint64 setId) { diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp index e57b3adc8..7f8a915c7 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp @@ -307,16 +307,17 @@ std::unique_ptr MakeSearch( const style::EmojiPan &st, Fn&&)> callback, not_null session, - bool statusCategories, - bool profilePhotoCategories) { + TabbedSearchType type) { using Descriptor = Ui::SearchDescriptor; const auto owner = &session->data(); auto result = std::make_unique(parent, st, Descriptor{ .st = st.search, - .groups = (profilePhotoCategories + .groups = ((type == TabbedSearchType::ProfilePhoto) ? owner->emojiStatuses().profilePhotoGroupsValue() - : statusCategories + : (type == TabbedSearchType::Status) ? owner->emojiStatuses().statusGroupsValue() + : (type == TabbedSearchType::Stickers) + ? owner->emojiStatuses().stickerGroupsValue() : owner->emojiStatuses().emojiGroupsValue()), .customEmojiFactory = owner->customEmojiManager().factory( Data::CustomEmojiManager::SizeTag::SetIcon, diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h index 606f1a926..f663d470a 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h @@ -98,13 +98,18 @@ struct TabbedSelectorDescriptor { ComposeFeatures features; }; +enum class TabbedSearchType { + Emoji, + Status, + ProfilePhoto, + Stickers, +}; [[nodiscard]] std::unique_ptr MakeSearch( not_null parent, const style::EmojiPan &st, Fn&&)> callback, not_null session, - bool statusCategories = false, - bool profilePhotoCategories = false); + TabbedSearchType type); class TabbedSelector : public Ui::RpWidget { public: diff --git a/Telegram/SourceFiles/data/data_emoji_statuses.cpp b/Telegram/SourceFiles/data/data_emoji_statuses.cpp index dd1ad583b..e00dd8910 100644 --- a/Telegram/SourceFiles/data/data_emoji_statuses.cpp +++ b/Telegram/SourceFiles/data/data_emoji_statuses.cpp @@ -153,6 +153,11 @@ auto EmojiStatuses::statusGroupsValue() const -> rpl::producer { return _statusGroups.data.value(); } +auto EmojiStatuses::stickerGroupsValue() const -> rpl::producer { + const_cast(this)->requestStickerGroups(); + return _stickerGroups.data.value(); +} + auto EmojiStatuses::profilePhotoGroupsValue() const -> rpl::producer { const_cast(this)->requestProfilePhotoGroups(); @@ -172,6 +177,12 @@ void EmojiStatuses::requestStatusGroups() { MTPmessages_GetEmojiStatusGroups(MTP_int(_statusGroups.hash))); } +void EmojiStatuses::requestStickerGroups() { + requestGroups( + &_stickerGroups, + MTPmessages_GetEmojiStickerGroups(MTP_int(_stickerGroups.hash))); +} + void EmojiStatuses::requestProfilePhotoGroups() { requestGroups( &_profilePhotoGroups, @@ -185,15 +196,24 @@ void EmojiStatuses::requestProfilePhotoGroups() { auto result = std::vector(); result.reserve(list.size()); for (const auto &group : list) { - const auto &data = group.data(); - auto emoticons = ranges::views::all( - data.vemoticons().v - ) | ranges::views::transform([](const MTPstring &emoticon) { - return qs(emoticon); - }) | ranges::to_vector; - result.push_back({ - .iconId = QString::number(data.vicon_emoji_id().v), - .emoticons = std::move(emoticons), + group.match([&](const MTPDemojiGroupPremium &data) { + result.push_back({ + .iconId = QString::number(data.vicon_emoji_id().v), + .type = Ui::EmojiGroupType::Premium, + }); + }, [&](const auto &data) { + auto emoticons = ranges::views::all( + data.vemoticons().v + ) | ranges::views::transform([](const MTPstring &emoticon) { + return qs(emoticon); + }) | ranges::to_vector; + result.push_back({ + .iconId = QString::number(data.vicon_emoji_id().v), + .emoticons = std::move(emoticons), + .type = (MTPDemojiGroupGreeting::Is() + ? Ui::EmojiGroupType::Greeting + : Ui::EmojiGroupType::Normal), + }); }); } return result; diff --git a/Telegram/SourceFiles/data/data_emoji_statuses.h b/Telegram/SourceFiles/data/data_emoji_statuses.h index 5501eb8bc..0a0b75ba2 100644 --- a/Telegram/SourceFiles/data/data_emoji_statuses.h +++ b/Telegram/SourceFiles/data/data_emoji_statuses.h @@ -60,9 +60,11 @@ public: using Groups = std::vector; [[nodiscard]] rpl::producer emojiGroupsValue() const; [[nodiscard]] rpl::producer statusGroupsValue() const; + [[nodiscard]] rpl::producer stickerGroupsValue() const; [[nodiscard]] rpl::producer profilePhotoGroupsValue() const; void requestEmojiGroups(); void requestStatusGroups(); + void requestStickerGroups(); void requestProfilePhotoGroups(); private: @@ -124,6 +126,7 @@ private: GroupsType _emojiGroups; GroupsType _statusGroups; + GroupsType _stickerGroups; GroupsType _profilePhotoGroups; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/data/stickers/data_stickers.cpp b/Telegram/SourceFiles/data/stickers/data_stickers.cpp index f6da8553d..057e1d8cf 100644 --- a/Telegram/SourceFiles/data/stickers/data_stickers.cpp +++ b/Telegram/SourceFiles/data/stickers/data_stickers.cpp @@ -1132,6 +1132,141 @@ void Stickers::gifsReceived(const QVector &items, uint64 hash) { notifySavedGifsUpdated(); } +std::vector> Stickers::getPremiumList(uint64 seed) { + struct StickerWithDate { + not_null document; + TimeId date = 0; + }; + auto result = std::vector(); + auto &sets = setsRef(); + auto setsToRequest = base::flat_map(); + + const auto add = [&](not_null document, TimeId date) { + if (ranges::find(result, document, [](const StickerWithDate &data) { + return data.document; + }) == result.end()) { + result.push_back({ document, date }); + } + }; + + constexpr auto kSlice = 65536; + const auto CreateSortKey = [&]( + not_null document, + int base) { + if (document->sticker() && document->sticker()->isAnimated()) { + base += kSlice; + } + return TimeId(base + int((document->id ^ seed) % kSlice)); + }; + const auto CreateRecentSortKey = [&](not_null document) { + return CreateSortKey(document, kSlice * 6); + }; + auto myCounter = 0; + const auto CreateMySortKey = [&](not_null document) { + auto base = kSlice * 6; + if (!document->sticker() || !document->sticker()->isAnimated()) { + base -= kSlice; + } + return (base - (++myCounter)); + }; + const auto CreateFeaturedSortKey = [&](not_null document) { + return CreateSortKey(document, kSlice * 2); + }; + const auto CreateOtherSortKey = [&](not_null document) { + return CreateSortKey(document, 0); + }; + const auto InstallDateAdjusted = [&]( + TimeId date, + not_null document) { + return (document->sticker() && document->sticker()->isAnimated()) + ? date + : date / 2; + }; + const auto RecentInstallDate = [&](not_null document) { + Expects(document->sticker() != nullptr); + + const auto sticker = document->sticker(); + if (sticker->set.id) { + const auto setIt = sets.find(sticker->set.id); + if (setIt != sets.end()) { + return InstallDateAdjusted(setIt->second->installDate, document); + } + } + return TimeId(0); + }; + + auto recentIt = sets.find(Stickers::CloudRecentSetId); + if (recentIt != sets.cend()) { + const auto recent = recentIt->second.get(); + const auto count = int(recent->stickers.size()); + result.reserve(count); + for (auto i = 0; i != count; ++i) { + const auto document = recent->stickers[i]; + auto index = i; + if (!document->isPremiumSticker()) { + continue; + } else { + index = recent->stickers.indexOf(document); + } + const auto usageDate = (recent->dates.empty() || index < 0) + ? 0 + : recent->dates[index]; + const auto date = usageDate + ? usageDate + : RecentInstallDate(document); + result.push_back({ + document, + date ? date : CreateRecentSortKey(document) }); + } + } + const auto addList = [&]( + const StickersSetsOrder &order, + SetFlag skip) { + for (const auto setId : order) { + auto it = sets.find(setId); + if (it == sets.cend() || (it->second->flags & skip)) { + continue; + } + const auto set = it->second.get(); + if (set->emoji.empty()) { + setsToRequest.emplace(set->id, set->accessHash); + set->flags |= SetFlag::NotLoaded; + continue; + } + const auto my = (set->flags & SetFlag::Installed); + result.reserve(result.size() + set->stickers.size()); + for (const auto document : set->stickers) { + if (!document->isPremiumSticker()) { + continue; + } + const auto installDate = my ? set->installDate : TimeId(0); + const auto date = (installDate > 1) + ? InstallDateAdjusted(installDate, document) + : my + ? CreateMySortKey(document) + : CreateFeaturedSortKey(document); + add(document, date); + } + } + }; + + addList(setsOrder(), SetFlag::Archived); + addList(featuredSetsOrder(), SetFlag::Installed); + + if (!setsToRequest.empty()) { + for (const auto &[setId, accessHash] : setsToRequest) { + session().api().scheduleStickerSetRequest(setId, accessHash); + } + session().api().requestStickerSets(); + } + + ranges::sort(result, std::greater<>(), &StickerWithDate::date); + + return result + | ranges::views::transform(&StickerWithDate::document) + | ranges::to_vector; +} + std::vector> Stickers::getListByEmoji( std::vector emoji, uint64 seed, diff --git a/Telegram/SourceFiles/data/stickers/data_stickers.h b/Telegram/SourceFiles/data/stickers/data_stickers.h index d5a192b4b..426b034aa 100644 --- a/Telegram/SourceFiles/data/stickers/data_stickers.h +++ b/Telegram/SourceFiles/data/stickers/data_stickers.h @@ -235,6 +235,8 @@ public: const MTPmessages_FeaturedStickers &result); void gifsReceived(const QVector &items, uint64 hash); + [[nodiscard]] std::vector> getPremiumList( + uint64 seed); [[nodiscard]] std::vector> getListByEmoji( std::vector emoji, uint64 seed, diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl index a75781792..963785e0b 100644 --- a/Telegram/SourceFiles/mtproto/scheme/api.tl +++ b/Telegram/SourceFiles/mtproto/scheme/api.tl @@ -1519,6 +1519,8 @@ emojiListNotModified#481eadfa = EmojiList; emojiList#7a1e11d1 hash:long document_id:Vector = EmojiList; emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; +emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; +emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup; messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups; messages.emojiGroups#881fb94b hash:int groups:Vector = messages.EmojiGroups; @@ -1762,7 +1764,7 @@ channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options: channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult; -stats.broadcastRevenueStats#d07b4bad top_hours_graph:StatsGraph revenue_graph:StatsGraph current_balance:long available_balance:long overall_revenue:long usd_rate:double = stats.BroadcastRevenueStats; +stats.broadcastRevenueStats#5407e297 top_hours_graph:StatsGraph revenue_graph:StatsGraph balances:BroadcastRevenueBalances usd_rate:double = stats.BroadcastRevenueStats; stats.broadcastRevenueWithdrawalUrl#ec659737 url:string = stats.BroadcastRevenueWithdrawalUrl; @@ -1777,6 +1779,8 @@ reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; +broadcastRevenueBalances#8438f1c6 current_balance:long available_balance:long overall_revenue:long = BroadcastRevenueBalances; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -2165,6 +2169,7 @@ messages.sendQuickReplyMessages#6c750de1 peer:InputPeer shortcut_id:int id:Vecto messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector = Updates; messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; +messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups; updates.getState#edd4882a = updates.State; updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; diff --git a/Telegram/SourceFiles/ui/controls/tabbed_search.cpp b/Telegram/SourceFiles/ui/controls/tabbed_search.cpp index 6aaea70dc..7acc65a8f 100644 --- a/Telegram/SourceFiles/ui/controls/tabbed_search.cpp +++ b/Telegram/SourceFiles/ui/controls/tabbed_search.cpp @@ -273,6 +273,11 @@ void GroupsStrip::fireChosenGroup() { } // namespace +const QString &PremiumGroupFakeEmoticon() { + static const auto result = u"*premium"_q; + return result; +} + SearchWithGroups::SearchWithGroups( QWidget *parent, SearchDescriptor descriptor) @@ -359,7 +364,9 @@ void SearchWithGroups::initGroups() { widget->chosen( ) | rpl::start_with_next([=](const GroupsStrip::Chosen &chosen) { _chosenGroup = chosen.group->iconId; - _query = chosen.group->emoticons; + _query = (chosen.group->type == EmojiGroupType::Premium) + ? std::vector{ PremiumGroupFakeEmoticon() } + : chosen.group->emoticons; _debouncedQuery = chosen.group->emoticons; _debounceTimer.cancel(); scrollGroupsToIcon(chosen.iconLeft, chosen.iconRight); diff --git a/Telegram/SourceFiles/ui/controls/tabbed_search.h b/Telegram/SourceFiles/ui/controls/tabbed_search.h index 000cbccea..2a5d67e40 100644 --- a/Telegram/SourceFiles/ui/controls/tabbed_search.h +++ b/Telegram/SourceFiles/ui/controls/tabbed_search.h @@ -31,15 +31,24 @@ class RpWidget; template class FadeWrap; +enum class EmojiGroupType { + Normal, + Greeting, + Premium, +}; + struct EmojiGroup { QString iconId; std::vector emoticons; + EmojiGroupType type = EmojiGroupType::Normal; friend inline auto operator<=>( const EmojiGroup &a, const EmojiGroup &b) = default; }; +[[nodiscard]] const QString &PremiumGroupFakeEmoticon(); + struct SearchDescriptor { const style::TabbedSearch &st; rpl::producer> groups;