Update scheme, new sticker categories.

This commit is contained in:
John Preston 2024-04-30 22:30:39 +04:00
parent 63e1731d7c
commit bb6fd4bc4d
13 changed files with 238 additions and 30 deletions

View file

@ -760,14 +760,14 @@ rpl::producer<rpl::no_value, QString> EarnStatistics::request() {
channel()->inputChannel channel()->inputChannel
)).done([=](const MTPstats_BroadcastRevenueStats &result) { )).done([=](const MTPstats_BroadcastRevenueStats &result) {
const auto &data = result.data(); const auto &data = result.data();
const auto &balances = data.vbalances().data();
_data = Data::EarnStatistics{ _data = Data::EarnStatistics{
.topHoursGraph = StatisticalGraphFromTL( .topHoursGraph = StatisticalGraphFromTL(
data.vtop_hours_graph()), data.vtop_hours_graph()),
.revenueGraph = StatisticalGraphFromTL(data.vrevenue_graph()), .revenueGraph = StatisticalGraphFromTL(data.vrevenue_graph()),
.currentBalance = data.vcurrent_balance().v, .currentBalance = balances.vcurrent_balance().v,
.availableBalance = data.vavailable_balance().v, .availableBalance = balances.vavailable_balance().v,
.overallRevenue = data.voverall_revenue().v, .overallRevenue = balances.voverall_revenue().v,
.usdRate = data.vusd_rate().v, .usdRate = data.vusd_rate().v,
}; };

View file

@ -573,12 +573,17 @@ EmojiListWidget::~EmojiListWidget() {
void EmojiListWidget::setupSearch() { void EmojiListWidget::setupSearch() {
const auto session = &_show->session(); 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<QString> &&query) { _search = MakeSearch(this, st(), [=](std::vector<QString> &&query) {
_nextSearchQuery = std::move(query); _nextSearchQuery = std::move(query);
InvokeQueued(this, [=] { InvokeQueued(this, [=] {
applyNextSearchQuery(); applyNextSearchQuery();
}); });
}, session, (_mode == Mode::EmojiStatus), _mode == Mode::UserpicBuilder); }, session, type);
} }
void EmojiListWidget::applyNextSearchQuery() { void EmojiListWidget::applyNextSearchQuery() {

View file

@ -820,7 +820,7 @@ void GifsListWidget::setupSearch() {
: SearchEmojiSectionSetId(); : SearchEmojiSectionSetId();
refreshIcons(); refreshIcons();
searchForGifs(accumulated); searchForGifs(accumulated);
}, session); }, session, TabbedSearchType::Emoji);
} }
int32 GifsListWidget::showInlineRows(bool newResults) { int32 GifsListWidget::showInlineRows(bool newResults) {

View file

@ -547,6 +547,15 @@ void StickersListWidget::sendSearchRequest() {
} }
_search->setLoading(true); _search->setLoading(true);
if (_searchQuery == Ui::PremiumGroupFakeEmoticon()) {
_search->setLoading(false);
_searchRequestId = 0;
_searchCache.emplace(_searchQuery, std::vector<uint64>());
showSearchResults();
return;
}
const auto hash = uint64(0); const auto hash = uint64(0);
_searchRequestId = _api.request(MTPmessages_SearchStickerSets( _searchRequestId = _api.request(MTPmessages_SearchStickerSets(
MTP_flags(0), MTP_flags(0),
@ -570,10 +579,14 @@ void StickersListWidget::searchForSets(
return; return;
} }
if (query == Ui::PremiumGroupFakeEmoticon()) {
_filteredStickers = session().data().stickers().getPremiumList(0);
} else {
_filteredStickers = session().data().stickers().getListByEmoji( _filteredStickers = session().data().stickers().getListByEmoji(
std::move(emoji), std::move(emoji),
0, 0,
true); true);
}
if (_searchQuery != cleaned) { if (_searchQuery != cleaned) {
_search->setLoading(false); _search->setLoading(false);
if (const auto requestId = base::take(_searchRequestId)) { if (const auto requestId = base::take(_searchRequestId)) {
@ -2604,6 +2617,9 @@ void StickersListWidget::beforeHiding() {
void StickersListWidget::setupSearch() { void StickersListWidget::setupSearch() {
const auto session = &_show->session(); const auto session = &_show->session();
const auto type = (_mode == Mode::UserpicBuilder)
? TabbedSearchType::ProfilePhoto
: TabbedSearchType::Stickers;
_search = MakeSearch(this, st(), [=](std::vector<QString> &&query) { _search = MakeSearch(this, st(), [=](std::vector<QString> &&query) {
auto set = base::flat_set<EmojiPtr>(); auto set = base::flat_set<EmojiPtr>();
auto text = ranges::accumulate(query, QString(), []( auto text = ranges::accumulate(query, QString(), [](
@ -2612,7 +2628,7 @@ void StickersListWidget::setupSearch() {
return a.isEmpty() ? b : (a + ' ' + b); return a.isEmpty() ? b : (a + ' ' + b);
}); });
searchForSets(std::move(text), SearchEmoji(query, set)); searchForSets(std::move(text), SearchEmoji(query, set));
}, session, false, (_mode == Mode::UserpicBuilder)); }, session, type);
} }
void StickersListWidget::displaySet(uint64 setId) { void StickersListWidget::displaySet(uint64 setId) {

View file

@ -307,16 +307,17 @@ std::unique_ptr<Ui::TabbedSearch> MakeSearch(
const style::EmojiPan &st, const style::EmojiPan &st,
Fn<void(std::vector<QString>&&)> callback, Fn<void(std::vector<QString>&&)> callback,
not_null<Main::Session*> session, not_null<Main::Session*> session,
bool statusCategories, TabbedSearchType type) {
bool profilePhotoCategories) {
using Descriptor = Ui::SearchDescriptor; using Descriptor = Ui::SearchDescriptor;
const auto owner = &session->data(); const auto owner = &session->data();
auto result = std::make_unique<Ui::TabbedSearch>(parent, st, Descriptor{ auto result = std::make_unique<Ui::TabbedSearch>(parent, st, Descriptor{
.st = st.search, .st = st.search,
.groups = (profilePhotoCategories .groups = ((type == TabbedSearchType::ProfilePhoto)
? owner->emojiStatuses().profilePhotoGroupsValue() ? owner->emojiStatuses().profilePhotoGroupsValue()
: statusCategories : (type == TabbedSearchType::Status)
? owner->emojiStatuses().statusGroupsValue() ? owner->emojiStatuses().statusGroupsValue()
: (type == TabbedSearchType::Stickers)
? owner->emojiStatuses().stickerGroupsValue()
: owner->emojiStatuses().emojiGroupsValue()), : owner->emojiStatuses().emojiGroupsValue()),
.customEmojiFactory = owner->customEmojiManager().factory( .customEmojiFactory = owner->customEmojiManager().factory(
Data::CustomEmojiManager::SizeTag::SetIcon, Data::CustomEmojiManager::SizeTag::SetIcon,

View file

@ -98,13 +98,18 @@ struct TabbedSelectorDescriptor {
ComposeFeatures features; ComposeFeatures features;
}; };
enum class TabbedSearchType {
Emoji,
Status,
ProfilePhoto,
Stickers,
};
[[nodiscard]] std::unique_ptr<Ui::TabbedSearch> MakeSearch( [[nodiscard]] std::unique_ptr<Ui::TabbedSearch> MakeSearch(
not_null<Ui::RpWidget*> parent, not_null<Ui::RpWidget*> parent,
const style::EmojiPan &st, const style::EmojiPan &st,
Fn<void(std::vector<QString>&&)> callback, Fn<void(std::vector<QString>&&)> callback,
not_null<Main::Session*> session, not_null<Main::Session*> session,
bool statusCategories = false, TabbedSearchType type);
bool profilePhotoCategories = false);
class TabbedSelector : public Ui::RpWidget { class TabbedSelector : public Ui::RpWidget {
public: public:

View file

@ -153,6 +153,11 @@ auto EmojiStatuses::statusGroupsValue() const -> rpl::producer<Groups> {
return _statusGroups.data.value(); return _statusGroups.data.value();
} }
auto EmojiStatuses::stickerGroupsValue() const -> rpl::producer<Groups> {
const_cast<EmojiStatuses*>(this)->requestStickerGroups();
return _stickerGroups.data.value();
}
auto EmojiStatuses::profilePhotoGroupsValue() const auto EmojiStatuses::profilePhotoGroupsValue() const
-> rpl::producer<Groups> { -> rpl::producer<Groups> {
const_cast<EmojiStatuses*>(this)->requestProfilePhotoGroups(); const_cast<EmojiStatuses*>(this)->requestProfilePhotoGroups();
@ -172,6 +177,12 @@ void EmojiStatuses::requestStatusGroups() {
MTPmessages_GetEmojiStatusGroups(MTP_int(_statusGroups.hash))); MTPmessages_GetEmojiStatusGroups(MTP_int(_statusGroups.hash)));
} }
void EmojiStatuses::requestStickerGroups() {
requestGroups(
&_stickerGroups,
MTPmessages_GetEmojiStickerGroups(MTP_int(_stickerGroups.hash)));
}
void EmojiStatuses::requestProfilePhotoGroups() { void EmojiStatuses::requestProfilePhotoGroups() {
requestGroups( requestGroups(
&_profilePhotoGroups, &_profilePhotoGroups,
@ -185,7 +196,12 @@ void EmojiStatuses::requestProfilePhotoGroups() {
auto result = std::vector<Ui::EmojiGroup>(); auto result = std::vector<Ui::EmojiGroup>();
result.reserve(list.size()); result.reserve(list.size());
for (const auto &group : list) { for (const auto &group : list) {
const auto &data = group.data(); 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( auto emoticons = ranges::views::all(
data.vemoticons().v data.vemoticons().v
) | ranges::views::transform([](const MTPstring &emoticon) { ) | ranges::views::transform([](const MTPstring &emoticon) {
@ -194,6 +210,10 @@ void EmojiStatuses::requestProfilePhotoGroups() {
result.push_back({ result.push_back({
.iconId = QString::number(data.vicon_emoji_id().v), .iconId = QString::number(data.vicon_emoji_id().v),
.emoticons = std::move(emoticons), .emoticons = std::move(emoticons),
.type = (MTPDemojiGroupGreeting::Is<decltype(data)>()
? Ui::EmojiGroupType::Greeting
: Ui::EmojiGroupType::Normal),
});
}); });
} }
return result; return result;

View file

@ -60,9 +60,11 @@ public:
using Groups = std::vector<Ui::EmojiGroup>; using Groups = std::vector<Ui::EmojiGroup>;
[[nodiscard]] rpl::producer<Groups> emojiGroupsValue() const; [[nodiscard]] rpl::producer<Groups> emojiGroupsValue() const;
[[nodiscard]] rpl::producer<Groups> statusGroupsValue() const; [[nodiscard]] rpl::producer<Groups> statusGroupsValue() const;
[[nodiscard]] rpl::producer<Groups> stickerGroupsValue() const;
[[nodiscard]] rpl::producer<Groups> profilePhotoGroupsValue() const; [[nodiscard]] rpl::producer<Groups> profilePhotoGroupsValue() const;
void requestEmojiGroups(); void requestEmojiGroups();
void requestStatusGroups(); void requestStatusGroups();
void requestStickerGroups();
void requestProfilePhotoGroups(); void requestProfilePhotoGroups();
private: private:
@ -124,6 +126,7 @@ private:
GroupsType _emojiGroups; GroupsType _emojiGroups;
GroupsType _statusGroups; GroupsType _statusGroups;
GroupsType _stickerGroups;
GroupsType _profilePhotoGroups; GroupsType _profilePhotoGroups;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;

View file

@ -1132,6 +1132,141 @@ void Stickers::gifsReceived(const QVector<MTPDocument> &items, uint64 hash) {
notifySavedGifsUpdated(); notifySavedGifsUpdated();
} }
std::vector<not_null<DocumentData*>> Stickers::getPremiumList(uint64 seed) {
struct StickerWithDate {
not_null<DocumentData*> document;
TimeId date = 0;
};
auto result = std::vector<StickerWithDate>();
auto &sets = setsRef();
auto setsToRequest = base::flat_map<uint64, uint64>();
const auto add = [&](not_null<DocumentData*> 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<DocumentData*> document,
int base) {
if (document->sticker() && document->sticker()->isAnimated()) {
base += kSlice;
}
return TimeId(base + int((document->id ^ seed) % kSlice));
};
const auto CreateRecentSortKey = [&](not_null<DocumentData*> document) {
return CreateSortKey(document, kSlice * 6);
};
auto myCounter = 0;
const auto CreateMySortKey = [&](not_null<DocumentData*> document) {
auto base = kSlice * 6;
if (!document->sticker() || !document->sticker()->isAnimated()) {
base -= kSlice;
}
return (base - (++myCounter));
};
const auto CreateFeaturedSortKey = [&](not_null<DocumentData*> document) {
return CreateSortKey(document, kSlice * 2);
};
const auto CreateOtherSortKey = [&](not_null<DocumentData*> document) {
return CreateSortKey(document, 0);
};
const auto InstallDateAdjusted = [&](
TimeId date,
not_null<DocumentData*> document) {
return (document->sticker() && document->sticker()->isAnimated())
? date
: date / 2;
};
const auto RecentInstallDate = [&](not_null<DocumentData*> 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<not_null<DocumentData*>> Stickers::getListByEmoji( std::vector<not_null<DocumentData*>> Stickers::getListByEmoji(
std::vector<EmojiPtr> emoji, std::vector<EmojiPtr> emoji,
uint64 seed, uint64 seed,

View file

@ -235,6 +235,8 @@ public:
const MTPmessages_FeaturedStickers &result); const MTPmessages_FeaturedStickers &result);
void gifsReceived(const QVector<MTPDocument> &items, uint64 hash); void gifsReceived(const QVector<MTPDocument> &items, uint64 hash);
[[nodiscard]] std::vector<not_null<DocumentData*>> getPremiumList(
uint64 seed);
[[nodiscard]] std::vector<not_null<DocumentData*>> getListByEmoji( [[nodiscard]] std::vector<not_null<DocumentData*>> getListByEmoji(
std::vector<EmojiPtr> emoji, std::vector<EmojiPtr> emoji,
uint64 seed, uint64 seed,

View file

@ -1519,6 +1519,8 @@ emojiListNotModified#481eadfa = EmojiList;
emojiList#7a1e11d1 hash:long document_id:Vector<long> = EmojiList; emojiList#7a1e11d1 hash:long document_id:Vector<long> = EmojiList;
emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector<string> = EmojiGroup; emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector<string> = EmojiGroup;
emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector<string> = EmojiGroup;
emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup;
messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups; messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups;
messages.emojiGroups#881fb94b hash:int groups:Vector<EmojiGroup> = messages.EmojiGroups; messages.emojiGroups#881fb94b hash:int groups:Vector<EmojiGroup> = messages.EmojiGroups;
@ -1762,7 +1764,7 @@ channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options:
channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult;
channels.sponsoredMessageReportResultReported#ad798849 = 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; 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; 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--- ---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; 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<int> = Updates; messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector<int> = Updates;
messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool;
messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers;
messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups;
updates.getState#edd4882a = updates.State; 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; 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;

View file

@ -273,6 +273,11 @@ void GroupsStrip::fireChosenGroup() {
} // namespace } // namespace
const QString &PremiumGroupFakeEmoticon() {
static const auto result = u"*premium"_q;
return result;
}
SearchWithGroups::SearchWithGroups( SearchWithGroups::SearchWithGroups(
QWidget *parent, QWidget *parent,
SearchDescriptor descriptor) SearchDescriptor descriptor)
@ -359,7 +364,9 @@ void SearchWithGroups::initGroups() {
widget->chosen( widget->chosen(
) | rpl::start_with_next([=](const GroupsStrip::Chosen &chosen) { ) | rpl::start_with_next([=](const GroupsStrip::Chosen &chosen) {
_chosenGroup = chosen.group->iconId; _chosenGroup = chosen.group->iconId;
_query = chosen.group->emoticons; _query = (chosen.group->type == EmojiGroupType::Premium)
? std::vector{ PremiumGroupFakeEmoticon() }
: chosen.group->emoticons;
_debouncedQuery = chosen.group->emoticons; _debouncedQuery = chosen.group->emoticons;
_debounceTimer.cancel(); _debounceTimer.cancel();
scrollGroupsToIcon(chosen.iconLeft, chosen.iconRight); scrollGroupsToIcon(chosen.iconLeft, chosen.iconRight);

View file

@ -31,15 +31,24 @@ class RpWidget;
template <typename Widget> template <typename Widget>
class FadeWrap; class FadeWrap;
enum class EmojiGroupType {
Normal,
Greeting,
Premium,
};
struct EmojiGroup { struct EmojiGroup {
QString iconId; QString iconId;
std::vector<QString> emoticons; std::vector<QString> emoticons;
EmojiGroupType type = EmojiGroupType::Normal;
friend inline auto operator<=>( friend inline auto operator<=>(
const EmojiGroup &a, const EmojiGroup &a,
const EmojiGroup &b) = default; const EmojiGroup &b) = default;
}; };
[[nodiscard]] const QString &PremiumGroupFakeEmoticon();
struct SearchDescriptor { struct SearchDescriptor {
const style::TabbedSearch &st; const style::TabbedSearch &st;
rpl::producer<std::vector<EmojiGroup>> groups; rpl::producer<std::vector<EmojiGroup>> groups;