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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -211,7 +211,9 @@ Selector::Selector(
reactions,
(reactions.customAllowed
? ChatHelpers::EmojiListMode::FullReactions
: ChatHelpers::EmojiListMode::RecentReactions),
: reactions.stickers.empty()
? ChatHelpers::EmojiListMode::RecentReactions
: ChatHelpers::EmojiListMode::MessageEffects),
{},
std::move(about),
iconFactory,
@ -1075,15 +1077,6 @@ void Selector::createList() {
_shadow->update();
}
}, _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({
_st.margin.left(),
@ -1091,7 +1084,17 @@ void Selector::createList() {
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();
}