diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 25cf71a96..ee71e46e7 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/dialogs_inner_widget.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_stories_content.h" #include "dialogs/ui/dialogs_video_userpic.h" @@ -747,6 +748,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { p.fillRect(dialogsClip, currentBg()); } } else if (_state == WidgetState::Filtered) { + auto top = 0; if (!_hashtagResults.empty()) { auto from = floorclamp(r.y(), 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.translate(0, st::mentionHeight); + top += st::mentionHeight; } } } @@ -800,7 +803,9 @@ void InnerWidget::paintEvent(QPaintEvent *e) { auto to = std::min( filteredIndex(r.y() + r.height() - skip) + 1, int(_filterResults.size())); - p.translate(0, filteredHeight(from)); + const auto height = filteredHeight(from); + p.translate(0, height); + top += height; for (; from < to; ++from) { const auto selected = isPressed() ? (from == _filteredPressed) @@ -808,6 +813,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { const auto row = _filterResults[from].row; paintRow(row, selected, !activeEntry.fullId); p.translate(0, row->height()); + top += row->height(); } } @@ -817,11 +823,13 @@ void InnerWidget::paintEvent(QPaintEvent *e) { p.setPen(st::searchedBarFg); p.drawTextLeft(st::searchedBarPosition.x(), st::searchedBarPosition.y(), width(), tr::lng_search_global_results(tr::now)); p.translate(0, st::searchedBarHeight); + top += st::searchedBarHeight; auto skip = peerSearchOffset(); auto from = floorclamp(r.y() - 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); + top += from * st::dialogsRowHeight; if (from < _peerSearchResults.size()) { const auto activePeer = activeEntry.key.peer(); for (; from < to; ++from) { @@ -844,6 +852,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { .paused = videoPaused, }); p.translate(0, st::dialogsRowHeight); + top += st::dialogsRowHeight; } } } @@ -857,29 +866,15 @@ void InnerWidget::paintEvent(QPaintEvent *e) { .paused = videoPaused, }); p.translate(0, searchInChatSkip()); - if (_waitingForSearch && _searchResults.empty()) { - p.fillRect( - 0, - 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); + top += searchInChatSkip(); + if (_searchResults.empty()) { + p.fillRect(0, 0, fullWidth, st::lineWidth, st::shadowFg); } } const auto showUnreadInSearchResults = uniqueSearchResults(); - if (!_waitingForSearch || !_searchResults.empty()) { - const auto text = _searchResults.empty() - ? tr::lng_search_no_results(tr::now) - : showUnreadInSearchResults + if (!_searchResults.empty()) { + const auto text = showUnreadInSearchResults ? u"Search results"_q : tr::lng_search_found_results( tr::now, @@ -890,11 +885,13 @@ void InnerWidget::paintEvent(QPaintEvent *e) { p.setPen(st::searchedBarFg); p.drawTextLeft(st::searchedBarPosition.x(), st::searchedBarPosition.y(), width(), text); p.translate(0, st::searchedBarHeight); + top += st::searchedBarHeight; auto skip = searchedOffset(); auto from = floorclamp(r.y() - 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); + top += from * _st->height; if (from < _searchResults.size()) { for (; from < to; ++from) { const auto &result = _searchResults[from]; @@ -920,6 +917,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { .displayUnreadInfo = showUnreadInSearchResults, }); p.translate(0, _st->height); + top += _st->height; } } } @@ -1127,10 +1125,11 @@ void InnerWidget::paintSearchInChat( auto top = 0; if (_searchTags) { const auto height = _searchTags->height(); + top += st::dialogsSearchTagBottom; 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); - top += height; + top += height - st::dialogsSearchTagBottom; } p.setFont(st::searchedBarFont); auto fullRect = QRect(0, top, width(), height - top); @@ -1279,7 +1278,9 @@ void InnerWidget::selectByMouse(QPoint globalPosition) { _lastMousePosition = globalPosition; _lastRowLocalMouseX = local.x(); - const auto tagBase = QPoint(_searchTagsLeft, searchInChatOffset()); + const auto tagBase = QPoint( + _searchTagsLeft, + searchInChatOffset() + st::dialogsSearchTagBottom); const auto tagPoint = local - tagBase; const auto inTags = _searchTags && QRect( @@ -1895,7 +1896,7 @@ void InnerWidget::moveCancelSearchButtons() { st::columnMinimalWidthLeft - _narrowWidth); const auto left = widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchFromUser->width(); 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); } @@ -2460,6 +2461,74 @@ void InnerWidget::applySearchState(SearchState state) { withSameQuery.query = _searchState.query; 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( + &peer->owner(), + reactions->myTagsValue(sublist), + state.tags); + + _searchTags->selectedChanges( + ) | rpl::start_with_next([=](std::vector &&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); auto newFilter = _searchState.query; const auto mentionsSearch = (newFilter == u"@"_q); @@ -2569,7 +2638,9 @@ InnerWidget::~InnerWidget() { } void InnerWidget::clearSearchResults(bool clearPeerSearchResults) { - if (clearPeerSearchResults) _peerSearchResults.clear(); + if (clearPeerSearchResults) { + _peerSearchResults.clear(); + } _searchResults.clear(); _searchResultsLifetime.destroy(); _searchResultsHistories.clear(); @@ -2807,7 +2878,8 @@ void InnerWidget::searchReceived( SearchRequestType type, int fullCount) { const auto uniquePeers = uniqueSearchResults(); - if (type == SearchRequestType::FromStart || type == SearchRequestType::PeerFromStart) { + if (type == SearchRequestType::FromStart + || type == SearchRequestType::PeerFromStart) { clearSearchResults(false); } const auto isMigratedSearch = (type == SearchRequestType::MigratedFromStart) @@ -3066,81 +3138,6 @@ bool InnerWidget::hasFilteredResults() const { return !_filterResults.empty() && _hashtagResults.empty(); } -void InnerWidget::searchInChat( - Key key, - PeerData *from, - std::vector 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( - &peer->owner(), - reactions->myTagsValue(sublist), - tags); - - _searchTags->selectedChanges( - ) | rpl::start_with_next([=](std::vector &&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 -> rpl::producer> { return _searchTags diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 805a7ff2b..57f649c3c 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -146,10 +146,6 @@ public: [[nodiscard]] bool hasFilteredResults() const; void applySearchState(SearchState state); - void searchInChat( - Key key, - PeerData *from, - std::vector tags); [[nodiscard]] auto searchTagsChanges() const -> rpl::producer>; @@ -386,6 +382,7 @@ private: const Ui::Text::String &text) const; void refreshSearchInChatLabel(); void repaintSearchResult(int index); + void paintEmpty(QPainter &p, int top); Ui::VideoUserpic *validateVideoUserpic(not_null row); Ui::VideoUserpic *validateVideoUserpic(not_null history); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index cc510a948..bc9f2426a 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -375,7 +375,7 @@ Widget::Widget( _search->changes( ) | rpl::start_with_next([=] { - applySearchUpdate(); + crl::on_main(this, [=] { applySearchUpdate(); }); }, _search->lifetime()); _search->submits( @@ -524,7 +524,7 @@ Widget::Widget( void Widget::chosenRow(const ChosenRow &row) { storiesToggleExplicitExpand(false); - if (!currentSearchQuery().isEmpty()) { + if (!_searchState.query.isEmpty()) { if (const auto history = row.key.history()) { session().recentPeers().bump(history->peer); } @@ -1240,6 +1240,7 @@ void Widget::updateSearchTabs() { applySearchState(std::move(copy)); }, _searchTabs->lifetime()); } + const auto sublist = _searchState.inChat.sublist(); const auto topic = _searchState.inChat.topic(); const auto peer = _searchState.inChat.owningHistory() ? _searchState.inChat.owningHistory()->peer.get() @@ -1258,6 +1259,10 @@ void Widget::updateSearchTabs() { ? Ui::Text::SingleCustomEmoji( session().data().customEmojiManager().peerUserpicEmojiData( peer)) + : sublist + ? Ui::Text::SingleCustomEmoji( + session().data().customEmojiManager().peerUserpicEmojiData( + sublist->peer())) : TextWithEntities(); const auto myShortLabel = DefaultShortLabel(ChatSearchTab::MyMessages); const auto publicShortLabel = _searchingHashtag @@ -1275,12 +1280,17 @@ void Widget::updateSearchTabs() { ? ChatSearchTab::ThisPeer : ChatSearchTab::MyMessages; } + const auto peerTabType = (peer && peer->isBroadcast()) + ? ChatSearchPeerTabType::Channel + : (peer && (peer->isChat() || peer->isMegagroup())) + ? ChatSearchPeerTabType::Group + : ChatSearchPeerTabType::Chat; _searchTabs->setTabShortLabels({ { ChatSearchTab::ThisTopic, topicShortLabel }, { ChatSearchTab::ThisPeer, peerShortLabel }, { ChatSearchTab::MyMessages, myShortLabel }, { ChatSearchTab::PublicPosts, publicShortLabel }, - }, _searchState.tab); + }, _searchState.tab, peerTabType); updateControlsGeometry(); } @@ -1611,7 +1621,7 @@ void Widget::jumpToTop(bool belowPinned) { if (session().supportMode()) { return; } - if ((currentSearchQuery().trimmed().isEmpty() && !_searchState.inChat)) { + if ((_searchState.query.trimmed().isEmpty() && !_searchState.inChat)) { auto to = 0; if (belowPinned) { const auto list = _openedForum @@ -1749,7 +1759,7 @@ void Widget::updateStoriesVisibility() { || _childList || _searchHasFocus || _searchSuggestionsLocked - || !currentSearchQuery().isEmpty() + || !_searchState.query.isEmpty() || _searchState.inChat || _stories->empty(); if (_stories->isHidden() != hidden) { @@ -1952,16 +1962,22 @@ void Widget::loadMoreBlockedByDate() { bool Widget::search(bool inCache) { auto result = false; - const auto query = currentSearchQuery().trimmed(); + const auto query = _searchState.query.trimmed(); const auto inPeer = searchInPeer(); const auto fromPeer = searchFromPeer(); const auto &inTags = searchInTags(); const auto tab = _searchState.tab; + const auto fromStartType = inPeer + ? SearchRequestType::PeerFromStart + : SearchRequestType::FromStart; const auto skipRequest = (query.isEmpty() && !fromPeer && inTags.empty()) || (tab == ChatSearchTab::PublicPosts && query.size() < 2); if (skipRequest) { cancelSearchRequest(); + searchApplyEmpty(fromStartType, 0); _api.request(base::take(_peerSearchRequest)).cancel(); + _peerSearchQuery = QString(); + peerSearchApplyEmpty(0); _api.request(base::take(_topicSearchRequest)).cancel(); return true; } else if (inCache) { @@ -1981,9 +1997,7 @@ bool Widget::search(bool inCache) { _searchFull = _searchFullMigrated = false; cancelSearchRequest(); searchReceived( - (inPeer - ? SearchRequestType::PeerFromStart - : SearchRequestType::FromStart), + fromStartType, i->second, 0); result = true; @@ -2109,21 +2123,14 @@ bool Widget::search(bool inCache) { )).done([=](const MTPcontacts_Found &result, mtpRequestId requestId) { peerSearchReceived(result, requestId); }).fail([=](const MTP::Error &error, mtpRequestId requestId) { - peopleFailed(error, requestId); + peerSearchFailed(error, requestId); }).send(); _peerSearchQueries.emplace(_peerSearchRequest, _peerSearchQuery); } } else { _api.request(base::take(_peerSearchRequest)).cancel(); _peerSearchQuery = peerQuery; - _peerSearchFull = true; - peerSearchReceived( - MTP_contacts_found( - MTP_vector(0), - MTP_vector(0), - MTP_vector(0), - MTP_vector(0)), - 0); + peerSearchApplyEmpty(0); } if (searchForTopicsRequired(peerQuery)) { if (inCache) { @@ -2170,64 +2177,7 @@ void Widget::showMainMenu() { void Widget::searchMessages(SearchState state) { applySearchState(std::move(state)); - session().local().saveRecentSearchHashtags(state.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); - //} + session().local().saveRecentSearchHashtags(_searchState.query); } 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(), + MTP_vector(), + MTP_vector()), + id); +} + +void Widget::peerSearchApplyEmpty(mtpRequestId id) { + _peerSearchFull = true; + peerSearchReceived( + MTP_contacts_found( + MTP_vector(0), + MTP_vector(0), + MTP_vector(0), + MTP_vector(0)), + id); +} + void Widget::searchFailed( SearchRequestType type, const MTP::Error &error, mtpRequestId requestId) { if (error.type() == u"SEARCH_QUERY_EMPTY"_q) { - searchReceived( - type, - MTP_messages_messages( - MTP_vector(), - MTP_vector(), - MTP_vector()), - requestId); + searchApplyEmpty(type, requestId); } else if (_searchRequest == requestId) { _searchRequest = 0; if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { @@ -2596,8 +2562,8 @@ void Widget::searchFailed( } } -void Widget::peopleFailed(const MTP::Error &error, mtpRequestId requestId) { - if (_peerSearchRequest == requestId) { +void Widget::peerSearchFailed(const MTP::Error &error, mtpRequestId id) { + if (_peerSearchRequest == id) { _peerSearchRequest = 0; _peerSearchFull = true; } @@ -2702,40 +2668,33 @@ void Widget::listScrollUpdated() { } void Widget::updateCancelSearch() { - const auto shown = !_search->getLastText().isEmpty() + const auto shown = !_searchState.query.isEmpty() || (!_searchState.inChat && (_searchHasFocus || _searchSuggestionsLocked)); _cancelSearch->toggle(shown, anim::type::normal); } -bool Widget::fixSearchQuery() { - if (_fixingSearchQuery) { - return false; - } - _fixingSearchQuery = true; +QString Widget::validateSearchQuery() { const auto query = currentSearchQuery(); if (_searchState.tab == ChatSearchTab::PublicPosts) { + _searchingHashtag = true; const auto fixed = FixHashtagSearchQuery( query, currentSearchQueryCursorPosition()); if (fixed.text != query) { setSearchQuery(fixed.text, fixed.cursorPosition); } - _searchingHashtag = true; + return fixed.text; } else if (_searchingHashtag != IsHashtagSearchQuery(query)) { _searchingHashtag = !_searchingHashtag; updateSearchTabs(); } - _fixingSearchQuery = false; - return true; + return query; } void Widget::applySearchUpdate() { - if (!fixSearchQuery()) { - return; - } auto copy = _searchState; - copy.query = currentSearchQuery(); + copy.query = validateSearchQuery(); applySearchState(std::move(copy)); if (_chooseFromUser->toggled() @@ -2755,7 +2714,7 @@ void Widget::updateForceDisplayWide() { controller()->setChatsForceDisplayWide(_searchHasFocus || (_subsectionTopBar && _subsectionTopBar->searchHasFocus()) || _searchSuggestionsLocked - || !currentSearchQuery().isEmpty() + || !_searchState.query.isEmpty() || _searchState.inChat); } @@ -2961,12 +2920,10 @@ bool Widget::applySearchState(SearchState state) { updateSearchTabs(); } if (queryChanged || inChatChanged) { - updateJumpToDateVisibility(); updateStoriesVisibility(); } - if (fromPeerChanged) { - updateSearchFromVisibility(); - } + updateJumpToDateVisibility(); + updateSearchFromVisibility(); updateLockUnlockPosition(); if ((state.query.isEmpty() && !state.fromPeer && state.tags.empty()) @@ -2988,6 +2945,7 @@ bool Widget::applySearchState(SearchState state) { controller()->closeFolder(); } + setSearchQuery(_searchState.query); _inner->applySearchState(_searchState); if (!_postponeProcessSearchFocusChange) { @@ -3009,7 +2967,7 @@ bool Widget::applySearchState(SearchState state) { && _lastSearchText == HistoryView::SwitchToChooseFromQuery()) { cancelSearch(); } - if (_searchState.inChat || !_search->getLastText().isEmpty()) { + if (_searchState.inChat || !_searchState.query.isEmpty()) { _search->setFocus(); } else { setInnerFocus(); @@ -3138,7 +3096,7 @@ void Widget::updateLockUnlockVisibility(anim::type animated) { || _searchHasFocus || _searchSuggestionsLocked || _searchState.inChat - || !_search->getLastText().isEmpty(); + || !_searchState.query.isEmpty(); if (_lockUnlock->toggled() == hidden) { const auto stories = _stories && !_stories->empty(); _lockUnlock->toggle( @@ -3157,7 +3115,7 @@ void Widget::updateLoadMoreChatsVisibility() { } const auto hidden = (_openedFolder != nullptr) || (_openedForum != nullptr) - || !currentSearchQuery().isEmpty(); + || !_searchState.query.isEmpty(); if (_loadMoreChats->isHidden() != hidden) { _loadMoreChats->setVisible(!hidden); updateControlsGeometry(); @@ -3170,7 +3128,7 @@ void Widget::updateJumpToDateVisibility(bool fast) { } _jumpToDate->toggle( - (_searchState.inChat && _search->getLastText().isEmpty()), + (searchInPeer() && _searchState.query.isEmpty()), fast ? anim::type::instant : anim::type::normal); } @@ -3617,6 +3575,10 @@ void Widget::clearSearchField() { } void Widget::setSearchQuery(const QString &query, int cursorPosition) { + if (query.isEmpty()) { + clearSearchField(); + return; + } if (cursorPosition < 0) { cursorPosition = query.size(); } @@ -3666,7 +3628,6 @@ bool Widget::cancelSearch() { _lastSearchPeer = nullptr; _lastSearchId = _lastSearchMigratedId = 0; _inner->clearFilter(); - clearSearchField(); applySearchState(std::move(updatedState)); if (_suggestions && clearSearchFocus) { setInnerFocus(true); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index f265ebf87..47b407e07 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -232,7 +232,7 @@ private: void fullSearchRefreshOn(rpl::producer<> events); void updateCancelSearch(); - bool fixSearchQuery(); + [[nodiscard]] QString validateSearchQuery(); void applySearchUpdate(); void refreshLoadMoreButton(bool mayBlock, bool isBlocked); void loadMoreBlockedByDate(); @@ -241,7 +241,9 @@ private: SearchRequestType type, const MTP::Error &error, 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 scrollToDefault(bool verytop = false); @@ -307,7 +309,6 @@ private: object_ptr _scrollToTop; bool _scrollToTopIsShown = false; bool _forumSearchRequested = false; - bool _fixingSearchQuery = false; bool _searchingHashtag = false; Data::Folder *_openedFolder = nullptr; diff --git a/Telegram/SourceFiles/dialogs/ui/chat_search_tabs.cpp b/Telegram/SourceFiles/dialogs/ui/chat_search_tabs.cpp index 456183d30..d79eb0502 100644 --- a/Telegram/SourceFiles/dialogs/ui/chat_search_tabs.cpp +++ b/Telegram/SourceFiles/dialogs/ui/chat_search_tabs.cpp @@ -77,6 +77,10 @@ FixedHashtagSearchQuery FixHashtagSearchQuery( result += ch; } } + if (result.size() == start) { + result += '#'; + ++cursorPosition; + } return { result, cursorPosition }; } @@ -123,23 +127,17 @@ ChatSearchTabs::ChatSearchTabs(QWidget *parent, ChatSearchTab active) 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( std::vector labels, - ChatSearchTab active) { + ChatSearchTab active, + ChatSearchPeerTabType peerTabType) { for (const auto &label : labels) { const auto i = ranges::find(_list, label.tab, &Tab::value); Assert(i != end(_list)); i->shortLabel = std::move(label.label); + if (i->value == ChatSearchTab::ThisPeer) { + i->label = TabLabel(label.tab, peerTabType); + } } refreshTabs(active); } @@ -175,4 +173,8 @@ int ChatSearchTabs::resizeGetHeight(int newWidth) { return _tabs->height(); } +void ChatSearchTabs::paintEvent(QPaintEvent *e) { + QPainter(this).fillRect(e->rect(), st::dialogsBg); +} + } // namespace Dialogs \ No newline at end of file diff --git a/Telegram/SourceFiles/dialogs/ui/chat_search_tabs.h b/Telegram/SourceFiles/dialogs/ui/chat_search_tabs.h index 0e2640f83..ba87f9f98 100644 --- a/Telegram/SourceFiles/dialogs/ui/chat_search_tabs.h +++ b/Telegram/SourceFiles/dialogs/ui/chat_search_tabs.h @@ -37,8 +37,6 @@ public: ChatSearchTabs(QWidget *parent, ChatSearchTab active); ~ChatSearchTabs(); - void setPeerTabType(ChatSearchPeerTabType type); - // A [custom] emoji to use when there is not enough space for text. // Only tabs with available short labels are shown. struct ShortLabel { @@ -47,7 +45,8 @@ public: }; void setTabShortLabels( std::vector labels, - ChatSearchTab active); + ChatSearchTab active, + ChatSearchPeerTabType peerTabType); [[nodiscard]] rpl::producer tabChanges() const; @@ -60,13 +59,13 @@ private: void refreshTabs(ChatSearchTab active); int resizeGetHeight(int newWidth) override; + void paintEvent(QPaintEvent *e) override; const std::unique_ptr _tabs; const std::unique_ptr _shadow; std::vector _list; rpl::variable _active; - ChatSearchPeerTabType _type = {}; };