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
)).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,
};

View file

@ -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<QString> &&query) {
_nextSearchQuery = std::move(query);
InvokeQueued(this, [=] {
applyNextSearchQuery();
});
}, session, (_mode == Mode::EmojiStatus), _mode == Mode::UserpicBuilder);
}, session, type);
}
void EmojiListWidget::applyNextSearchQuery() {

View file

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

View file

@ -547,6 +547,15 @@ void StickersListWidget::sendSearchRequest() {
}
_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);
_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<QString> &&query) {
auto set = base::flat_set<EmojiPtr>();
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) {

View file

@ -307,16 +307,17 @@ std::unique_ptr<Ui::TabbedSearch> MakeSearch(
const style::EmojiPan &st,
Fn<void(std::vector<QString>&&)> callback,
not_null<Main::Session*> session,
bool statusCategories,
bool profilePhotoCategories) {
TabbedSearchType type) {
using Descriptor = Ui::SearchDescriptor;
const auto owner = &session->data();
auto result = std::make_unique<Ui::TabbedSearch>(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,

View file

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

View file

@ -153,6 +153,11 @@ auto EmojiStatuses::statusGroupsValue() const -> rpl::producer<Groups> {
return _statusGroups.data.value();
}
auto EmojiStatuses::stickerGroupsValue() const -> rpl::producer<Groups> {
const_cast<EmojiStatuses*>(this)->requestStickerGroups();
return _stickerGroups.data.value();
}
auto EmojiStatuses::profilePhotoGroupsValue() const
-> rpl::producer<Groups> {
const_cast<EmojiStatuses*>(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<Ui::EmojiGroup>();
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<decltype(data)>()
? Ui::EmojiGroupType::Greeting
: Ui::EmojiGroupType::Normal),
});
});
}
return result;

View file

@ -60,9 +60,11 @@ public:
using Groups = std::vector<Ui::EmojiGroup>;
[[nodiscard]] rpl::producer<Groups> emojiGroupsValue() const;
[[nodiscard]] rpl::producer<Groups> statusGroupsValue() const;
[[nodiscard]] rpl::producer<Groups> stickerGroupsValue() const;
[[nodiscard]] rpl::producer<Groups> 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;

View file

@ -1132,6 +1132,141 @@ void Stickers::gifsReceived(const QVector<MTPDocument> &items, uint64 hash) {
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<EmojiPtr> emoji,
uint64 seed,

View file

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

View file

@ -1519,6 +1519,8 @@ emojiListNotModified#481eadfa = EmojiList;
emojiList#7a1e11d1 hash:long document_id:Vector<long> = EmojiList;
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.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.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<int> = 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;

View file

@ -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);

View file

@ -31,15 +31,24 @@ class RpWidget;
template <typename Widget>
class FadeWrap;
enum class EmojiGroupType {
Normal,
Greeting,
Premium,
};
struct EmojiGroup {
QString iconId;
std::vector<QString> 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<std::vector<EmojiGroup>> groups;