Implement effects search.

This commit is contained in:
John Preston 2024-05-13 15:00:46 +04:00
parent bbb3a51b74
commit d102d256a9
7 changed files with 115 additions and 54 deletions

View file

@ -583,9 +583,14 @@ void EmojiListWidget::setupSearch() {
InvokeQueued(this, [=] { InvokeQueued(this, [=] {
applyNextSearchQuery(); applyNextSearchQuery();
}); });
_searchQueries.fire_copy(_nextSearchQuery);
}, session, type); }, session, type);
} }
rpl::producer<std::vector<QString>> EmojiListWidget::searchQueries() const {
return _searchQueries.events();
}
void EmojiListWidget::applyNextSearchQuery() { void EmojiListWidget::applyNextSearchQuery() {
if (_searchQuery == _nextSearchQuery) { if (_searchQuery == _nextSearchQuery) {
return; return;
@ -834,7 +839,8 @@ void EmojiListWidget::unloadCustomIn(const SectionInfo &info) {
object_ptr<TabbedSelector::InnerFooter> EmojiListWidget::createFooter() { object_ptr<TabbedSelector::InnerFooter> EmojiListWidget::createFooter() {
Expects(_footer == nullptr); Expects(_footer == nullptr);
if (_mode == EmojiListMode::RecentReactions) { if (_mode == EmojiListMode::RecentReactions
|| _mode == EmojiListMode::MessageEffects) {
return { nullptr }; return { nullptr };
} }
@ -2131,7 +2137,7 @@ void EmojiListWidget::refreshRecent() {
} }
void EmojiListWidget::refreshCustom() { void EmojiListWidget::refreshCustom() {
if (_mode == Mode::RecentReactions) { if (_mode == Mode::RecentReactions || _mode == Mode::MessageEffects) {
return; return;
} }
auto old = base::take(_custom); auto old = base::take(_custom);

View file

@ -77,6 +77,7 @@ enum class EmojiListMode {
UserpicBuilder, UserpicBuilder,
BackgroundEmoji, BackgroundEmoji,
PeerTitle, PeerTitle,
MessageEffects,
}; };
struct EmojiListDescriptor { struct EmojiListDescriptor {
@ -146,6 +147,8 @@ public:
base::unique_qptr<Ui::PopupMenu> fillContextMenu( base::unique_qptr<Ui::PopupMenu> fillContextMenu(
const SendMenu::Details &details) override; const SendMenu::Details &details) override;
[[nodiscard]] rpl::producer<std::vector<QString>> searchQueries() const;
protected: protected:
void visibleTopBottomUpdated( void visibleTopBottomUpdated(
int visibleTop, int visibleTop,
@ -418,6 +421,7 @@ private:
bool _colorAllRippleForced = false; bool _colorAllRippleForced = false;
rpl::lifetime _colorAllRippleForcedLifetime; rpl::lifetime _colorAllRippleForcedLifetime;
rpl::event_stream<std::vector<QString>> _searchQueries;
std::vector<QString> _nextSearchQuery; std::vector<QString> _nextSearchQuery;
std::vector<QString> _searchQuery; std::vector<QString> _searchQuery;
base::flat_set<EmojiPtr> _searchEmoji; base::flat_set<EmojiPtr> _searchEmoji;

View file

@ -547,7 +547,7 @@ int StickersListWidget::countDesiredHeight(int newWidth) {
} }
void StickersListWidget::sendSearchRequest() { void StickersListWidget::sendSearchRequest() {
if (_searchRequestId || _searchNextQuery.isEmpty()) { if (_searchRequestId || _searchNextQuery.isEmpty() || _isEffects) {
return; return;
} }
@ -556,14 +556,12 @@ void StickersListWidget::sendSearchRequest() {
auto it = _searchCache.find(_searchQuery); auto it = _searchCache.find(_searchQuery);
if (it != _searchCache.cend()) { if (it != _searchCache.cend()) {
_search->setLoading(false); toggleSearchLoading(false);
return; return;
} }
toggleSearchLoading(true);
_search->setLoading(true);
if (_searchQuery == Ui::PremiumGroupFakeEmoticon()) { if (_searchQuery == Ui::PremiumGroupFakeEmoticon()) {
_search->setLoading(false); toggleSearchLoading(false);
_searchRequestId = 0; _searchRequestId = 0;
_searchCache.emplace(_searchQuery, std::vector<uint64>()); _searchCache.emplace(_searchQuery, std::vector<uint64>());
showSearchResults(); showSearchResults();
@ -579,7 +577,7 @@ void StickersListWidget::sendSearchRequest() {
searchResultsDone(result); searchResultsDone(result);
}).fail([=] { }).fail([=] {
// show error? // show error?
_search->setLoading(false); toggleSearchLoading(false);
_searchRequestId = 0; _searchRequestId = 0;
}).handleAllErrors().send(); }).handleAllErrors().send();
} }
@ -593,7 +591,10 @@ void StickersListWidget::searchForSets(
return; return;
} }
if (query == Ui::PremiumGroupFakeEmoticon()) { _filterStickersCornerEmoji.clear();
if (_isEffects) {
filterEffectsByEmoji(std::move(emoji));
} else if (query == Ui::PremiumGroupFakeEmoticon()) {
_filteredStickers = session().data().stickers().getPremiumList(0); _filteredStickers = session().data().stickers().getPremiumList(0);
} else { } else {
_filteredStickers = session().data().stickers().getListByEmoji( _filteredStickers = session().data().stickers().getListByEmoji(
@ -602,7 +603,7 @@ void StickersListWidget::searchForSets(
true); true);
} }
if (_searchQuery != cleaned) { if (_searchQuery != cleaned) {
_search->setLoading(false); toggleSearchLoading(false);
if (const auto requestId = base::take(_searchRequestId)) { if (const auto requestId = base::take(_searchRequestId)) {
_api.request(requestId).cancel(); _api.request(requestId).cancel();
} }
@ -618,13 +619,14 @@ void StickersListWidget::searchForSets(
} }
void StickersListWidget::cancelSetsSearch() { void StickersListWidget::cancelSetsSearch() {
_search->setLoading(false); toggleSearchLoading(false);
if (const auto requestId = base::take(_searchRequestId)) { if (const auto requestId = base::take(_searchRequestId)) {
_api.request(requestId).cancel(); _api.request(requestId).cancel();
} }
_searchRequestTimer.cancel(); _searchRequestTimer.cancel();
_searchQuery = _searchNextQuery = QString(); _searchQuery = _searchNextQuery = QString();
_filteredStickers.clear(); _filteredStickers.clear();
_filterStickersCornerEmoji.clear();
_searchCache.clear(); _searchCache.clear();
refreshSearchRows(nullptr); refreshSearchRows(nullptr);
} }
@ -655,8 +657,9 @@ void StickersListWidget::refreshSearchRows(
}); });
fillFilteredStickersRow(); fillFilteredStickersRow();
fillLocalSearchRows(_searchNextQuery); if (!_isEffects) {
fillLocalSearchRows(_searchNextQuery);
}
if (!cloudSets && _searchNextQuery.isEmpty()) { if (!cloudSets && _searchNextQuery.isEmpty()) {
showStickerSet(!_mySets.empty() showStickerSet(!_mySets.empty()
? _mySets[0].id ? _mySets[0].id
@ -665,11 +668,10 @@ void StickersListWidget::refreshSearchRows(
} }
setSection(Section::Search); setSection(Section::Search);
if (cloudSets) { if (!_isEffects && cloudSets) {
fillCloudSearchRows(*cloudSets); fillCloudSearchRows(*cloudSets);
} }
refreshIcons(ValidateIconAnimations::Scroll); refreshIcons(ValidateIconAnimations::Scroll);
_lastMousePosition = QCursor::pos(); _lastMousePosition = QCursor::pos();
resizeToWidth(width()); resizeToWidth(width());
@ -735,7 +737,7 @@ void StickersListWidget::fillFilteredStickersRow() {
SearchEmojiSectionSetId(), SearchEmojiSectionSetId(),
nullptr, nullptr,
Data::StickersSetFlag::Special, Data::StickersSetFlag::Special,
QString(), // title _isEffects ? tr::lng_effect_stickers_title(tr::now) : QString(),
QString(), // shortName QString(), // shortName
_filteredStickers.size(), _filteredStickers.size(),
false, // externalLayout false, // externalLayout
@ -758,6 +760,12 @@ void StickersListWidget::addSearchRow(not_null<StickersSet*> set) {
std::move(elements)); std::move(elements));
} }
void StickersListWidget::toggleSearchLoading(bool loading) {
if (_search) {
_search->setLoading(loading);
}
}
void StickersListWidget::takeHeavyData( void StickersListWidget::takeHeavyData(
std::vector<Set> &to, std::vector<Set> &to,
std::vector<Set> &from) { std::vector<Set> &from) {
@ -839,7 +847,7 @@ auto StickersListWidget::shownSets() -> std::vector<Set> & {
void StickersListWidget::searchResultsDone( void StickersListWidget::searchResultsDone(
const MTPmessages_FoundStickerSets &result) { const MTPmessages_FoundStickerSets &result) {
_search->setLoading(false); toggleSearchLoading(false);
_searchRequestId = 0; _searchRequestId = 0;
if (result.type() == mtpc_messages_foundStickerSetsNotModified) { if (result.type() == mtpc_messages_foundStickerSetsNotModified) {
@ -1476,9 +1484,14 @@ void StickersListWidget::paintSticker(
} }
auto cornerPainted = false; auto cornerPainted = false;
if (set.id == Data::Stickers::RecentSetId && !_cornerEmoji.empty()) { const auto corner = (set.id == Data::Stickers::RecentSetId)
Assert(index < _cornerEmoji.size()); ? &_cornerEmoji
if (const auto emoji = _cornerEmoji[index]) { : (set.id == SearchEmojiSectionSetId())
? &_filterStickersCornerEmoji
: nullptr;
if (corner && !corner->empty()) {
Assert(index < corner->size());
if (const auto emoji = (*corner)[index]) {
const auto size = Ui::Emoji::GetSizeNormal(); const auto size = Ui::Emoji::GetSizeNormal();
const auto ratio = style::DevicePixelRatio(); const auto ratio = style::DevicePixelRatio();
const auto radius = st::roundRadiusSmall; const auto radius = st::roundRadiusSmall;
@ -2492,14 +2505,14 @@ void StickersListWidget::updateSelected() {
} }
bool StickersListWidget::setHasTitle(const Set &set) const { bool StickersListWidget::setHasTitle(const Set &set) const {
if (set.id == Data::Stickers::FavedSetId if (_isEffects) {
return true;
} else if (set.id == Data::Stickers::FavedSetId
|| set.id == SearchEmojiSectionSetId()) { || set.id == SearchEmojiSectionSetId()) {
return false; return false;
} else if (set.id == Data::Stickers::RecentSetId) { } else if (set.id == Data::Stickers::RecentSetId) {
return !_mySets.empty() return !_mySets.empty()
&& (_isMasks && (_isMasks || (_mySets[0].id == Data::Stickers::FavedSetId));
|| _isEffects
|| (_mySets[0].id == Data::Stickers::FavedSetId));
} }
return true; return true;
} }
@ -2581,9 +2594,10 @@ void StickersListWidget::showStickerSet(uint64 setId) {
const auto guard = gsl::finally([&] { _showingSetById = false; }); const auto guard = gsl::finally([&] { _showingSetById = false; });
clearSelection(); clearSelection();
if (_search if (!_searchQuery.isEmpty() || !_searchNextQuery.isEmpty()) {
&& (!_searchQuery.isEmpty() || !_searchNextQuery.isEmpty())) { if (_search) {
_search->cancel(); _search->cancel();
}
cancelSetsSearch(); cancelSetsSearch();
} }
@ -2686,14 +2700,18 @@ void StickersListWidget::setupSearch() {
? TabbedSearchType::Greeting ? TabbedSearchType::Greeting
: TabbedSearchType::Stickers; : TabbedSearchType::Stickers;
_search = MakeSearch(this, st(), [=](std::vector<QString> &&query) { _search = MakeSearch(this, st(), [=](std::vector<QString> &&query) {
auto set = base::flat_set<EmojiPtr>(); applySearchQuery(std::move(query));
auto text = ranges::accumulate(query, QString(), []( }, session, type);
}
void StickersListWidget::applySearchQuery(std::vector<QString> &&query) {
auto set = base::flat_set<EmojiPtr>();
auto text = ranges::accumulate(query, QString(), [](
QString a, QString a,
QString b) { QString b) {
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, type);
} }
void StickersListWidget::displaySet(uint64 setId) { void StickersListWidget::displaySet(uint64 setId) {
@ -2768,6 +2786,32 @@ bool StickersListWidget::mySetsEmpty() const {
return _mySets.empty(); return _mySets.empty();
} }
void StickersListWidget::filterEffectsByEmoji(
const std::vector<EmojiPtr> &emoji) {
_filteredStickers.clear();
_filterStickersCornerEmoji.clear();
if (_mySets.empty()
|| _mySets.front().id != Data::Stickers::RecentSetId
|| _mySets.front().stickers.empty()) {
return;
}
const auto &list = _mySets.front().stickers;
auto all = base::flat_set<EmojiPtr>();
for (const auto &one : emoji) {
all.emplace(one->original());
}
const auto count = int(list.size());
_filteredStickers.reserve(count);
_filterStickersCornerEmoji.reserve(count);
for (auto i = 0; i != count; ++i) {
Assert(i < _cornerEmoji.size());
if (all.contains(_cornerEmoji[i])) {
_filteredStickers.push_back(list[i].document);
_filterStickersCornerEmoji.push_back(_cornerEmoji[i]);
}
}
}
StickersListWidget::~StickersListWidget() = default; StickersListWidget::~StickersListWidget() = default;
object_ptr<Ui::BoxContent> MakeConfirmRemoveSetBox( object_ptr<Ui::BoxContent> MakeConfirmRemoveSetBox(

View file

@ -127,6 +127,8 @@ public:
bool mySetsEmpty() const; bool mySetsEmpty() const;
void applySearchQuery(std::vector<QString> &&query);
~StickersListWidget(); ~StickersListWidget();
protected: protected:
@ -261,12 +263,13 @@ private:
void updateSelected(); void updateSelected();
void setSelected(OverState newSelected); void setSelected(OverState newSelected);
void setPressed(OverState newPressed); void setPressed(OverState newPressed);
std::unique_ptr<Ui::RippleAnimation> createButtonRipple(int section); [[nodiscard]] std::unique_ptr<Ui::RippleAnimation> createButtonRipple(
QPoint buttonRippleTopLeft(int section) const; int section);
[[nodiscard]] QPoint buttonRippleTopLeft(int section) const;
std::vector<Set> &shownSets(); [[nodiscard]] std::vector<Set> &shownSets();
const std::vector<Set> &shownSets() const; [[nodiscard]] const std::vector<Set> &shownSets() const;
int featuredRowHeight() const; [[nodiscard]] int featuredRowHeight() const;
void checkVisibleFeatured(int visibleTop, int visibleBottom); void checkVisibleFeatured(int visibleTop, int visibleBottom);
void readVisibleFeatured(int visibleTop, int visibleBottom); void readVisibleFeatured(int visibleTop, int visibleBottom);
@ -324,6 +327,7 @@ private:
[[nodiscard]] const Data::StickersSetsOrder &defaultSetsOrder() const; [[nodiscard]] const Data::StickersSetsOrder &defaultSetsOrder() const;
[[nodiscard]] Data::StickersSetsOrder &defaultSetsOrderRef(); [[nodiscard]] Data::StickersSetsOrder &defaultSetsOrderRef();
void filterEffectsByEmoji(const std::vector<EmojiPtr> &emoji);
enum class AppendSkip { enum class AppendSkip {
None, None,
@ -356,6 +360,7 @@ private:
void fillLocalSearchRows(const QString &query); void fillLocalSearchRows(const QString &query);
void fillCloudSearchRows(const std::vector<uint64> &cloudSets); void fillCloudSearchRows(const std::vector<uint64> &cloudSets);
void addSearchRow(not_null<Data::StickersSet*> set); void addSearchRow(not_null<Data::StickersSet*> set);
void toggleSearchLoading(bool loading);
void showPreview(); void showPreview();
@ -431,6 +436,7 @@ private:
std::unique_ptr<StickerPremiumMark> _premiumMark; std::unique_ptr<StickerPremiumMark> _premiumMark;
std::vector<not_null<DocumentData*>> _filteredStickers; std::vector<not_null<DocumentData*>> _filteredStickers;
std::vector<EmojiPtr> _filterStickersCornerEmoji;
std::map<QString, std::vector<uint64>> _searchCache; std::map<QString, std::vector<uint64>> _searchCache;
std::vector<std::pair<uint64, QStringList>> _searchIndex; std::vector<std::pair<uint64, QStringList>> _searchIndex;
base::Timer _searchRequestTimer; base::Timer _searchRequestTimer;

View file

@ -1460,9 +1460,7 @@ int TabbedSelector::Inner::resizeGetHeight(int newWidth) {
} }
int TabbedSelector::Inner::minimalHeight() const { int TabbedSelector::Inner::minimalHeight() const {
return (_minimalHeight > 0) return _minimalHeight.value_or(defaultMinimalHeight());
? _minimalHeight
: defaultMinimalHeight();
} }
int TabbedSelector::Inner::defaultMinimalHeight() const { int TabbedSelector::Inner::defaultMinimalHeight() const {

View file

@ -422,7 +422,7 @@ private:
int _visibleTop = 0; int _visibleTop = 0;
int _visibleBottom = 0; int _visibleBottom = 0;
int _minimalHeight = 0; std::optional<int> _minimalHeight;
rpl::event_stream<int> _scrollToRequests; rpl::event_stream<int> _scrollToRequests;
rpl::event_stream<bool> _disableScrollRequests; rpl::event_stream<bool> _disableScrollRequests;

View file

@ -211,7 +211,9 @@ Selector::Selector(
reactions, reactions,
(reactions.customAllowed (reactions.customAllowed
? ChatHelpers::EmojiListMode::FullReactions ? ChatHelpers::EmojiListMode::FullReactions
: ChatHelpers::EmojiListMode::RecentReactions), : reactions.stickers.empty()
? ChatHelpers::EmojiListMode::RecentReactions
: ChatHelpers::EmojiListMode::MessageEffects),
{}, {},
std::move(about), std::move(about),
iconFactory, iconFactory,
@ -1075,15 +1077,6 @@ void Selector::createList() {
_shadow->update(); _shadow->update();
} }
}, _list->lifetime()); }, _list->lifetime());
if (_stickers) {
_stickers->scrollToRequests(
) | rpl::start_with_next([=](int y) {
_scroll->scrollToY(_list->height() + y);
if (_shadow) {
_shadow->update();
}
}, _stickers->lifetime());
}
_scroll->setGeometry(inner.marginsRemoved({ _scroll->setGeometry(inner.marginsRemoved({
_st.margin.left(), _st.margin.left(),
@ -1091,7 +1084,17 @@ void Selector::createList() {
0, 0,
0, 0,
})); }));
_list->setMinimalHeight(geometry.width(), _scroll->height()); if (_stickers) {
_list->setMinimalHeight(geometry.width(), 0);
_stickers->setMinimalHeight(geometry.width(), 0);
_list->searchQueries(
) | rpl::start_with_next([=](std::vector<QString> &&query) {
_stickers->applySearchQuery(std::move(query));
}, _stickers->lifetime());
} else {
_list->setMinimalHeight(geometry.width(), _scroll->height());
}
updateVisibleTopBottom(); updateVisibleTopBottom();
} }