diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index a24daa0d3..2a594aa58 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -131,6 +131,8 @@ PRIVATE api/api_media.h api/api_messages_search.cpp api/api_messages_search.h + api/api_messages_search_merged.cpp + api/api_messages_search_merged.h api/api_peer_photo.cpp api/api_peer_photo.h api/api_polls.cpp diff --git a/Telegram/SourceFiles/api/api_messages_search.cpp b/Telegram/SourceFiles/api/api_messages_search.cpp index 54d75e3d6..f1de7b3a0 100644 --- a/Telegram/SourceFiles/api/api_messages_search.cpp +++ b/Telegram/SourceFiles/api/api_messages_search.cpp @@ -44,12 +44,9 @@ MessageIdsList HistoryItemsFromTL( } // namespace -MessagesSearch::MessagesSearch( - not_null session, - not_null history) -: _session(session) -, _history(history) -, _api(&session->mtp()) { +MessagesSearch::MessagesSearch(not_null history) +: _history(history) +, _api(&history->session().mtp()) { } void MessagesSearch::searchMessages(const QString &query, PeerData *from) { @@ -115,7 +112,7 @@ void MessagesSearch::searchRequest() { }).send(); return _requestId; }; - _searchInHistoryRequest = _session->data().histories().sendRequest( + _searchInHistoryRequest = _history->owner().histories().sendRequest( _history, Data::Histories::RequestType::History, std::move(callback)); @@ -128,7 +125,7 @@ void MessagesSearch::searchReceived( if (requestId != _requestId) { return; } - auto &owner = _session->data(); + auto &owner = _history->owner(); auto found = result.match([&](const MTPDmessages_messages &data) { if (_requestId != 0) { // Don't apply cached data! diff --git a/Telegram/SourceFiles/api/api_messages_search.h b/Telegram/SourceFiles/api/api_messages_search.h index 76e84202d..a4a542fd2 100644 --- a/Telegram/SourceFiles/api/api_messages_search.h +++ b/Telegram/SourceFiles/api/api_messages_search.h @@ -13,10 +13,6 @@ class HistoryItem; class History; class PeerData; -namespace Main { -class Session; -} // namespace Main - namespace Api { struct FoundMessages { @@ -27,9 +23,7 @@ struct FoundMessages { class MessagesSearch final { public: - explicit MessagesSearch( - not_null session, - not_null history); + explicit MessagesSearch(not_null history); void searchMessages(const QString &query, PeerData *from); void searchMore(); @@ -44,7 +38,6 @@ private: mtpRequestId requestId, const QString &nextToken); - const not_null _session; const not_null _history; MTP::Sender _api; diff --git a/Telegram/SourceFiles/api/api_messages_search_merged.cpp b/Telegram/SourceFiles/api/api_messages_search_merged.cpp new file mode 100644 index 000000000..d25460de2 --- /dev/null +++ b/Telegram/SourceFiles/api/api_messages_search_merged.cpp @@ -0,0 +1,113 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "api/api_messages_search_merged.h" + +#include "history/history.h" + +namespace Api { + +bool MessagesSearchMerged::RequestCompare::operator()( + const Request &a, + const Request &b) const { + return (a.query < b.query) && (a.from < b.from); +} + +MessagesSearchMerged::MessagesSearchMerged(not_null history) +: _apiSearch(history) +, _migratedSearch(history->migrateFrom() + ? std::make_optional(history->migrateFrom()) + : std::nullopt) { + + const auto checkWaitingForTotal = [=] { + if (_waitingForTotal) { + if (_concatedFound.total >= 0 && _migratedFirstFound.total >= 0) { + _waitingForTotal = false; + _concatedFound.total += _migratedFirstFound.total; + _newFounds.fire({}); + } + } else { + _newFounds.fire({}); + } + }; + + const auto checkFull = [=](const FoundMessages &data) { + if (data.total == int(_concatedFound.messages.size())) { + _isFull = true; + addFound(_migratedFirstFound); + } + }; + + _apiSearch.messagesFounds( + ) | rpl::start_with_next([=](const FoundMessages &data) { + if (data.nextToken == _concatedFound.nextToken) { + addFound(data); + checkFull(data); + _nextFounds.fire({}); + } else { + _concatedFound = data; + checkFull(data); + checkWaitingForTotal(); + } + }, _lifetime); + + if (_migratedSearch) { + _migratedSearch->messagesFounds( + ) | rpl::start_with_next([=](const FoundMessages &data) { + if (_isFull) { + addFound(data); + } + if (data.nextToken == _migratedFirstFound.nextToken) { + _nextFounds.fire({}); + } else { + _migratedFirstFound = data; + checkWaitingForTotal(); + } + }, _lifetime); + } +} + +void MessagesSearchMerged::addFound(const FoundMessages &data) { + for (const auto &message : data.messages) { + _concatedFound.messages.push_back(message); + } +} + +const FoundMessages &MessagesSearchMerged::messages() const { + return _concatedFound; +} + +void MessagesSearchMerged::clear() { + _concatedFound = {}; + _migratedFirstFound = {}; +} + +void MessagesSearchMerged::search(const Request &search) { + if (_migratedSearch) { + _waitingForTotal = true; + _migratedSearch->searchMessages(search.query, search.from); + } + _apiSearch.searchMessages(search.query, search.from); +} + +void MessagesSearchMerged::searchMore() { + if (_migratedSearch && _isFull) { + _migratedSearch->searchMore(); + } else { + _apiSearch.searchMore(); + } +} + +rpl::producer<> MessagesSearchMerged::newFounds() const { + return _newFounds.events(); +} + +rpl::producer<> MessagesSearchMerged::nextFounds() const { + return _nextFounds.events(); +} + +} // namespace Api diff --git a/Telegram/SourceFiles/api/api_messages_search_merged.h b/Telegram/SourceFiles/api/api_messages_search_merged.h new file mode 100644 index 000000000..d7c67713f --- /dev/null +++ b/Telegram/SourceFiles/api/api_messages_search_merged.h @@ -0,0 +1,60 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "api/api_messages_search.h" + +class History; +class PeerData; + +namespace Api { + +// Search in both of history and migrated history, if it exists. +class MessagesSearchMerged final { +public: + struct Request { + QString query; + PeerData *from = nullptr; + }; + struct RequestCompare { + bool operator()(const Request &a, const Request &b) const; + }; + using CachedRequests = std::set; + + MessagesSearchMerged(not_null history); + + void clear(); + void search(const Request &search); + void searchMore(); + + [[nodiscard]] const FoundMessages &messages() const; + + [[nodiscard]] rpl::producer<> newFounds() const; + [[nodiscard]] rpl::producer<> nextFounds() const; + +private: + void addFound(const FoundMessages &data); + + MessagesSearch _apiSearch; + + std::optional _migratedSearch; + FoundMessages _migratedFirstFound; + + FoundMessages _concatedFound; + + bool _waitingForTotal = false; + bool _isFull = false; + + rpl::event_stream<> _newFounds; + rpl::event_stream<> _nextFounds; + + rpl::lifetime _lifetime; + +}; + +} // namespace Api diff --git a/Telegram/SourceFiles/boxes/delete_messages_box.cpp b/Telegram/SourceFiles/boxes/delete_messages_box.cpp index 4bafcac68..21f024ac5 100644 --- a/Telegram/SourceFiles/boxes/delete_messages_box.cpp +++ b/Telegram/SourceFiles/boxes/delete_messages_box.cpp @@ -184,7 +184,6 @@ void DeleteMessagesBox::prepare() { st::defaultBoxCheckbox); if (_moderateDeleteAll) { const auto search = lifetime().make_state( - _session, _session->data().message(_ids.front())->history()); _deleteAll.create( this, diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_search.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_search.cpp index 73422e84b..bd764f558 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_search.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_search.cpp @@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "history/view/controls/history_view_compose_search.h" -#include "api/api_messages_search.h" +#include "api/api_messages_search_merged.h" #include "boxes/peer_list_box.h" #include "data/data_session.h" #include "dialogs/dialogs_search_from_controllers.h" // SearchFromBox @@ -29,6 +29,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { namespace { +using SearchRequest = Api::MessagesSearchMerged::Request; + [[nodiscard]] inline bool HasChooseFrom(not_null history) { if (const auto peer = history->peer) { return (peer->isChat() || peer->isMegagroup()); @@ -36,11 +38,6 @@ namespace { return false; } -struct SearchRequest { - QString query; - PeerData *from = nullptr; -}; - class Row final : public PeerListRow { public: Row(std::unique_ptr fakeRow); @@ -269,7 +266,7 @@ private: base::Timer _searchTimer; - std::vector _typedRequests; + Api::MessagesSearchMerged::CachedRequests _typedRequests; rpl::event_stream _searchRequests; rpl::event_stream<> _queryChanges; @@ -342,18 +339,17 @@ void TopBar::clearItems() { void TopBar::requestSearch(bool cache) { const auto search = SearchRequest{ _select->getQuery(), _from.current() }; if (cache) { - _typedRequests.push_back(search); + _typedRequests.insert(search); } _searchRequests.fire_copy(search); } void TopBar::requestSearchDelayed() { // Check cached queries. - for (const auto &t : _typedRequests) { - if (t.query == _select->getQuery() && t.from == _from.current()) { - requestSearch(false); - return; - } + const auto search = SearchRequest{ _select->getQuery(), _from.current() }; + if (_typedRequests.contains(search)) { + requestSearch(false); + return; } _searchTimer.callOnce(AutoSearchTimeout); @@ -575,134 +571,6 @@ void BottomBar::buttonCalendarToggleOn(rpl::producer &&visible) { }, _jumpToDate->lifetime()); } -class ApiSearch final { -public: - ApiSearch(not_null session, not_null history); - - void clear(); - void search(const SearchRequest &search); - void searchMore(); - - const Api::FoundMessages &messages() const; - - [[nodiscard]] rpl::producer<> newFounds() const; - [[nodiscard]] rpl::producer<> nextFounds() const; - -private: - void addFound(const Api::FoundMessages &data); - - Api::MessagesSearch _apiSearch; - - std::optional _migratedSearch; - Api::FoundMessages _migratedFirstFound; - - Api::FoundMessages _concatedFound; - - bool _waitingForTotal = false; - bool _isFull = false; - - rpl::event_stream<> _newFounds; - rpl::event_stream<> _nextFounds; - - rpl::lifetime _lifetime; - -}; - -ApiSearch::ApiSearch( - not_null session, - not_null history) -: _apiSearch(session, history) -, _migratedSearch(history->migrateFrom() - ? std::make_optional(session, history->migrateFrom()) - : std::nullopt) { - - const auto checkWaitingForTotal = [=] { - if (_waitingForTotal) { - if (_concatedFound.total >= 0 && _migratedFirstFound.total >= 0) { - _waitingForTotal = false; - _concatedFound.total += _migratedFirstFound.total; - _newFounds.fire({}); - } - } else { - _newFounds.fire({}); - } - }; - - const auto checkFull = [=](const Api::FoundMessages &data) { - if (data.total == int(_concatedFound.messages.size())) { - _isFull = true; - addFound(_migratedFirstFound); - } - }; - - _apiSearch.messagesFounds( - ) | rpl::start_with_next([=](const Api::FoundMessages &data) { - if (data.nextToken == _concatedFound.nextToken) { - addFound(data); - checkFull(data); - _nextFounds.fire({}); - } else { - _concatedFound = data; - checkFull(data); - checkWaitingForTotal(); - } - }, _lifetime); - - if (_migratedSearch) { - _migratedSearch->messagesFounds( - ) | rpl::start_with_next([=](const Api::FoundMessages &data) { - if (_isFull) { - addFound(data); - } - if (data.nextToken == _migratedFirstFound.nextToken) { - _nextFounds.fire({}); - } else { - _migratedFirstFound = data; - checkWaitingForTotal(); - } - }, _lifetime); - } -} - -void ApiSearch::addFound(const Api::FoundMessages &data) { - for (const auto &message : data.messages) { - _concatedFound.messages.push_back(message); - } -} - -const Api::FoundMessages &ApiSearch::messages() const { - return _concatedFound; -} - -void ApiSearch::clear() { - _concatedFound = {}; - _migratedFirstFound = {}; -} - -void ApiSearch::search(const SearchRequest &search) { - if (_migratedSearch) { - _waitingForTotal = true; - _migratedSearch->searchMessages(search.query, search.from); - } - _apiSearch.searchMessages(search.query, search.from); -} - -void ApiSearch::searchMore() { - if (_migratedSearch && _isFull) { - _migratedSearch->searchMore(); - } else { - _apiSearch.searchMore(); - } -} - -rpl::producer<> ApiSearch::newFounds() const { - return _newFounds.events(); -} - -rpl::producer<> ApiSearch::nextFounds() const { - return _nextFounds.events(); -} - } // namespace class ComposeSearch::Inner final { @@ -729,7 +597,7 @@ private: const base::unique_qptr _bottomBar; const List _list; - ApiSearch _apiSearch; + Api::MessagesSearchMerged _apiSearch; struct { struct { @@ -752,7 +620,7 @@ ComposeSearch::Inner::Inner( , _topBar(base::make_unique_q(parent)) , _bottomBar(base::make_unique_q(parent, HasChooseFrom(history))) , _list(CreateList(parent, history)) -, _apiSearch(&window->session(), history) { +, _apiSearch(history) { showAnimated(); rpl::combine(