diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp index 5bb545d4c0..c0d4a7db49 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp @@ -65,6 +65,7 @@ constexpr auto kCollapsedRows = 3; constexpr auto kAppearDuration = 0.3; constexpr auto kCustomSearchLimit = 256; constexpr auto kColorPickerDelay = crl::time(500); +constexpr auto kSearchRequestDelay = 400; using Core::RecentEmojiId; using Core::RecentEmojiDocument; @@ -502,6 +503,7 @@ EmojiListWidget::EmojiListWidget( &session(), st::emojiPremiumLock)) , _collapsedBg(st::emojiPanExpand.height / 2, st().headerFg) +, _searchRequestTimer([=] { sendSearchRequest(); }) , _picker(this, st()) , _showPickerTimer([=] { showPicker(); }) , _previewTimer([=] { showPreview(); }) { @@ -647,6 +649,7 @@ void EmojiListWidget::applyNextSearchQuery() { if (!searching) { _searchResults.clear(); _searchCustomIds.clear(); + _searchSets.clear(); } resizeToWidth(width()); _recentShownCount = searching @@ -659,6 +662,7 @@ void EmojiListWidget::applyNextSearchQuery() { updateSelected(); }; if (_searchQuery.empty()) { + cancelSearchRequest(); finish(false); return; } @@ -667,11 +671,13 @@ void EmojiListWidget::applyNextSearchQuery() { if (_searchEmoji == _searchEmojiPrevious) { return; } + _searchEmoticon = QString(); + for (const auto emoji : plain) { + _searchEmoticon += emoji->text(); + } _searchResults.clear(); _searchCustomIds.clear(); - if (_mode != Mode::Full || session().premium()) { - appendPremiumSearchResults(); - } + _searchSets.clear(); if (_mode == Mode::Full) { for (const auto emoji : plain) { _searchResults.push_back({ @@ -679,6 +685,44 @@ void EmojiListWidget::applyNextSearchQuery() { }); } } + if (_mode != Mode::Full || session().premium()) { + appendPremiumSearchResults(); + } + if (_mode == Mode::Full) { + appendLocalPackSearchResults(); + } + + _searchQueryText = ranges::accumulate( + _searchQuery, + QString(), + [](QString a, const QString &b) { + return a.isEmpty() ? b : (a + ' ' + b); + }).trimmed(); + if (!_searchQueryText.isEmpty()) { + toggleSearchLoading(false); + if (const auto requestId = base::take(_searchCloudRequestId)) { + _api.request(requestId).cancel(); + } + if (const auto requestId = base::take(_searchSetsRequestId)) { + _api.request(requestId).cancel(); + } + _searchNextRequestQuery = _searchQueryText; + const auto cloudCached = _searchCloudCache.find(_searchQueryText) + != _searchCloudCache.cend(); + const auto setsCached = _searchSetsCache.find(_searchQueryText) + != _searchSetsCache.cend(); + if (cloudCached || setsCached) { + _searchRequestTimer.cancel(); + _searchRequestQuery = _searchQueryText; + fillCloudSearchResults(); + fillCloudSearchSets(); + if (!cloudCached || !setsCached) { + sendSearchRequest(); + } + } else { + _searchRequestTimer.callOnce(kSearchRequestDelay); + } + } } void EmojiListWidget::showPreview() { @@ -776,6 +820,338 @@ void EmojiListWidget::appendPremiumSearchResults() { } } +void EmojiListWidget::appendLocalPackSearchResults() { + const auto text = _searchQueryText.toLower(); + if (text.isEmpty()) { + return; + } + const auto test = session().isTestMode(); + const auto &sets = session().data().stickers().sets(); + const auto processSet = [&](uint64 setId) { + const auto it = sets.find(setId); + if (it == sets.end()) { + return; + } + const auto set = it->second.get(); + if (!(set->flags & Data::StickersSetFlag::Emoji)) { + return; + } + const auto title = set->title.toLower(); + if (!title.startsWith(text) + && !title.contains(u' ' + text)) { + return; + } + const auto &list = set->stickers.empty() + ? set->covers + : set->stickers; + for (const auto document : list) { + if (_searchResults.size() >= kCustomSearchLimit) { + return; + } + const auto sticker = document->sticker(); + if (!sticker) { + continue; + } + const auto id = document->id; + if (!_searchCustomIds.emplace(id).second) { + continue; + } + const auto statusId = EmojiStatusId{ id }; + _searchResults.push_back({ + .custom = resolveCustomEmoji( + statusId, + document, + SearchEmojiSectionSetId()), + .id = { RecentEmojiDocument{ .id = id, .test = test } }, + }); + } + }; + for (const auto setId + : session().data().stickers().emojiSetsOrder()) { + processSet(setId); + } + for (const auto setId + : session().data().stickers().featuredEmojiSetsOrder()) { + processSet(setId); + } +} + +void EmojiListWidget::toggleSearchLoading(bool loading) { + if (_search) { + _search->setLoading(loading); + } + if (_searchLoading != loading) { + _searchLoading = loading; + update(); + } +} + +void EmojiListWidget::sendSearchRequest() { + _searchRequestQuery = _searchQueryText; + if (_searchRequestQuery.isEmpty()) { + return; + } + + const auto cloudCached = _searchCloudCache.find( + _searchRequestQuery) != _searchCloudCache.cend(); + const auto setsCached = _searchSetsCache.find( + _searchRequestQuery) != _searchSetsCache.cend(); + if (cloudCached && setsCached) { + toggleSearchLoading(false); + return; + } + toggleSearchLoading(true); + + const auto hash = uint64(0); + if (!cloudCached) { + auto langCodes = QVector(); + const auto method = QGuiApplication::inputMethod(); + if (method) { + for (const auto &lang : method->locale().uiLanguages()) { + langCodes.push_back(MTP_string(lang)); + } + } + using Flag = MTPmessages_SearchStickers::Flag; + _searchCloudRequestId = _api.request(MTPmessages_SearchStickers( + MTP_flags(Flag::f_emojis), + MTP_string(_searchRequestQuery), + MTP_string(_searchEmoticon), + MTP_vector(langCodes), + MTP_int(0), + MTP_int(50), + MTP_long(hash) + )).done([=](const MTPmessages_FoundStickers &result) { + searchCloudResultsDone(result); + }).fail([=] { + _searchCloudRequestId = 0; + _searchCloudCache.emplace( + _searchRequestQuery, + std::vector()); + if (!_searchSetsRequestId) { + toggleSearchLoading(false); + showSearchResults(); + } + }).handleAllErrors().send(); + } + if (!setsCached) { + sendSearchSetsRequest(); + } +} + +void EmojiListWidget::sendSearchSetsRequest() { + const auto hash = uint64(0); + _searchSetsRequestId = _api.request( + MTPmessages_SearchEmojiStickerSets( + MTP_flags(0), + MTP_string(_searchRequestQuery), + MTP_long(hash)) + ).done([=](const MTPmessages_FoundStickerSets &result) { + searchSetsResultsDone(result); + }).fail([=] { + _searchSetsRequestId = 0; + if (!_searchCloudRequestId) { + toggleSearchLoading(false); + } + }).handleAllErrors().send(); +} + +void EmojiListWidget::cancelSearchRequest() { + toggleSearchLoading(false); + if (const auto requestId = base::take(_searchCloudRequestId)) { + _api.request(requestId).cancel(); + } + if (const auto requestId = base::take(_searchSetsRequestId)) { + _api.request(requestId).cancel(); + } + _searchRequestTimer.cancel(); + _searchRequestQuery = QString(); + _searchNextRequestQuery = QString(); + _searchCloudCache.clear(); + _searchSetsCache.clear(); + _searchSets.clear(); +} + +void EmojiListWidget::searchCloudResultsDone( + const MTPmessages_FoundStickers &result) { + _searchCloudRequestId = 0; + + result.match([&](const MTPDmessages_foundStickersNotModified &) { + LOG(("API: messages.foundStickersNotModified.")); + }, [&](const MTPDmessages_foundStickers &data) { + auto it = _searchCloudCache.find(_searchRequestQuery); + if (it == _searchCloudCache.cend()) { + it = _searchCloudCache.emplace( + _searchRequestQuery, + std::vector()).first; + } + + for (const auto &sticker : data.vstickers().v) { + if (const auto doc = session().data().processDocument( + sticker)) { + it->second.push_back(doc->id); + } + } + + if (!_searchSetsRequestId) { + toggleSearchLoading(false); + } + showSearchResults(); + }); +} + +void EmojiListWidget::searchSetsResultsDone( + const MTPmessages_FoundStickerSets &result) { + _searchSetsRequestId = 0; + if (!_searchCloudRequestId) { + toggleSearchLoading(false); + } + + result.match([&](const MTPDmessages_foundStickerSetsNotModified &) { + LOG(("API Error: " + "messages.foundStickerSetsNotModified not expected.")); + }, [&](const MTPDmessages_foundStickerSets &data) { + auto it = _searchSetsCache.find(_searchRequestQuery); + if (it == _searchSetsCache.cend()) { + it = _searchSetsCache.emplace( + _searchRequestQuery, + std::vector()).first; + } + for (const auto &setData : data.vsets().v) { + const auto set + = session().data().stickers().feedSet(setData); + if (set->stickers.empty() && set->covers.empty()) { + continue; + } + it->second.push_back(set->id); + } + showSearchResults(); + }); +} + +void EmojiListWidget::showSearchResults() { + clearSelection(); + + _searchResults.clear(); + _searchCustomIds.clear(); + _searchSets.clear(); + _searchEmoji.clear(); + + if (_mode == Mode::Full) { + auto plain = collectPlainSearchResults(); + for (const auto emoji : plain) { + _searchResults.push_back({ + .id = { emoji }, + }); + } + } + if (_mode != Mode::Full || session().premium()) { + appendPremiumSearchResults(); + } + fillCloudSearchResults(); + if (_mode == Mode::Full) { + appendLocalPackSearchResults(); + } + fillCloudSearchSets(); + + resizeToWidth(width()); + _recentShownCount = _searchResults.size(); + update(); + updateSelected(); +} + +void EmojiListWidget::fillCloudSearchResults() { + const auto it = _searchCloudCache.find(_searchRequestQuery); + if (it == _searchCloudCache.cend() || it->second.empty()) { + return; + } + const auto test = session().isTestMode(); + for (const auto id : it->second) { + if (_searchResults.size() >= kCustomSearchLimit) { + break; + } + if (!_searchCustomIds.emplace(id).second) { + continue; + } + const auto document = session().data().document(id); + const auto sticker = document->sticker(); + if (!sticker) { + continue; + } + const auto statusId = EmojiStatusId{ id }; + _searchResults.push_back({ + .custom = resolveCustomEmoji( + statusId, + document, + SearchEmojiSectionSetId()), + .id = { RecentEmojiDocument{ .id = id, .test = test } }, + }); + } +} + +void EmojiListWidget::fillCloudSearchSets() { + const auto it = _searchSetsCache.find(_searchRequestQuery); + if (it == _searchSetsCache.cend() || it->second.empty()) { + return; + } + const auto &sets = session().data().stickers().sets(); + const auto test = session().isTestMode(); + for (const auto setId : it->second) { + const auto setIt = sets.find(setId); + if (setIt == sets.end()) { + continue; + } + const auto set = setIt->second.get(); + const auto &list = set->stickers.empty() + ? set->covers + : set->stickers; + if (list.empty()) { + continue; + } + auto customs = std::vector(); + customs.reserve(list.size()); + for (const auto document : list) { + if (const auto sticker = document->sticker()) { + const auto statusId = EmojiStatusId{ document->id }; + customs.push_back({ + .custom = resolveCustomEmoji( + statusId, + document, + setId), + .document = document, + .emoji = Ui::Emoji::Find(sticker->alt), + }); + } + } + if (customs.empty()) { + continue; + } + const auto installed = !!(set->flags + & Data::StickersSetFlag::Installed); + _searchSets.push_back({ + .id = setId, + .set = set, + .thumbnailDocument = set->lookupThumbnailDocument(), + .title = set->title, + .list = std::move(customs), + .canRemove = installed, + }); + } +} + +EmojiListWidget::CustomSet &EmojiListWidget::searchSetBySection( + int section) { + Expects(section > 0 && section <= int(_searchSets.size())); + + return _searchSets[section - 1]; +} + +const EmojiListWidget::CustomSet &EmojiListWidget::searchSetBySection( + int section) const { + Expects(section > 0 && section <= int(_searchSets.size())); + + return _searchSets[section - 1]; +} + void EmojiListWidget::provideRecent( const std::vector &customRecentList) { clearSelection(); @@ -791,6 +1167,18 @@ void EmojiListWidget::repaintCustom(uint64 setId) { if (_searchMode) { if (repaintSearch) { update(); + } else { + enumerateSections([&](const SectionInfo &info) { + if (info.section > 0 + && searchSetBySection(info.section).id == setId) { + update( + 0, + info.rowsTop, + width(), + info.rowsBottom - info.rowsTop); + } + return true; + }); } return; } @@ -906,6 +1294,16 @@ void EmojiListWidget::unloadCustomIn(const SectionInfo &info) { } } return; + } else if (_searchMode && info.section > 0) { + auto &custom = searchSetBySection(info.section); + if (!custom.painted) { + return; + } + custom.painted = false; + for (const auto &single : custom.list) { + single.custom->unload(); + } + return; } else if (info.section < _staticCount) { return; } @@ -989,7 +1387,22 @@ bool EmojiListWidget::enumerateSections(Callback callback) const { if (_searchMode) { info.section = i; info.count = _searchResults.size(); - return next(); + if (!next()) { + return false; + } + ++i; + for (auto §ion : _searchSets) { + info.section = i++; + info.premiumRequired = section.premiumRequired; + info.count = int(section.list.size()); + info.collapsed = !section.expanded + && (!section.canRemove || section.premiumRequired) + && (info.count > _columnCount * kCollapsedRows); + if (!next()) { + return false; + } + } + return true; } for (; i != _staticCount; ++i) { info.section = i; @@ -1041,7 +1454,9 @@ EmojiListWidget::SectionInfo EmojiListWidget::sectionInfoByOffset( } int EmojiListWidget::sectionsCount() const { - return _searchMode ? 1 : (_staticCount + int(_custom.size())); + return _searchMode + ? (1 + int(_searchSets.size())) + : (_staticCount + int(_custom.size())); } void EmojiListWidget::setSingleSize(QSize size) { @@ -1406,7 +1821,11 @@ void EmojiListWidget::paint( auto selectedButton = std::get_if(!v::is_null(_pressed) ? &_pressed : &_selected); - if (_searchResults.empty() && _searchMode) { + if (_searchResults.empty() + && _searchSets.empty() + && _searchMode + && !_searchLoading + && !_searchRequestTimer.isActive()) { paintEmptySearchResults(p); } enumerateSections([&](const SectionInfo &info) { @@ -1427,7 +1846,9 @@ void EmojiListWidget::paint( if (info.section > 0 && clip.top() < info.rowsTop) { p.setFont(st::emojiPanHeaderFont); p.setPen(st().headerFg); - auto titleText = (info.section < _staticCount) + auto titleText = (_searchMode && info.section > 0) + ? searchSetBySection(info.section).title + : (info.section < _staticCount) ? ChatHelpers::EmojiCategoryTitle(info.section)(tr::now) : _custom[info.section - _staticCount].title; auto titleWidth = st::emojiPanHeaderFont->width(titleText); @@ -1508,8 +1929,15 @@ void EmojiListWidget::paint( } _overBg.paint(p, QRect(tl, st::emojiPanArea)); } - if (_searchMode) { + if (_searchMode && info.section == 0) { drawRecent(p, context, w, _searchResults[index]); + } else if (_searchMode && info.section > 0) { + drawSearchSetCustom( + p, + context, + w, + info.section, + index); } else if (info.section == int(Section::Recent)) { drawRecent(p, context, w, _recent[index]); } else if (info.section < _staticCount) { @@ -1644,6 +2072,22 @@ void EmojiListWidget::drawCustom( entry.custom->paint(p, *_emojiPaintContext); } +void EmojiListWidget::drawSearchSetCustom( + QPainter &p, + const ExpandingContext &context, + QPoint position, + int section, + int index) { + auto &custom = searchSetBySection(section); + custom.painted = true; + auto &entry = custom.list[index]; + _emojiPaintContext->scale = context.progress; + _emojiPaintContext->position = position + + _innerPosition + + _customPosition; + entry.custom->paint(p, *_emojiPaintContext); +} + bool EmojiListWidget::checkPickerHide() { if (!_picker->isHidden() && !v::is_null(_pickerSelected)) { _picker->hideAnimated(); @@ -1664,7 +2108,7 @@ EmojiListWidget::ResolvedCustom EmojiListWidget::lookupCustomEmoji( EmojiListWidget::ResolvedCustom EmojiListWidget::lookupCustomEmoji( int index, int section) const { - if (_searchMode) { + if (_searchMode && section == 0) { if (index < _searchResults.size()) { const auto document = std::get_if( &_searchResults[index].id.data); @@ -1673,6 +2117,13 @@ EmojiListWidget::ResolvedCustom EmojiListWidget::lookupCustomEmoji( } } return {}; + } else if (_searchMode && section > 0) { + const auto &set = searchSetBySection(section); + if (index < int(set.list.size())) { + auto &entry = set.list[index]; + return { entry.document, entry.collectible }; + } + return {}; } else if (section == int(Section::Recent) && index < _recent.size()) { const auto &recent = _recent[index]; if (recent.collectible) { @@ -1698,11 +2149,15 @@ EmojiListWidget::ResolvedCustom EmojiListWidget::lookupCustomEmoji( EmojiPtr EmojiListWidget::lookupOverEmoji(const OverEmoji *over) const { const auto section = over ? over->section : -1; const auto index = over ? over->index : -1; - return _searchMode + return (_searchMode && section == 0) ? ((index < _searchResults.size() && v::is(_searchResults[index].id.data)) ? v::get(_searchResults[index].id.data) : nullptr) + : (_searchMode && section > 0) + ? ((index < int(searchSetBySection(section).list.size())) + ? searchSetBySection(section).list[index].emoji + : nullptr) : (section == int(Section::Recent) && index < _recent.size() && v::is(_recent[index].id.data)) @@ -1824,10 +2279,13 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) { if (const auto over = std::get_if(&_selected)) { const auto section = over->section; const auto index = over->index; - if (section >= _staticCount - && sectionInfo(section).collapsed + if (sectionInfo(section).collapsed && index + 1 == _columnCount * kCollapsedRows) { - _custom[section - _staticCount].expanded = true; + if (_searchMode && section > 0) { + searchSetBySection(section).expanded = true; + } else if (section >= _staticCount) { + _custom[section - _staticCount].expanded = true; + } resizeToWidth(width()); update(); return; @@ -1840,13 +2298,20 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) { selectCustom(lookupChosen(custom, over)); } } else if (const auto set = std::get_if(&pressed)) { - Assert(set->section >= _staticCount - && set->section < _staticCount + _custom.size()); - displaySet(_custom[set->section - _staticCount].id); + const auto setId = (_searchMode && set->section > 0) + ? searchSetBySection(set->section).id + : (set->section >= _staticCount) + ? _custom[set->section - _staticCount].id + : uint64(0); + if (setId) { + displaySet(setId); + } } else if (auto button = std::get_if(&pressed)) { Assert(hasButton(button->section)); const auto id = hasColorButton(button->section) ? 0 + : (_searchMode && button->section > 0) + ? searchSetBySection(button->section).id : _custom[button->section - _staticCount].id; if (hasColorButton(button->section)) { _pickerSelected = pressed; @@ -2021,6 +2486,12 @@ QRect EmojiListWidget::colorButtonRect(const SectionInfo &info) const { } bool EmojiListWidget::hasRemoveButton(int index) const { + if (_searchMode) { + if (index > 0 && index <= int(_searchSets.size())) { + return searchSetBySection(index).canRemove; + } + return false; + } if (index < _staticCount || index >= _staticCount + _custom.size()) { return false; @@ -2056,6 +2527,13 @@ QRect EmojiListWidget::removeButtonRect(const SectionInfo &info) const { } bool EmojiListWidget::hasAddButton(int index) const { + if (_searchMode) { + if (index > 0 && index <= int(_searchSets.size())) { + const auto &set = searchSetBySection(index); + return !set.canRemove && !set.premiumRequired; + } + return false; + } if (index < _staticCount || index >= _staticCount + _custom.size()) { return false; @@ -2072,6 +2550,12 @@ QRect EmojiListWidget::addButtonRect(int index) const { } bool EmojiListWidget::hasUnlockButton(int index) const { + if (_searchMode) { + if (index > 0 && index <= int(_searchSets.size())) { + return searchSetBySection(index).premiumRequired; + } + return false; + } if (index < _staticCount || index >= _staticCount + _custom.size()) { return false; @@ -2081,13 +2565,19 @@ bool EmojiListWidget::hasUnlockButton(int index) const { } QRect EmojiListWidget::unlockButtonRect(int index) const { - Expects(index >= _staticCount - && index < _staticCount + _custom.size()); + Expects((_searchMode + && index > 0 + && index <= int(_searchSets.size())) + || (index >= _staticCount + && index < _staticCount + _custom.size())); return buttonRect(sectionInfo(index), rightButton(index)); } bool EmojiListWidget::hasButton(int index) const { + if (_searchMode) { + return (index > 0 && index <= int(_searchSets.size())); + } if (hasColorButton(index)) { return true; } else if (index >= _staticCount @@ -2121,6 +2611,15 @@ QRect EmojiListWidget::buttonRect( } auto EmojiListWidget::rightButton(int index) const -> const RightButton & { + if (_searchMode) { + Expects(index > 0 && index <= int(_searchSets.size())); + + return hasAddButton(index) + ? _add + : searchSetBySection(index).canRemove + ? _restore + : _unlock; + } Expects(index >= _staticCount && index < _staticCount + _custom.size()); @@ -2272,6 +2771,7 @@ void EmojiListWidget::processHideFinished() { _picker->hideFast(); _pickerSelected = v::null; } + cancelSearchRequest(); unloadAllCustom(); clearSelection(); } @@ -2646,7 +3146,9 @@ int EmojiListWidget::paintButtonGetWidth( if (!hasButton(info.section)) { return 0; } - auto &ripple = (info.section >= _staticCount) + auto &ripple = (_searchMode && info.section > 0) + ? searchSetBySection(info.section).ripple + : (info.section >= _staticCount) ? _custom[info.section - _staticCount].ripple : _colorAllRipple; const auto colorAll = hasColorButton(info.section); @@ -2801,9 +3303,13 @@ void EmojiListWidget::setSelected(OverState newSelected) { void EmojiListWidget::setPressed(OverState newPressed) { if (auto button = std::get_if(&_pressed)) { Assert(hasColorButton(button->section) + || (_searchMode && button->section > 0 + && button->section <= int(_searchSets.size())) || (button->section >= _staticCount && button->section < _staticCount + _custom.size())); - auto &ripple = (button->section >= _staticCount) + auto &ripple = (_searchMode && button->section > 0) + ? searchSetBySection(button->section).ripple + : (button->section >= _staticCount) ? _custom[button->section - _staticCount].ripple : _colorAllRipple; if (ripple) { @@ -2813,9 +3319,13 @@ void EmojiListWidget::setPressed(OverState newPressed) { _pressed = newPressed; if (auto button = std::get_if(&_pressed)) { Assert(hasColorButton(button->section) + || (_searchMode && button->section > 0 + && button->section <= int(_searchSets.size())) || (button->section >= _staticCount && button->section < _staticCount + _custom.size())); - auto &ripple = (button->section >= _staticCount) + auto &ripple = (_searchMode && button->section > 0) + ? searchSetBySection(button->section).ripple + : (button->section >= _staticCount) ? _custom[button->section - _staticCount].ripple : _colorAllRipple; if (!ripple) { @@ -2935,8 +3445,10 @@ uint64 EmojiListWidget::sectionSetId(int section) const { || section < _staticCount || (section - _staticCount) < _custom.size()); - return _searchMode + return (_searchMode && section == 0) ? SearchEmojiSectionSetId() + : (_searchMode && section > 0) + ? searchSetBySection(section).id : (section < _staticCount) ? EmojiSectionSetId(static_cast
(section)) : _custom[section - _staticCount].id; diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h index 59f623a8c3..c8deb74bb7 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h @@ -299,6 +299,18 @@ private: void setupSearch(); [[nodiscard]] std::vector collectPlainSearchResults(); void appendPremiumSearchResults(); + void appendLocalPackSearchResults(); + void sendSearchRequest(); + void sendSearchSetsRequest(); + void cancelSearchRequest(); + void toggleSearchLoading(bool loading); + void searchCloudResultsDone(const MTPmessages_FoundStickers &result); + void searchSetsResultsDone(const MTPmessages_FoundStickerSets &result); + void showSearchResults(); + void fillCloudSearchResults(); + void fillCloudSearchSets(); + [[nodiscard]] CustomSet &searchSetBySection(int section); + [[nodiscard]] const CustomSet &searchSetBySection(int section) const; void ensureLoaded(int section); void updateSelected(); void setSelected(OverState newSelected); @@ -346,6 +358,12 @@ private: QPoint position, int set, int index); + void drawSearchSetCustom( + QPainter &p, + const ExpandingContext &context, + QPoint position, + int section, + int index); void validateEmojiPaintContext(const ExpandingContext &context); [[nodiscard]] bool hasColorButton(int index) const; [[nodiscard]] QRect colorButtonRect(int index) const; @@ -459,11 +477,21 @@ private: rpl::event_stream> _searchQueries; std::vector _nextSearchQuery; std::vector _searchQuery; + QString _searchQueryText; base::flat_set _searchEmoji; base::flat_set _searchEmojiPrevious; base::flat_set _searchCustomIds; std::vector _searchResults; bool _searchMode = false; + std::map> _searchCloudCache; + std::map> _searchSetsCache; + std::vector _searchSets; + QString _searchRequestQuery; + QString _searchNextRequestQuery; + QString _searchEmoticon; + mtpRequestId _searchCloudRequestId = 0; + mtpRequestId _searchSetsRequestId = 0; + bool _searchLoading = false; int _rowsTop = 0; int _rowsLeft = 0; @@ -483,6 +511,7 @@ private: OverState _pickerSelected; QPoint _lastMousePos; + base::Timer _searchRequestTimer; object_ptr _picker; base::Timer _showPickerTimer; base::Timer _previewTimer;