diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index b18471d0e..e10544c6d 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -2588,6 +2588,15 @@ void InnerWidget::dragPinnedFromTouch() { updateReorderPinned(now); } +void InnerWidget::searchRequested(bool loading) { + _searchWaiting = false; + _searchLoading = loading; + if (loading) { + clearSearchResults(true); + } + refresh(true); +} + void InnerWidget::applySearchState(SearchState state) { if (_searchState == state) { return; @@ -2700,9 +2709,13 @@ void InnerWidget::applySearchState(SearchState state) { clearMouseSelection(true); } if (_state != WidgetState::Default) { - _searchLoading = true; - _searchMessages.fire({}); - refresh(true); + _searchWaiting = true; + _searchRequests.fire(otherChanged + ? SearchRequestDelay::Instant + : SearchRequestDelay::Delayed); + if (_searchWaiting) { + refresh(true); + } } } @@ -2918,8 +2931,8 @@ rpl::producer<Ui::ScrollToRequest> InnerWidget::dialogMoved() const { return _dialogMoved.events(); } -rpl::producer<> InnerWidget::searchMessages() const { - return _searchMessages.events(); +rpl::producer<SearchRequestDelay> InnerWidget::searchRequests() const { + return _searchRequests.events(); } rpl::producer<QString> InnerWidget::completeHashtagRequests() const { @@ -3007,6 +3020,7 @@ void InnerWidget::searchReceived( HistoryItem *inject, SearchRequestType type, int fullCount) { + _searchWaiting = false; _searchLoading = false; const auto uniquePeers = uniqueSearchResults(); @@ -3171,7 +3185,7 @@ void InnerWidget::refreshEmpty() { && _searchResults.empty() && _peerSearchResults.empty() && _hashtagResults.empty(); - if (_searchLoading || !empty) { + if (_searchLoading || _searchWaiting || !empty) { if (_searchEmpty) { _searchEmpty->hide(); } @@ -3185,7 +3199,7 @@ void InnerWidget::refreshEmpty() { _searchEmpty->show(); } - if (!_searchLoading || !empty) { + if ((!_searchLoading && !_searchWaiting) || !empty) { _loadingAnimation.destroy(); } else if (!_loadingAnimation) { _loadingAnimation = Ui::CreateLoadingDialogRowWidget( diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index ebb22aa82..3adad0cf4 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -71,7 +71,7 @@ struct ChosenRow { bool newWindow : 1 = false; }; -enum class SearchRequestType { +enum class SearchRequestType : uchar { FromStart, FromOffset, PeerFromStart, @@ -80,6 +80,12 @@ enum class SearchRequestType { MigratedFromOffset, }; +enum class SearchRequestDelay : uchar { + InCache, + Instant, + Delayed, +}; + enum class WidgetState { Default, Filtered, @@ -145,6 +151,7 @@ public: } [[nodiscard]] bool hasFilteredResults() const; + void searchRequested(bool loading); void applySearchState(SearchState state); [[nodiscard]] auto searchTagsChanges() const -> rpl::producer<std::vector<Data::ReactionId>>; @@ -168,7 +175,7 @@ public: [[nodiscard]] rpl::producer<int> scrollByDeltaRequests() const; [[nodiscard]] rpl::producer<Ui::ScrollToRequest> mustScrollTo() const; [[nodiscard]] rpl::producer<Ui::ScrollToRequest> dialogMoved() const; - [[nodiscard]] rpl::producer<> searchMessages() const; + [[nodiscard]] rpl::producer<SearchRequestDelay> searchRequests() const; [[nodiscard]] rpl::producer<QString> completeHashtagRequests() const; [[nodiscard]] rpl::producer<> refreshHashtagsRequests() const; @@ -529,7 +536,7 @@ private: rpl::event_stream<Ui::ScrollToRequest> _mustScrollTo; rpl::event_stream<Ui::ScrollToRequest> _dialogMoved; - rpl::event_stream<> _searchMessages; + rpl::event_stream<SearchRequestDelay> _searchRequests; rpl::event_stream<QString> _completeHashtagRequests; rpl::event_stream<> _refreshHashtagsRequests; @@ -547,6 +554,7 @@ private: bool _savedSublists = false; bool _searchLoading = false; + bool _searchWaiting = false; base::unique_qptr<Ui::PopupMenu> _menu; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 068c30815..61689d105 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -95,6 +95,7 @@ namespace { constexpr auto kSearchPerPage = 50; constexpr auto kStoriesExpandDuration = crl::time(200); +constexpr auto kSearchRequestDelay = crl::time(900); base::options::toggle OptionForumHideChatsList({ .id = kOptionForumHideChatsList, @@ -324,9 +325,9 @@ Widget::Widget( _scroll->scrollToY(st + _inner->st()->height); } }, lifetime()); - _inner->searchMessages( - ) | rpl::start_with_next([=] { - searchRequested(); + _inner->searchRequests( + ) | rpl::start_with_next([=](SearchRequestDelay delay) { + searchRequested(delay); }, lifetime()); _inner->completeHashtagRequests( ) | rpl::start_with_next([=](const QString &tag) { @@ -1921,7 +1922,7 @@ void Widget::loadMoreBlockedByDate() { session().api().requestMoreBlockedByDateDialogs(); } -bool Widget::search(bool inCache) { +bool Widget::search(bool inCache, SearchRequestDelay delay) { _processingSearch = true; const auto guard = gsl::finally([&] { _processingSearch = false; @@ -1950,7 +1951,7 @@ bool Widget::search(bool inCache) { return true; } else if (inCache) { const auto success = _singleMessageSearch.lookup(query, [=] { - searchRequested(); + searchRequested(delay); }); if (!success) { return false; @@ -2068,6 +2069,9 @@ bool Widget::search(bool inCache) { }).send(); _searchQueries.emplace(_searchRequest, _searchQuery); } + _inner->searchRequested(true); + } else { + _inner->searchRequested(false); } const auto peerQuery = Api::ConvertPeerSearchQuery(query); if (searchForPeersRequired(peerQuery)) { @@ -2130,9 +2134,14 @@ bool Widget::searchForTopicsRequired(const QString &query) const { && !_openedForum->topicsList()->loaded(); } -void Widget::searchRequested() { - if (!search(true)) { - _searchTimer.callOnce(AutoSearchTimeout); +void Widget::searchRequested(SearchRequestDelay delay) { + if (search(true, delay)) { + return; + } else if (delay == SearchRequestDelay::Instant) { + _searchTimer.cancel(); + search(); + } else { + _searchTimer.callOnce(kSearchRequestDelay); } } @@ -2187,10 +2196,11 @@ void Widget::searchTopics() { } void Widget::searchMore() { - if (_searchRequest || _searchInHistoryRequest) { + if (_searchRequest + || _searchInHistoryRequest + || _searchTimer.isActive()) { return; - } - if (!_searchFull) { + } else if (!_searchFull) { if (const auto peer = searchInPeer()) { auto &histories = session().data().histories(); const auto topic = searchInTopic(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 581bfdc00..46e5b55e0 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -74,7 +74,8 @@ class FakeRow; class Key; struct ChosenRow; class InnerWidget; -enum class SearchRequestType; +enum class SearchRequestType : uchar; +enum class SearchRequestDelay : uchar; class Suggestions; class ChatSearchIn; enum class ChatSearchTab : uchar; @@ -156,8 +157,8 @@ private: [[nodiscard]] QString currentSearchQuery() const; [[nodiscard]] int currentSearchQueryCursorPosition() const; void clearSearchField(); - void searchRequested(); - bool search(bool inCache = false); + void searchRequested(SearchRequestDelay delay); + bool search(bool inCache = false, SearchRequestDelay after = {}); void searchTopics(); void searchMore();