Fix some bugs in new chats search.

This commit is contained in:
John Preston 2024-05-19 12:05:32 +04:00
parent dd5643ac67
commit 6a8edefc87
6 changed files with 188 additions and 231 deletions

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "dialogs/dialogs_inner_widget.h" #include "dialogs/dialogs_inner_widget.h"
#include "dialogs/dialogs_three_state_icon.h" #include "dialogs/dialogs_three_state_icon.h"
#include "dialogs/ui/chat_search_tabs.h"
#include "dialogs/ui/dialogs_layout.h" #include "dialogs/ui/dialogs_layout.h"
#include "dialogs/ui/dialogs_stories_content.h" #include "dialogs/ui/dialogs_stories_content.h"
#include "dialogs/ui/dialogs_video_userpic.h" #include "dialogs/ui/dialogs_video_userpic.h"
@ -747,6 +748,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
p.fillRect(dialogsClip, currentBg()); p.fillRect(dialogsClip, currentBg());
} }
} else if (_state == WidgetState::Filtered) { } else if (_state == WidgetState::Filtered) {
auto top = 0;
if (!_hashtagResults.empty()) { if (!_hashtagResults.empty()) {
auto from = floorclamp(r.y(), st::mentionHeight, 0, _hashtagResults.size()); auto from = floorclamp(r.y(), st::mentionHeight, 0, _hashtagResults.size());
auto to = ceilclamp(r.y() + r.height(), st::mentionHeight, 0, _hashtagResults.size()); auto to = ceilclamp(r.y() + r.height(), st::mentionHeight, 0, _hashtagResults.size());
@ -791,6 +793,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
p.drawText(htagleft + firstwidth, st::mentionTop + st::mentionFont->ascent, second); p.drawText(htagleft + firstwidth, st::mentionTop + st::mentionFont->ascent, second);
} }
p.translate(0, st::mentionHeight); p.translate(0, st::mentionHeight);
top += st::mentionHeight;
} }
} }
} }
@ -800,7 +803,9 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
auto to = std::min( auto to = std::min(
filteredIndex(r.y() + r.height() - skip) + 1, filteredIndex(r.y() + r.height() - skip) + 1,
int(_filterResults.size())); int(_filterResults.size()));
p.translate(0, filteredHeight(from)); const auto height = filteredHeight(from);
p.translate(0, height);
top += height;
for (; from < to; ++from) { for (; from < to; ++from) {
const auto selected = isPressed() const auto selected = isPressed()
? (from == _filteredPressed) ? (from == _filteredPressed)
@ -808,6 +813,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
const auto row = _filterResults[from].row; const auto row = _filterResults[from].row;
paintRow(row, selected, !activeEntry.fullId); paintRow(row, selected, !activeEntry.fullId);
p.translate(0, row->height()); p.translate(0, row->height());
top += row->height();
} }
} }
@ -817,11 +823,13 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
p.setPen(st::searchedBarFg); p.setPen(st::searchedBarFg);
p.drawTextLeft(st::searchedBarPosition.x(), st::searchedBarPosition.y(), width(), tr::lng_search_global_results(tr::now)); p.drawTextLeft(st::searchedBarPosition.x(), st::searchedBarPosition.y(), width(), tr::lng_search_global_results(tr::now));
p.translate(0, st::searchedBarHeight); p.translate(0, st::searchedBarHeight);
top += st::searchedBarHeight;
auto skip = peerSearchOffset(); auto skip = peerSearchOffset();
auto from = floorclamp(r.y() - skip, st::dialogsRowHeight, 0, _peerSearchResults.size()); auto from = floorclamp(r.y() - skip, st::dialogsRowHeight, 0, _peerSearchResults.size());
auto to = ceilclamp(r.y() + r.height() - skip, st::dialogsRowHeight, 0, _peerSearchResults.size()); auto to = ceilclamp(r.y() + r.height() - skip, st::dialogsRowHeight, 0, _peerSearchResults.size());
p.translate(0, from * st::dialogsRowHeight); p.translate(0, from * st::dialogsRowHeight);
top += from * st::dialogsRowHeight;
if (from < _peerSearchResults.size()) { if (from < _peerSearchResults.size()) {
const auto activePeer = activeEntry.key.peer(); const auto activePeer = activeEntry.key.peer();
for (; from < to; ++from) { for (; from < to; ++from) {
@ -844,6 +852,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
.paused = videoPaused, .paused = videoPaused,
}); });
p.translate(0, st::dialogsRowHeight); p.translate(0, st::dialogsRowHeight);
top += st::dialogsRowHeight;
} }
} }
} }
@ -857,29 +866,15 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
.paused = videoPaused, .paused = videoPaused,
}); });
p.translate(0, searchInChatSkip()); p.translate(0, searchInChatSkip());
if (_waitingForSearch && _searchResults.empty()) { top += searchInChatSkip();
p.fillRect( if (_searchResults.empty()) {
0, p.fillRect(0, 0, fullWidth, st::lineWidth, st::shadowFg);
0,
fullWidth,
st::searchedBarHeight,
st::searchedBarBg);
p.setFont(st::searchedBarFont);
p.setPen(st::searchedBarFg);
p.drawTextLeft(
st::searchedBarPosition.x(),
st::searchedBarPosition.y(),
width(),
tr::lng_dlg_search_for_messages(tr::now));
p.translate(0, st::searchedBarHeight);
} }
} }
const auto showUnreadInSearchResults = uniqueSearchResults(); const auto showUnreadInSearchResults = uniqueSearchResults();
if (!_waitingForSearch || !_searchResults.empty()) { if (!_searchResults.empty()) {
const auto text = _searchResults.empty() const auto text = showUnreadInSearchResults
? tr::lng_search_no_results(tr::now)
: showUnreadInSearchResults
? u"Search results"_q ? u"Search results"_q
: tr::lng_search_found_results( : tr::lng_search_found_results(
tr::now, tr::now,
@ -890,11 +885,13 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
p.setPen(st::searchedBarFg); p.setPen(st::searchedBarFg);
p.drawTextLeft(st::searchedBarPosition.x(), st::searchedBarPosition.y(), width(), text); p.drawTextLeft(st::searchedBarPosition.x(), st::searchedBarPosition.y(), width(), text);
p.translate(0, st::searchedBarHeight); p.translate(0, st::searchedBarHeight);
top += st::searchedBarHeight;
auto skip = searchedOffset(); auto skip = searchedOffset();
auto from = floorclamp(r.y() - skip, _st->height, 0, _searchResults.size()); auto from = floorclamp(r.y() - skip, _st->height, 0, _searchResults.size());
auto to = ceilclamp(r.y() + r.height() - skip, _st->height, 0, _searchResults.size()); auto to = ceilclamp(r.y() + r.height() - skip, _st->height, 0, _searchResults.size());
p.translate(0, from * _st->height); p.translate(0, from * _st->height);
top += from * _st->height;
if (from < _searchResults.size()) { if (from < _searchResults.size()) {
for (; from < to; ++from) { for (; from < to; ++from) {
const auto &result = _searchResults[from]; const auto &result = _searchResults[from];
@ -920,6 +917,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
.displayUnreadInfo = showUnreadInSearchResults, .displayUnreadInfo = showUnreadInSearchResults,
}); });
p.translate(0, _st->height); p.translate(0, _st->height);
top += _st->height;
} }
} }
} }
@ -1127,10 +1125,11 @@ void InnerWidget::paintSearchInChat(
auto top = 0; auto top = 0;
if (_searchTags) { if (_searchTags) {
const auto height = _searchTags->height(); const auto height = _searchTags->height();
top += st::dialogsSearchTagBottom;
p.fillRect(0, top, width(), height, currentBg()); p.fillRect(0, top, width(), height, currentBg());
const auto position = QPoint(_searchTagsLeft, 0); const auto position = QPoint(_searchTagsLeft, top);
_searchTags->paint(p, position, context.now, context.paused); _searchTags->paint(p, position, context.now, context.paused);
top += height; top += height - st::dialogsSearchTagBottom;
} }
p.setFont(st::searchedBarFont); p.setFont(st::searchedBarFont);
auto fullRect = QRect(0, top, width(), height - top); auto fullRect = QRect(0, top, width(), height - top);
@ -1279,7 +1278,9 @@ void InnerWidget::selectByMouse(QPoint globalPosition) {
_lastMousePosition = globalPosition; _lastMousePosition = globalPosition;
_lastRowLocalMouseX = local.x(); _lastRowLocalMouseX = local.x();
const auto tagBase = QPoint(_searchTagsLeft, searchInChatOffset()); const auto tagBase = QPoint(
_searchTagsLeft,
searchInChatOffset() + st::dialogsSearchTagBottom);
const auto tagPoint = local - tagBase; const auto tagPoint = local - tagBase;
const auto inTags = _searchTags const auto inTags = _searchTags
&& QRect( && QRect(
@ -1895,7 +1896,7 @@ void InnerWidget::moveCancelSearchButtons() {
st::columnMinimalWidthLeft - _narrowWidth); st::columnMinimalWidthLeft - _narrowWidth);
const auto left = widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchFromUser->width(); const auto left = widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchFromUser->width();
const auto top = (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2; const auto top = (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2;
const auto skip = st::searchedBarHeight + (_searchTags ? _searchTags->height() : 0); const auto skip = (_searchTags ? _searchTags->height() : 0);
_cancelSearchFromUser->moveToLeft(left, skip + top); _cancelSearchFromUser->moveToLeft(left, skip + top);
} }
@ -2460,6 +2461,74 @@ void InnerWidget::applySearchState(SearchState state) {
withSameQuery.query = _searchState.query; withSameQuery.query = _searchState.query;
const auto otherChanged = (_searchState != withSameQuery); const auto otherChanged = (_searchState != withSameQuery);
const auto ignoreInChat = (state.tab == ChatSearchTab::MyMessages)
|| (state.tab == ChatSearchTab::PublicPosts);
const auto sublist = ignoreInChat ? nullptr : state.inChat.sublist();
const auto peer = ignoreInChat
? nullptr
: sublist
? session().user().get()
: state.inChat.peer();
if (const auto migrateFrom = peer ? peer->migrateFrom() : nullptr) {
_searchInMigrated = peer->owner().history(migrateFrom);
} else {
_searchInMigrated = nullptr;
}
if (peer && peer->isSelf()) {
const auto reactions = &peer->owner().reactions();
_searchTags = std::make_unique<SearchTags>(
&peer->owner(),
reactions->myTagsValue(sublist),
state.tags);
_searchTags->selectedChanges(
) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) {
_searchState.tags = std::move(list);
}, _searchTags->lifetime());
_searchTags->repaintRequests() | rpl::start_with_next([=] {
const auto height = _searchTags->height();
update(0, searchInChatOffset(), width(), height);
}, _searchTags->lifetime());
_searchTags->menuRequests(
) | rpl::start_with_next([=](Data::ReactionId id) {
HistoryView::ShowTagInListMenu(
&_menu,
_lastMousePosition.value_or(QCursor::pos()),
this,
id,
_controller);
}, _searchTags->lifetime());
_searchTags->heightValue() | rpl::skip(
1
) | rpl::start_with_next([=] {
refresh();
moveCancelSearchButtons();
}, _searchTags->lifetime());
} else {
_searchTags = nullptr;
state.tags.clear();
}
_searchFromShown = ignoreInChat
? nullptr
: sublist
? sublist->peer().get()
: state.fromPeer;
if (state.inChat) {
onHashtagFilterUpdate(QStringView());
}
if (_searchFromShown) {
_cancelSearchFromUser->show();
_searchFromUserUserpic = _searchFromShown->createUserpicView();
} else {
_cancelSearchFromUser->hide();
_searchFromUserUserpic = {};
}
refreshSearchInChatLabel();
moveCancelSearchButtons();
_searchState = std::move(state); _searchState = std::move(state);
auto newFilter = _searchState.query; auto newFilter = _searchState.query;
const auto mentionsSearch = (newFilter == u"@"_q); const auto mentionsSearch = (newFilter == u"@"_q);
@ -2569,7 +2638,9 @@ InnerWidget::~InnerWidget() {
} }
void InnerWidget::clearSearchResults(bool clearPeerSearchResults) { void InnerWidget::clearSearchResults(bool clearPeerSearchResults) {
if (clearPeerSearchResults) _peerSearchResults.clear(); if (clearPeerSearchResults) {
_peerSearchResults.clear();
}
_searchResults.clear(); _searchResults.clear();
_searchResultsLifetime.destroy(); _searchResultsLifetime.destroy();
_searchResultsHistories.clear(); _searchResultsHistories.clear();
@ -2807,7 +2878,8 @@ void InnerWidget::searchReceived(
SearchRequestType type, SearchRequestType type,
int fullCount) { int fullCount) {
const auto uniquePeers = uniqueSearchResults(); const auto uniquePeers = uniqueSearchResults();
if (type == SearchRequestType::FromStart || type == SearchRequestType::PeerFromStart) { if (type == SearchRequestType::FromStart
|| type == SearchRequestType::PeerFromStart) {
clearSearchResults(false); clearSearchResults(false);
} }
const auto isMigratedSearch = (type == SearchRequestType::MigratedFromStart) const auto isMigratedSearch = (type == SearchRequestType::MigratedFromStart)
@ -3066,81 +3138,6 @@ bool InnerWidget::hasFilteredResults() const {
return !_filterResults.empty() && _hashtagResults.empty(); return !_filterResults.empty() && _hashtagResults.empty();
} }
void InnerWidget::searchInChat(
Key key,
PeerData *from,
std::vector<Data::ReactionId> tags) {
_searchInMigrated = nullptr;
const auto sublist = key.sublist();
const auto peer = sublist ? session().user().get() : key.peer();
if (peer) {
if (const auto migrateTo = peer->migrateTo()) {
const auto to = peer->owner().history(migrateTo);
return searchInChat(to, from, tags);
} else if (const auto migrateFrom = peer->migrateFrom()) {
_searchInMigrated = peer->owner().history(migrateFrom);
}
if (peer->isSelf()) {
const auto reactions = &peer->owner().reactions();
_searchTags = std::make_unique<SearchTags>(
&peer->owner(),
reactions->myTagsValue(sublist),
tags);
_searchTags->selectedChanges(
) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) {
_searchState.tags = std::move(list);
}, _searchTags->lifetime());
_searchTags->repaintRequests() | rpl::start_with_next([=] {
const auto height = _searchTags->height();
update(0, searchInChatOffset(), width(), height);
}, _searchTags->lifetime());
_searchTags->menuRequests(
) | rpl::start_with_next([=](Data::ReactionId id) {
HistoryView::ShowTagInListMenu(
&_menu,
_lastMousePosition.value_or(QCursor::pos()),
this,
id,
_controller);
}, _searchTags->lifetime());
_searchTags->heightValue() | rpl::skip(
1
) | rpl::start_with_next([=] {
refresh();
moveCancelSearchButtons();
}, _searchTags->lifetime());
} else {
_searchTags = nullptr;
_searchState.tags.clear();
}
} else {
_searchTags = nullptr;
_searchState.tags.clear();
}
_searchState.inChat = key;
_searchState.fromPeer = from;
_searchFromShown = key.sublist() ? key.sublist()->peer().get() : from;
if (_searchState.inChat) {
onHashtagFilterUpdate(QStringView());
}
if (_searchFromShown) {
_cancelSearchFromUser->show();
_searchFromUserUserpic = _searchFromShown->createUserpicView();
} else {
_cancelSearchFromUser->hide();
_searchFromUserUserpic = {};
}
if (_searchState.inChat || _searchState.fromPeer) {
refreshSearchInChatLabel();
}
moveCancelSearchButtons();
}
auto InnerWidget::searchTagsChanges() const auto InnerWidget::searchTagsChanges() const
-> rpl::producer<std::vector<Data::ReactionId>> { -> rpl::producer<std::vector<Data::ReactionId>> {
return _searchTags return _searchTags

View file

@ -146,10 +146,6 @@ public:
[[nodiscard]] bool hasFilteredResults() const; [[nodiscard]] bool hasFilteredResults() const;
void applySearchState(SearchState state); void applySearchState(SearchState state);
void searchInChat(
Key key,
PeerData *from,
std::vector<Data::ReactionId> tags);
[[nodiscard]] auto searchTagsChanges() const [[nodiscard]] auto searchTagsChanges() const
-> rpl::producer<std::vector<Data::ReactionId>>; -> rpl::producer<std::vector<Data::ReactionId>>;
@ -386,6 +382,7 @@ private:
const Ui::Text::String &text) const; const Ui::Text::String &text) const;
void refreshSearchInChatLabel(); void refreshSearchInChatLabel();
void repaintSearchResult(int index); void repaintSearchResult(int index);
void paintEmpty(QPainter &p, int top);
Ui::VideoUserpic *validateVideoUserpic(not_null<Row*> row); Ui::VideoUserpic *validateVideoUserpic(not_null<Row*> row);
Ui::VideoUserpic *validateVideoUserpic(not_null<History*> history); Ui::VideoUserpic *validateVideoUserpic(not_null<History*> history);

View file

@ -375,7 +375,7 @@ Widget::Widget(
_search->changes( _search->changes(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
applySearchUpdate(); crl::on_main(this, [=] { applySearchUpdate(); });
}, _search->lifetime()); }, _search->lifetime());
_search->submits( _search->submits(
@ -524,7 +524,7 @@ Widget::Widget(
void Widget::chosenRow(const ChosenRow &row) { void Widget::chosenRow(const ChosenRow &row) {
storiesToggleExplicitExpand(false); storiesToggleExplicitExpand(false);
if (!currentSearchQuery().isEmpty()) { if (!_searchState.query.isEmpty()) {
if (const auto history = row.key.history()) { if (const auto history = row.key.history()) {
session().recentPeers().bump(history->peer); session().recentPeers().bump(history->peer);
} }
@ -1240,6 +1240,7 @@ void Widget::updateSearchTabs() {
applySearchState(std::move(copy)); applySearchState(std::move(copy));
}, _searchTabs->lifetime()); }, _searchTabs->lifetime());
} }
const auto sublist = _searchState.inChat.sublist();
const auto topic = _searchState.inChat.topic(); const auto topic = _searchState.inChat.topic();
const auto peer = _searchState.inChat.owningHistory() const auto peer = _searchState.inChat.owningHistory()
? _searchState.inChat.owningHistory()->peer.get() ? _searchState.inChat.owningHistory()->peer.get()
@ -1258,6 +1259,10 @@ void Widget::updateSearchTabs() {
? Ui::Text::SingleCustomEmoji( ? Ui::Text::SingleCustomEmoji(
session().data().customEmojiManager().peerUserpicEmojiData( session().data().customEmojiManager().peerUserpicEmojiData(
peer)) peer))
: sublist
? Ui::Text::SingleCustomEmoji(
session().data().customEmojiManager().peerUserpicEmojiData(
sublist->peer()))
: TextWithEntities(); : TextWithEntities();
const auto myShortLabel = DefaultShortLabel(ChatSearchTab::MyMessages); const auto myShortLabel = DefaultShortLabel(ChatSearchTab::MyMessages);
const auto publicShortLabel = _searchingHashtag const auto publicShortLabel = _searchingHashtag
@ -1275,12 +1280,17 @@ void Widget::updateSearchTabs() {
? ChatSearchTab::ThisPeer ? ChatSearchTab::ThisPeer
: ChatSearchTab::MyMessages; : ChatSearchTab::MyMessages;
} }
const auto peerTabType = (peer && peer->isBroadcast())
? ChatSearchPeerTabType::Channel
: (peer && (peer->isChat() || peer->isMegagroup()))
? ChatSearchPeerTabType::Group
: ChatSearchPeerTabType::Chat;
_searchTabs->setTabShortLabels({ _searchTabs->setTabShortLabels({
{ ChatSearchTab::ThisTopic, topicShortLabel }, { ChatSearchTab::ThisTopic, topicShortLabel },
{ ChatSearchTab::ThisPeer, peerShortLabel }, { ChatSearchTab::ThisPeer, peerShortLabel },
{ ChatSearchTab::MyMessages, myShortLabel }, { ChatSearchTab::MyMessages, myShortLabel },
{ ChatSearchTab::PublicPosts, publicShortLabel }, { ChatSearchTab::PublicPosts, publicShortLabel },
}, _searchState.tab); }, _searchState.tab, peerTabType);
updateControlsGeometry(); updateControlsGeometry();
} }
@ -1611,7 +1621,7 @@ void Widget::jumpToTop(bool belowPinned) {
if (session().supportMode()) { if (session().supportMode()) {
return; return;
} }
if ((currentSearchQuery().trimmed().isEmpty() && !_searchState.inChat)) { if ((_searchState.query.trimmed().isEmpty() && !_searchState.inChat)) {
auto to = 0; auto to = 0;
if (belowPinned) { if (belowPinned) {
const auto list = _openedForum const auto list = _openedForum
@ -1749,7 +1759,7 @@ void Widget::updateStoriesVisibility() {
|| _childList || _childList
|| _searchHasFocus || _searchHasFocus
|| _searchSuggestionsLocked || _searchSuggestionsLocked
|| !currentSearchQuery().isEmpty() || !_searchState.query.isEmpty()
|| _searchState.inChat || _searchState.inChat
|| _stories->empty(); || _stories->empty();
if (_stories->isHidden() != hidden) { if (_stories->isHidden() != hidden) {
@ -1952,16 +1962,22 @@ void Widget::loadMoreBlockedByDate() {
bool Widget::search(bool inCache) { bool Widget::search(bool inCache) {
auto result = false; auto result = false;
const auto query = currentSearchQuery().trimmed(); const auto query = _searchState.query.trimmed();
const auto inPeer = searchInPeer(); const auto inPeer = searchInPeer();
const auto fromPeer = searchFromPeer(); const auto fromPeer = searchFromPeer();
const auto &inTags = searchInTags(); const auto &inTags = searchInTags();
const auto tab = _searchState.tab; const auto tab = _searchState.tab;
const auto fromStartType = inPeer
? SearchRequestType::PeerFromStart
: SearchRequestType::FromStart;
const auto skipRequest = (query.isEmpty() && !fromPeer && inTags.empty()) const auto skipRequest = (query.isEmpty() && !fromPeer && inTags.empty())
|| (tab == ChatSearchTab::PublicPosts && query.size() < 2); || (tab == ChatSearchTab::PublicPosts && query.size() < 2);
if (skipRequest) { if (skipRequest) {
cancelSearchRequest(); cancelSearchRequest();
searchApplyEmpty(fromStartType, 0);
_api.request(base::take(_peerSearchRequest)).cancel(); _api.request(base::take(_peerSearchRequest)).cancel();
_peerSearchQuery = QString();
peerSearchApplyEmpty(0);
_api.request(base::take(_topicSearchRequest)).cancel(); _api.request(base::take(_topicSearchRequest)).cancel();
return true; return true;
} else if (inCache) { } else if (inCache) {
@ -1981,9 +1997,7 @@ bool Widget::search(bool inCache) {
_searchFull = _searchFullMigrated = false; _searchFull = _searchFullMigrated = false;
cancelSearchRequest(); cancelSearchRequest();
searchReceived( searchReceived(
(inPeer fromStartType,
? SearchRequestType::PeerFromStart
: SearchRequestType::FromStart),
i->second, i->second,
0); 0);
result = true; result = true;
@ -2109,21 +2123,14 @@ bool Widget::search(bool inCache) {
)).done([=](const MTPcontacts_Found &result, mtpRequestId requestId) { )).done([=](const MTPcontacts_Found &result, mtpRequestId requestId) {
peerSearchReceived(result, requestId); peerSearchReceived(result, requestId);
}).fail([=](const MTP::Error &error, mtpRequestId requestId) { }).fail([=](const MTP::Error &error, mtpRequestId requestId) {
peopleFailed(error, requestId); peerSearchFailed(error, requestId);
}).send(); }).send();
_peerSearchQueries.emplace(_peerSearchRequest, _peerSearchQuery); _peerSearchQueries.emplace(_peerSearchRequest, _peerSearchQuery);
} }
} else { } else {
_api.request(base::take(_peerSearchRequest)).cancel(); _api.request(base::take(_peerSearchRequest)).cancel();
_peerSearchQuery = peerQuery; _peerSearchQuery = peerQuery;
_peerSearchFull = true; peerSearchApplyEmpty(0);
peerSearchReceived(
MTP_contacts_found(
MTP_vector<MTPPeer>(0),
MTP_vector<MTPPeer>(0),
MTP_vector<MTPChat>(0),
MTP_vector<MTPUser>(0)),
0);
} }
if (searchForTopicsRequired(peerQuery)) { if (searchForTopicsRequired(peerQuery)) {
if (inCache) { if (inCache) {
@ -2170,64 +2177,7 @@ void Widget::showMainMenu() {
void Widget::searchMessages(SearchState state) { void Widget::searchMessages(SearchState state) {
applySearchState(std::move(state)); applySearchState(std::move(state));
session().local().saveRecentSearchHashtags(state.query); session().local().saveRecentSearchHashtags(_searchState.query);
//if (_childList) {
// const auto forum = controller()->shownForum().current();
// const auto topic = inChat.topic();
// if ((forum && forum->channel() == inChat.peer())
// || (topic && topic->forum() == forum)) {
// _childList->searchMessages(query, inChat);
// return;
// }
// hideChildList();
//}
//if (_openedFolder) {
// controller()->closeFolder();
//}
//auto tags = Data::SearchTagsFromQuery(query);
//if (!tags.empty()) {
// if (!inChat.sublist()) {
// inChat = session().data().history(session().user());
// }
// query = QString();
//}
//const auto inChatChanged = [&] {
// const auto inPeer = inChat.peer();
// const auto inTopic = inChat.topic();
// if (!inTopic
// && _openedForum
// && inPeer == _openedForum->channel()
// && _subsectionTopBar
// && _subsectionTopBar->searchMode()) {
// return false;
// } else if ((inTopic || (inPeer && !inPeer->isForum()))
// && (inChat == _searchState.inChat)) {
// return false;
// } else if (inPeer) {
// if (const auto to = inPeer->migrateTo()) {
// if (to == _searchState.inChat.peer()
// && !_searchState.inChat.topic()) {
// return false;
// }
// }
// }
// return true;
//}();
//if ((currentSearchQuery() != query)
// || inChatChanged
// || _searchState.tags != tags) {
// if (inChat) {
// cancelSearch();
// setSearchInChat(inChat, nullptr, tags);
// }
// setSearchQuery(query);
// applySearchUpdate(true);
// _searchTimer.cancel();
// searchMessages();
// session().local().saveRecentSearchHashtags(query);
//}
} }
void Widget::searchTopics() { void Widget::searchTopics() {
@ -2574,18 +2524,34 @@ void Widget::peerSearchReceived(
} }
} }
void Widget::searchApplyEmpty(SearchRequestType type, mtpRequestId id) {
_searchFull = _searchFullMigrated = true;
searchReceived(
type,
MTP_messages_messages(
MTP_vector<MTPMessage>(),
MTP_vector<MTPChat>(),
MTP_vector<MTPUser>()),
id);
}
void Widget::peerSearchApplyEmpty(mtpRequestId id) {
_peerSearchFull = true;
peerSearchReceived(
MTP_contacts_found(
MTP_vector<MTPPeer>(0),
MTP_vector<MTPPeer>(0),
MTP_vector<MTPChat>(0),
MTP_vector<MTPUser>(0)),
id);
}
void Widget::searchFailed( void Widget::searchFailed(
SearchRequestType type, SearchRequestType type,
const MTP::Error &error, const MTP::Error &error,
mtpRequestId requestId) { mtpRequestId requestId) {
if (error.type() == u"SEARCH_QUERY_EMPTY"_q) { if (error.type() == u"SEARCH_QUERY_EMPTY"_q) {
searchReceived( searchApplyEmpty(type, requestId);
type,
MTP_messages_messages(
MTP_vector<MTPMessage>(),
MTP_vector<MTPChat>(),
MTP_vector<MTPUser>()),
requestId);
} else if (_searchRequest == requestId) { } else if (_searchRequest == requestId) {
_searchRequest = 0; _searchRequest = 0;
if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) {
@ -2596,8 +2562,8 @@ void Widget::searchFailed(
} }
} }
void Widget::peopleFailed(const MTP::Error &error, mtpRequestId requestId) { void Widget::peerSearchFailed(const MTP::Error &error, mtpRequestId id) {
if (_peerSearchRequest == requestId) { if (_peerSearchRequest == id) {
_peerSearchRequest = 0; _peerSearchRequest = 0;
_peerSearchFull = true; _peerSearchFull = true;
} }
@ -2702,40 +2668,33 @@ void Widget::listScrollUpdated() {
} }
void Widget::updateCancelSearch() { void Widget::updateCancelSearch() {
const auto shown = !_search->getLastText().isEmpty() const auto shown = !_searchState.query.isEmpty()
|| (!_searchState.inChat || (!_searchState.inChat
&& (_searchHasFocus || _searchSuggestionsLocked)); && (_searchHasFocus || _searchSuggestionsLocked));
_cancelSearch->toggle(shown, anim::type::normal); _cancelSearch->toggle(shown, anim::type::normal);
} }
bool Widget::fixSearchQuery() { QString Widget::validateSearchQuery() {
if (_fixingSearchQuery) {
return false;
}
_fixingSearchQuery = true;
const auto query = currentSearchQuery(); const auto query = currentSearchQuery();
if (_searchState.tab == ChatSearchTab::PublicPosts) { if (_searchState.tab == ChatSearchTab::PublicPosts) {
_searchingHashtag = true;
const auto fixed = FixHashtagSearchQuery( const auto fixed = FixHashtagSearchQuery(
query, query,
currentSearchQueryCursorPosition()); currentSearchQueryCursorPosition());
if (fixed.text != query) { if (fixed.text != query) {
setSearchQuery(fixed.text, fixed.cursorPosition); setSearchQuery(fixed.text, fixed.cursorPosition);
} }
_searchingHashtag = true; return fixed.text;
} else if (_searchingHashtag != IsHashtagSearchQuery(query)) { } else if (_searchingHashtag != IsHashtagSearchQuery(query)) {
_searchingHashtag = !_searchingHashtag; _searchingHashtag = !_searchingHashtag;
updateSearchTabs(); updateSearchTabs();
} }
_fixingSearchQuery = false; return query;
return true;
} }
void Widget::applySearchUpdate() { void Widget::applySearchUpdate() {
if (!fixSearchQuery()) {
return;
}
auto copy = _searchState; auto copy = _searchState;
copy.query = currentSearchQuery(); copy.query = validateSearchQuery();
applySearchState(std::move(copy)); applySearchState(std::move(copy));
if (_chooseFromUser->toggled() if (_chooseFromUser->toggled()
@ -2755,7 +2714,7 @@ void Widget::updateForceDisplayWide() {
controller()->setChatsForceDisplayWide(_searchHasFocus controller()->setChatsForceDisplayWide(_searchHasFocus
|| (_subsectionTopBar && _subsectionTopBar->searchHasFocus()) || (_subsectionTopBar && _subsectionTopBar->searchHasFocus())
|| _searchSuggestionsLocked || _searchSuggestionsLocked
|| !currentSearchQuery().isEmpty() || !_searchState.query.isEmpty()
|| _searchState.inChat); || _searchState.inChat);
} }
@ -2961,12 +2920,10 @@ bool Widget::applySearchState(SearchState state) {
updateSearchTabs(); updateSearchTabs();
} }
if (queryChanged || inChatChanged) { if (queryChanged || inChatChanged) {
updateJumpToDateVisibility();
updateStoriesVisibility(); updateStoriesVisibility();
} }
if (fromPeerChanged) { updateJumpToDateVisibility();
updateSearchFromVisibility(); updateSearchFromVisibility();
}
updateLockUnlockPosition(); updateLockUnlockPosition();
if ((state.query.isEmpty() && !state.fromPeer && state.tags.empty()) if ((state.query.isEmpty() && !state.fromPeer && state.tags.empty())
@ -2988,6 +2945,7 @@ bool Widget::applySearchState(SearchState state) {
controller()->closeFolder(); controller()->closeFolder();
} }
setSearchQuery(_searchState.query);
_inner->applySearchState(_searchState); _inner->applySearchState(_searchState);
if (!_postponeProcessSearchFocusChange) { if (!_postponeProcessSearchFocusChange) {
@ -3009,7 +2967,7 @@ bool Widget::applySearchState(SearchState state) {
&& _lastSearchText == HistoryView::SwitchToChooseFromQuery()) { && _lastSearchText == HistoryView::SwitchToChooseFromQuery()) {
cancelSearch(); cancelSearch();
} }
if (_searchState.inChat || !_search->getLastText().isEmpty()) { if (_searchState.inChat || !_searchState.query.isEmpty()) {
_search->setFocus(); _search->setFocus();
} else { } else {
setInnerFocus(); setInnerFocus();
@ -3138,7 +3096,7 @@ void Widget::updateLockUnlockVisibility(anim::type animated) {
|| _searchHasFocus || _searchHasFocus
|| _searchSuggestionsLocked || _searchSuggestionsLocked
|| _searchState.inChat || _searchState.inChat
|| !_search->getLastText().isEmpty(); || !_searchState.query.isEmpty();
if (_lockUnlock->toggled() == hidden) { if (_lockUnlock->toggled() == hidden) {
const auto stories = _stories && !_stories->empty(); const auto stories = _stories && !_stories->empty();
_lockUnlock->toggle( _lockUnlock->toggle(
@ -3157,7 +3115,7 @@ void Widget::updateLoadMoreChatsVisibility() {
} }
const auto hidden = (_openedFolder != nullptr) const auto hidden = (_openedFolder != nullptr)
|| (_openedForum != nullptr) || (_openedForum != nullptr)
|| !currentSearchQuery().isEmpty(); || !_searchState.query.isEmpty();
if (_loadMoreChats->isHidden() != hidden) { if (_loadMoreChats->isHidden() != hidden) {
_loadMoreChats->setVisible(!hidden); _loadMoreChats->setVisible(!hidden);
updateControlsGeometry(); updateControlsGeometry();
@ -3170,7 +3128,7 @@ void Widget::updateJumpToDateVisibility(bool fast) {
} }
_jumpToDate->toggle( _jumpToDate->toggle(
(_searchState.inChat && _search->getLastText().isEmpty()), (searchInPeer() && _searchState.query.isEmpty()),
fast ? anim::type::instant : anim::type::normal); fast ? anim::type::instant : anim::type::normal);
} }
@ -3617,6 +3575,10 @@ void Widget::clearSearchField() {
} }
void Widget::setSearchQuery(const QString &query, int cursorPosition) { void Widget::setSearchQuery(const QString &query, int cursorPosition) {
if (query.isEmpty()) {
clearSearchField();
return;
}
if (cursorPosition < 0) { if (cursorPosition < 0) {
cursorPosition = query.size(); cursorPosition = query.size();
} }
@ -3666,7 +3628,6 @@ bool Widget::cancelSearch() {
_lastSearchPeer = nullptr; _lastSearchPeer = nullptr;
_lastSearchId = _lastSearchMigratedId = 0; _lastSearchId = _lastSearchMigratedId = 0;
_inner->clearFilter(); _inner->clearFilter();
clearSearchField();
applySearchState(std::move(updatedState)); applySearchState(std::move(updatedState));
if (_suggestions && clearSearchFocus) { if (_suggestions && clearSearchFocus) {
setInnerFocus(true); setInnerFocus(true);

View file

@ -232,7 +232,7 @@ private:
void fullSearchRefreshOn(rpl::producer<> events); void fullSearchRefreshOn(rpl::producer<> events);
void updateCancelSearch(); void updateCancelSearch();
bool fixSearchQuery(); [[nodiscard]] QString validateSearchQuery();
void applySearchUpdate(); void applySearchUpdate();
void refreshLoadMoreButton(bool mayBlock, bool isBlocked); void refreshLoadMoreButton(bool mayBlock, bool isBlocked);
void loadMoreBlockedByDate(); void loadMoreBlockedByDate();
@ -241,7 +241,9 @@ private:
SearchRequestType type, SearchRequestType type,
const MTP::Error &error, const MTP::Error &error,
mtpRequestId requestId); mtpRequestId requestId);
void peopleFailed(const MTP::Error &error, mtpRequestId requestId); void peerSearchFailed(const MTP::Error &error, mtpRequestId requestId);
void searchApplyEmpty(SearchRequestType type, mtpRequestId id);
void peerSearchApplyEmpty(mtpRequestId id);
void updateForceDisplayWide(); void updateForceDisplayWide();
void scrollToDefault(bool verytop = false); void scrollToDefault(bool verytop = false);
@ -307,7 +309,6 @@ private:
object_ptr<Ui::JumpDownButton> _scrollToTop; object_ptr<Ui::JumpDownButton> _scrollToTop;
bool _scrollToTopIsShown = false; bool _scrollToTopIsShown = false;
bool _forumSearchRequested = false; bool _forumSearchRequested = false;
bool _fixingSearchQuery = false;
bool _searchingHashtag = false; bool _searchingHashtag = false;
Data::Folder *_openedFolder = nullptr; Data::Folder *_openedFolder = nullptr;

View file

@ -77,6 +77,10 @@ FixedHashtagSearchQuery FixHashtagSearchQuery(
result += ch; result += ch;
} }
} }
if (result.size() == start) {
result += '#';
++cursorPosition;
}
return { result, cursorPosition }; return { result, cursorPosition };
} }
@ -123,23 +127,17 @@ ChatSearchTabs::ChatSearchTabs(QWidget *parent, ChatSearchTab active)
ChatSearchTabs::~ChatSearchTabs() = default; ChatSearchTabs::~ChatSearchTabs() = default;
void ChatSearchTabs::setPeerTabType(ChatSearchPeerTabType type) {
_type = type;
const auto i = ranges::find(_list, ChatSearchTab::ThisPeer, &Tab::value);
Assert(i != end(_list));
i->label = TabLabel(ChatSearchTab::ThisPeer, type);
if (!i->shortLabel.empty()) {
refreshTabs(_active.current());
}
}
void ChatSearchTabs::setTabShortLabels( void ChatSearchTabs::setTabShortLabels(
std::vector<ShortLabel> labels, std::vector<ShortLabel> labels,
ChatSearchTab active) { ChatSearchTab active,
ChatSearchPeerTabType peerTabType) {
for (const auto &label : labels) { for (const auto &label : labels) {
const auto i = ranges::find(_list, label.tab, &Tab::value); const auto i = ranges::find(_list, label.tab, &Tab::value);
Assert(i != end(_list)); Assert(i != end(_list));
i->shortLabel = std::move(label.label); i->shortLabel = std::move(label.label);
if (i->value == ChatSearchTab::ThisPeer) {
i->label = TabLabel(label.tab, peerTabType);
}
} }
refreshTabs(active); refreshTabs(active);
} }
@ -175,4 +173,8 @@ int ChatSearchTabs::resizeGetHeight(int newWidth) {
return _tabs->height(); return _tabs->height();
} }
void ChatSearchTabs::paintEvent(QPaintEvent *e) {
QPainter(this).fillRect(e->rect(), st::dialogsBg);
}
} // namespace Dialogs } // namespace Dialogs

View file

@ -37,8 +37,6 @@ public:
ChatSearchTabs(QWidget *parent, ChatSearchTab active); ChatSearchTabs(QWidget *parent, ChatSearchTab active);
~ChatSearchTabs(); ~ChatSearchTabs();
void setPeerTabType(ChatSearchPeerTabType type);
// A [custom] emoji to use when there is not enough space for text. // A [custom] emoji to use when there is not enough space for text.
// Only tabs with available short labels are shown. // Only tabs with available short labels are shown.
struct ShortLabel { struct ShortLabel {
@ -47,7 +45,8 @@ public:
}; };
void setTabShortLabels( void setTabShortLabels(
std::vector<ShortLabel> labels, std::vector<ShortLabel> labels,
ChatSearchTab active); ChatSearchTab active,
ChatSearchPeerTabType peerTabType);
[[nodiscard]] rpl::producer<ChatSearchTab> tabChanges() const; [[nodiscard]] rpl::producer<ChatSearchTab> tabChanges() const;
@ -60,13 +59,13 @@ private:
void refreshTabs(ChatSearchTab active); void refreshTabs(ChatSearchTab active);
int resizeGetHeight(int newWidth) override; int resizeGetHeight(int newWidth) override;
void paintEvent(QPaintEvent *e) override;
const std::unique_ptr<Ui::SettingsSlider> _tabs; const std::unique_ptr<Ui::SettingsSlider> _tabs;
const std::unique_ptr<Ui::PlainShadow> _shadow; const std::unique_ptr<Ui::PlainShadow> _shadow;
std::vector<Tab> _list; std::vector<Tab> _list;
rpl::variable<ChatSearchTab> _active; rpl::variable<ChatSearchTab> _active;
ChatSearchPeerTabType _type = {};
}; };