diff --git a/Telegram/SourceFiles/api/api_single_message_search.cpp b/Telegram/SourceFiles/api/api_single_message_search.cpp new file mode 100644 index 000000000..d8ee6088e --- /dev/null +++ b/Telegram/SourceFiles/api/api_single_message_search.cpp @@ -0,0 +1,219 @@ +/* +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_single_message_search.h" + +#include "main/main_session.h" +#include "data/data_session.h" +#include "data/data_channel.h" +#include "data/data_search_controller.h" +#include "core/local_url_handlers.h" +#include "history/history_item.h" +#include "base/qthelp_url.h" +#include "apiwrap.h" + +namespace Api { +namespace { + +using Key = details::SingleMessageSearchKey; + +Key ExtractKey(const QString &query) { + const auto trimmed = query.trimmed(); + const auto local = Core::TryConvertUrlToLocal(query); + const auto check = local.isEmpty() ? trimmed : local; + const auto parse = [&] { + const auto delimeter = check.indexOf('?'); + return (delimeter > 0) + ? qthelp::url_parse_params( + check.mid(delimeter + 1), + qthelp::UrlParamNameTransform::ToLower) + : QMap(); + }; + if (check.startsWith(qstr("tg://privatepost"), Qt::CaseInsensitive)) { + const auto params = parse(); + const auto channel = params.value("channel"); + const auto post = params.value("post").toInt(); + return (channel.toInt() && post) ? Key{ channel, post } : Key(); + } else if (check.startsWith(qstr("tg://resolve"), Qt::CaseInsensitive)) { + const auto params = parse(); + const auto domain = params.value("domain"); + const auto post = params.value("post").toInt(); + return (!domain.isEmpty() && post) ? Key{ domain, post } : Key(); + } + return Key(); +} + +} // namespace + +SingleMessageSearch::SingleMessageSearch(not_null session) +: _session(session) { +} + +SingleMessageSearch::~SingleMessageSearch() { + clear(); +} + +void SingleMessageSearch::clear() { + _cache.clear(); + _requestKey = Key(); + _session->api().request(base::take(_requestId)).cancel(); +} + +std::optional SingleMessageSearch::lookup( + const QString &query, + Fn ready) { + const auto key = ExtractKey(query); + if (!key) { + return nullptr; + } + const auto i = _cache.find(key); + if (i != end(_cache)) { + return _session->data().message(i->second); + } + if (!(_requestKey == key)) { + _session->api().request(base::take(_requestId)).cancel(); + _requestKey = key; + } + return performLookup(ready); +} + +std::optional SingleMessageSearch::performLookupByChannel( + not_null channel, + Fn ready) { + Expects(!_requestKey.empty()); + + const auto postId = _requestKey.postId; + if (const auto item = _session->data().message(channel, postId)) { + _cache.emplace(_requestKey, item->fullId()); + return item; + } else if (!ready) { + return nullptr; + } + + const auto fail = [=] { + _cache.emplace(_requestKey, FullMsgId()); + ready(); + }; + _requestId = _session->api().request(MTPchannels_GetMessages( + channel->inputChannel, + MTP_vector(1, MTP_inputMessageID(MTP_int(postId))) + )).done([=](const MTPmessages_Messages &result) { + const auto received = Api::ParseSearchResult( + channel, + Storage::SharedMediaType::kCount, + postId, + Data::LoadDirection::Around, + result); + if (!received.messageIds.empty() + && received.messageIds.front() == postId) { + _cache.emplace( + _requestKey, + FullMsgId(channel->bareId(), postId)); + ready(); + } else { + fail(); + } + }).fail([=](const RPCError &error) { + fail(); + }).send(); + + return std::nullopt; +} + +std::optional SingleMessageSearch::performLookupById( + ChannelId channelId, + Fn ready) { + Expects(!_requestKey.empty()); + + if (const auto channel = _session->data().channelLoaded(channelId)) { + return performLookupByChannel(channel, ready); + } else if (!ready) { + return nullptr; + } + + const auto fail = [=] { + _cache.emplace(_requestKey, FullMsgId()); + ready(); + }; + _requestId = _session->api().request(MTPchannels_GetChannels( + MTP_vector( + 1, + MTP_inputChannel(MTP_int(channelId), MTP_long(0))) + )).done([=](const MTPmessages_Chats &result) { + result.match([&](const auto &data) { + const auto peer = _session->data().processChats(data.vchats()); + if (peer && peer->id == peerFromChannel(channelId)) { + if (performLookupByChannel(peer->asChannel(), ready)) { + ready(); + } + } else { + fail(); + } + }); + }).fail([=](const RPCError &error) { + fail(); + }).send(); + + return std::nullopt; +} + +std::optional SingleMessageSearch::performLookupByUsername( + const QString &username, + Fn ready) { + Expects(!_requestKey.empty()); + + if (const auto peer = _session->data().peerByUsername(username)) { + if (const auto channel = peer->asChannel()) { + return performLookupByChannel(channel, ready); + } + _cache.emplace(_requestKey, FullMsgId()); + return nullptr; + } else if (!ready) { + return nullptr; + } + + const auto fail = [=] { + _cache.emplace(_requestKey, FullMsgId()); + ready(); + }; + _requestId = _session->api().request(MTPcontacts_ResolveUsername( + MTP_string(username) + )).done([=](const MTPcontacts_ResolvedPeer &result) { + result.match([&](const MTPDcontacts_resolvedPeer &data) { + _session->data().processUsers(data.vusers()); + _session->data().processChats(data.vchats()); + const auto peerId = peerFromMTP(data.vpeer()); + const auto peer = peerId + ? _session->data().peerLoaded(peerId) + : nullptr; + if (const auto channel = peer ? peer->asChannel() : nullptr) { + if (performLookupByChannel(channel, ready)) { + ready(); + } + } else { + fail(); + } + }); + }).fail([=](const RPCError &error) { + fail(); + }).send(); + + return std::nullopt; +} + +std::optional SingleMessageSearch::performLookup( + Fn ready) { + Expects(!_requestKey.empty()); + + if (!_requestKey.domainOrId[0].isDigit()) { + return performLookupByUsername(_requestKey.domainOrId, ready); + } + const auto channelId = _requestKey.domainOrId.toInt(); + return performLookupById(channelId, ready); +} + +} // namespace Api diff --git a/Telegram/SourceFiles/api/api_single_message_search.h b/Telegram/SourceFiles/api/api_single_message_search.h new file mode 100644 index 000000000..28b8ec675 --- /dev/null +++ b/Telegram/SourceFiles/api/api_single_message_search.h @@ -0,0 +1,74 @@ +/* +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 + +namespace Main { +class Session; +} // namespace Main + +namespace Api { +namespace details { + +struct SingleMessageSearchKey { + QString domainOrId; + MsgId postId = 0; + + [[nodiscard]] bool empty() const { + return domainOrId.isEmpty() || !postId; + } + [[nodiscard]] explicit operator bool() const { + return !empty(); + } + [[nodiscard]] bool operator<(const SingleMessageSearchKey &other) const { + return std::tie(domainOrId, postId) + < std::tie(other.domainOrId, other.postId); + } + [[nodiscard]] bool operator==( + const SingleMessageSearchKey &other) const { + return std::tie(domainOrId, postId) + == std::tie(other.domainOrId, other.postId); + } +}; + +} // namespace details + +class SingleMessageSearch { +public: + explicit SingleMessageSearch(not_null session); + ~SingleMessageSearch(); + + void clear(); + + // If 'ready' callback is empty, the result must not be 'nullopt'. + [[nodiscard]] std::optional lookup( + const QString &query, + Fn ready = nullptr); + +private: + using Key = details::SingleMessageSearchKey; + + [[nodiscard]] std::optional performLookup( + Fn ready); + [[nodiscard]] std::optional performLookupById( + ChannelId channelId, + Fn ready); + [[nodiscard]] std::optional performLookupByUsername( + const QString &username, + Fn ready); + [[nodiscard]] std::optional performLookupByChannel( + not_null channel, + Fn ready); + + const not_null _session; + std::map _cache; + mtpRequestId _requestId = 0; + Key _requestKey; + +}; + +} // namespace Api diff --git a/Telegram/SourceFiles/core/click_handler_types.cpp b/Telegram/SourceFiles/core/click_handler_types.cpp index 9ef340fe7..516474cb0 100644 --- a/Telegram/SourceFiles/core/click_handler_types.cpp +++ b/Telegram/SourceFiles/core/click_handler_types.cpp @@ -26,58 +26,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { -QString tryConvertUrlToLocal(QString url) { - if (url.size() > 8192) { - url = url.mid(0, 8192); - } - - using namespace qthelp; - auto matchOptions = RegExOption::CaseInsensitive; - auto telegramMeMatch = regex_match(qsl("^https?://(www\\.)?(telegram\\.(me|dog)|t\\.me)/(.+)$"), url, matchOptions); - if (telegramMeMatch) { - auto query = telegramMeMatch->capturedRef(4); - if (auto joinChatMatch = regex_match(qsl("^joinchat/([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"), query, matchOptions)) { - return qsl("tg://join?invite=") + url_encode(joinChatMatch->captured(1)); - } else if (auto stickerSetMatch = regex_match(qsl("^addstickers/([a-zA-Z0-9\\.\\_]+)(\\?|$)"), query, matchOptions)) { - return qsl("tg://addstickers?set=") + url_encode(stickerSetMatch->captured(1)); - } else if (auto languageMatch = regex_match(qsl("^setlanguage/([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"), query, matchOptions)) { - return qsl("tg://setlanguage?lang=") + url_encode(languageMatch->captured(1)); - } else if (auto shareUrlMatch = regex_match(qsl("^share/url/?\\?(.+)$"), query, matchOptions)) { - return qsl("tg://msg_url?") + shareUrlMatch->captured(1); - } else if (auto confirmPhoneMatch = regex_match(qsl("^confirmphone/?\\?(.+)"), query, matchOptions)) { - return qsl("tg://confirmphone?") + confirmPhoneMatch->captured(1); - } else if (auto ivMatch = regex_match(qsl("^iv/?\\?(.+)(#|$)"), query, matchOptions)) { - // - // We need to show our t.me page, not the url directly. - // - //auto params = url_parse_params(ivMatch->captured(1), UrlParamNameTransform::ToLower); - //auto previewedUrl = params.value(qsl("url")); - //if (previewedUrl.startsWith(qstr("http://"), Qt::CaseInsensitive) - // || previewedUrl.startsWith(qstr("https://"), Qt::CaseInsensitive)) { - // return previewedUrl; - //} - return url; - } else if (auto socksMatch = regex_match(qsl("^socks/?\\?(.+)(#|$)"), query, matchOptions)) { - return qsl("tg://socks?") + socksMatch->captured(1); - } else if (auto proxyMatch = regex_match(qsl("^proxy/?\\?(.+)(#|$)"), query, matchOptions)) { - return qsl("tg://proxy?") + proxyMatch->captured(1); - } else if (auto bgMatch = regex_match(qsl("^bg/([a-zA-Z0-9\\.\\_\\-]+)(\\?(.+)?)?$"), query, matchOptions)) { - const auto params = bgMatch->captured(3); - return qsl("tg://bg?slug=") + bgMatch->captured(1) + (params.isEmpty() ? QString() : '&' + params); - } else if (auto postMatch = regex_match(qsl("^c/(\\-?\\d+)/(\\d+)(#|$)"), query, matchOptions)) { - return qsl("tg://privatepost?channel=%1&post=%2").arg(postMatch->captured(1)).arg(postMatch->captured(2)); - } else if (auto usernameMatch = regex_match(qsl("^([a-zA-Z0-9\\.\\_]+)(/?\\?|/?$|/(\\d+)/?(?:\\?|$))"), query, matchOptions)) { - auto params = query.mid(usernameMatch->captured(0).size()).toString(); - auto postParam = QString(); - if (auto postMatch = regex_match(qsl("^/\\d+/?(?:\\?|$)"), usernameMatch->captured(2))) { - postParam = qsl("&post=") + usernameMatch->captured(3); - } - return qsl("tg://resolve/?domain=") + url_encode(usernameMatch->captured(1)) + postParam + (params.isEmpty() ? QString() : '&' + params); - } - } - return url; -} - bool UrlRequiresConfirmation(const QUrl &url) { using namespace qthelp; return !regex_match(qsl("(^|\\.)(telegram\\.org|telegra\\.ph|telesco\\.pe)$"), url.host(), RegExOption::CaseInsensitive); @@ -120,7 +68,7 @@ QString UrlClickHandler::url() const { } void UrlClickHandler::Open(QString url, QVariant context) { - url = tryConvertUrlToLocal(url); + url = Core::TryConvertUrlToLocal(url); if (Core::InternalPassportLink(url)) { return; } @@ -143,7 +91,7 @@ auto UrlClickHandler::getTextEntity() const -> TextEntity { } void HiddenUrlClickHandler::Open(QString url, QVariant context) { - url = tryConvertUrlToLocal(url); + url = Core::TryConvertUrlToLocal(url); if (Core::InternalPassportLink(url)) { return; } @@ -174,7 +122,7 @@ void HiddenUrlClickHandler::Open(QString url, QVariant context) { } void BotGameUrlClickHandler::onClick(ClickContext context) const { - const auto url = tryConvertUrlToLocal(this->url()); + const auto url = Core::TryConvertUrlToLocal(this->url()); if (Core::InternalPassportLink(url)) { return; } diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index 9d0ab06c7..d1a7137da 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -401,6 +401,58 @@ const std::vector &LocalUrlHandlers() { return Result; } +QString TryConvertUrlToLocal(QString url) { + if (url.size() > 8192) { + url = url.mid(0, 8192); + } + + using namespace qthelp; + auto matchOptions = RegExOption::CaseInsensitive; + auto telegramMeMatch = regex_match(qsl("^https?://(www\\.)?(telegram\\.(me|dog)|t\\.me)/(.+)$"), url, matchOptions); + if (telegramMeMatch) { + auto query = telegramMeMatch->capturedRef(4); + if (auto joinChatMatch = regex_match(qsl("^joinchat/([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"), query, matchOptions)) { + return qsl("tg://join?invite=") + url_encode(joinChatMatch->captured(1)); + } else if (auto stickerSetMatch = regex_match(qsl("^addstickers/([a-zA-Z0-9\\.\\_]+)(\\?|$)"), query, matchOptions)) { + return qsl("tg://addstickers?set=") + url_encode(stickerSetMatch->captured(1)); + } else if (auto languageMatch = regex_match(qsl("^setlanguage/([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"), query, matchOptions)) { + return qsl("tg://setlanguage?lang=") + url_encode(languageMatch->captured(1)); + } else if (auto shareUrlMatch = regex_match(qsl("^share/url/?\\?(.+)$"), query, matchOptions)) { + return qsl("tg://msg_url?") + shareUrlMatch->captured(1); + } else if (auto confirmPhoneMatch = regex_match(qsl("^confirmphone/?\\?(.+)"), query, matchOptions)) { + return qsl("tg://confirmphone?") + confirmPhoneMatch->captured(1); + } else if (auto ivMatch = regex_match(qsl("^iv/?\\?(.+)(#|$)"), query, matchOptions)) { + // + // We need to show our t.me page, not the url directly. + // + //auto params = url_parse_params(ivMatch->captured(1), UrlParamNameTransform::ToLower); + //auto previewedUrl = params.value(qsl("url")); + //if (previewedUrl.startsWith(qstr("http://"), Qt::CaseInsensitive) + // || previewedUrl.startsWith(qstr("https://"), Qt::CaseInsensitive)) { + // return previewedUrl; + //} + return url; + } else if (auto socksMatch = regex_match(qsl("^socks/?\\?(.+)(#|$)"), query, matchOptions)) { + return qsl("tg://socks?") + socksMatch->captured(1); + } else if (auto proxyMatch = regex_match(qsl("^proxy/?\\?(.+)(#|$)"), query, matchOptions)) { + return qsl("tg://proxy?") + proxyMatch->captured(1); + } else if (auto bgMatch = regex_match(qsl("^bg/([a-zA-Z0-9\\.\\_\\-]+)(\\?(.+)?)?$"), query, matchOptions)) { + const auto params = bgMatch->captured(3); + return qsl("tg://bg?slug=") + bgMatch->captured(1) + (params.isEmpty() ? QString() : '&' + params); + } else if (auto postMatch = regex_match(qsl("^c/(\\-?\\d+)/(\\d+)(#|$)"), query, matchOptions)) { + return qsl("tg://privatepost?channel=%1&post=%2").arg(postMatch->captured(1)).arg(postMatch->captured(2)); + } else if (auto usernameMatch = regex_match(qsl("^([a-zA-Z0-9\\.\\_]+)(/?\\?|/?$|/(\\d+)/?(?:\\?|$))"), query, matchOptions)) { + auto params = query.mid(usernameMatch->captured(0).size()).toString(); + auto postParam = QString(); + if (auto postMatch = regex_match(qsl("^/\\d+/?(?:\\?|$)"), usernameMatch->captured(2))) { + postParam = qsl("&post=") + usernameMatch->captured(3); + } + return qsl("tg://resolve/?domain=") + url_encode(usernameMatch->captured(1)) + postParam + (params.isEmpty() ? QString() : '&' + params); + } + } + return url; +} + bool InternalPassportLink(const QString &url) { const auto urlTrimmed = url.trimmed(); if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive)) { diff --git a/Telegram/SourceFiles/core/local_url_handlers.h b/Telegram/SourceFiles/core/local_url_handlers.h index a24040c08..38c437e64 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.h +++ b/Telegram/SourceFiles/core/local_url_handlers.h @@ -25,10 +25,12 @@ struct LocalUrlHandler { const QVariant &context)> handler; }; -const std::vector &LocalUrlHandlers(); +[[nodiscard]] const std::vector &LocalUrlHandlers(); -bool InternalPassportLink(const QString &url); +[[nodiscard]] QString TryConvertUrlToLocal(QString url); -bool StartUrlRequiresActivate(const QString &url); +[[nodiscard]] bool InternalPassportLink(const QString &url); + +[[nodiscard]] bool StartUrlRequiresActivate(const QString &url); } // namespace Core diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index bef98c114..6722c551b 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -2000,6 +2000,7 @@ bool InnerWidget::hasHistoryInResults(not_null history) const { bool InnerWidget::searchReceived( const QVector &messages, + HistoryItem *inject, SearchRequestType type, int fullCount) { const auto uniquePeers = uniqueSearchResults(); @@ -2010,6 +2011,16 @@ bool InnerWidget::searchReceived( auto isMigratedSearch = (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset); TimeId lastDateFound = 0; + if (inject + && (!_searchInChat + || inject->history() == _searchInChat.history())) { + Assert(_searchResults.empty()); + _searchResults.push_back( + std::make_unique( + _searchInChat, + inject)); + ++fullCount; + } for (const auto &message : messages) { auto msgId = IdFromMessage(message); auto peerId = PeerFromMessage(message); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index da10156be..2a1b6e2f5 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -70,6 +70,7 @@ public: bool searchReceived( const QVector &result, + HistoryItem *inject, SearchRequestType type, int fullCount); void peerSearchReceived( diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 79f27cc42..b1a39c5b6 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -166,7 +166,8 @@ Widget::Widget( , _cancelSearch(_searchControls, st::dialogsCancelSearch) , _lockUnlock(_searchControls, st::dialogsLock) , _scroll(this, st::dialogsScroll) -, _scrollToTop(_scroll, st::dialogsToUp) { +, _scrollToTop(_scroll, st::dialogsToUp) +, _singleMessageSearch(&controller->session()) { _inner = _scroll->setOwnedWidget(object_ptr(this, controller)); rpl::combine( @@ -380,6 +381,7 @@ void Widget::fullSearchRefreshOn(rpl::producer<> events) { }) | rpl::start_with_next([=] { _searchTimer.stop(); _searchCache.clear(); + _singleMessageSearch.clear(); _searchQueries.clear(); _searchQuery = QString(); _scroll->scrollToY(0); @@ -730,6 +732,12 @@ bool Widget::onSearchMessages(bool searchCache) { return true; } if (searchCache) { + const auto success = _singleMessageSearch.lookup(q, [=] { + onNeedSearchMessages(); + }); + if (!success) { + return false; + } const auto i = _searchCache.constFind(q); if (i != _searchCache.cend()) { _searchQuery = q; @@ -992,6 +1000,10 @@ void Widget::searchReceived( } } } + const auto inject = (type == SearchRequestType::FromStart + || type == SearchRequestType::PeerFromStart) + ? *_singleMessageSearch.lookup(_searchQuery) + : nullptr; if (_searchRequest == requestId) { switch (result.type()) { @@ -1003,7 +1015,7 @@ void Widget::searchReceived( session().data().processChats(d.vchats()); } auto &msgs = d.vmessages().v; - _inner->searchReceived(msgs, type, msgs.size()); + _inner->searchReceived(msgs, inject, type, msgs.size()); if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { _searchFullMigrated = true; } else { @@ -1019,7 +1031,7 @@ void Widget::searchReceived( session().data().processChats(d.vchats()); } auto &msgs = d.vmessages().v; - const auto someAdded = _inner->searchReceived(msgs, type, d.vcount().v); + const auto someAdded = _inner->searchReceived(msgs, inject, type, d.vcount().v); const auto nextRate = d.vnext_rate(); const auto rateUpdated = nextRate && (nextRate->v != _searchNextRate); const auto finished = (type == SearchRequestType::FromStart || type == SearchRequestType::FromOffset) @@ -1058,7 +1070,7 @@ void Widget::searchReceived( session().data().processChats(d.vchats()); } auto &msgs = d.vmessages().v; - if (!_inner->searchReceived(msgs, type, d.vcount().v)) { + if (!_inner->searchReceived(msgs, inject, type, d.vcount().v)) { if (type == SearchRequestType::MigratedFromStart || type == SearchRequestType::MigratedFromOffset) { _searchFullMigrated = true; } else { @@ -1292,6 +1304,7 @@ void Widget::setSearchInChat(Key chat, UserData *from) { void Widget::clearSearchCache() { _searchCache.clear(); + _singleMessageSearch.clear(); _searchQueries.clear(); _searchQuery = QString(); _searchQueryFrom = nullptr; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index 01808db86..b26ec7932 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -7,11 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "dialogs/dialogs_key.h" #include "window/section_widget.h" #include "ui/effects/animations.h" #include "ui/widgets/scroll_area.h" -#include "dialogs/dialogs_key.h" #include "ui/special_buttons.h" +#include "api/api_single_message_search.h" namespace Main { class Session; @@ -218,17 +219,11 @@ private: bool _searchFullMigrated = false; mtpRequestId _searchRequest = 0; - using SearchCache = QMap; - SearchCache _searchCache; - - using SearchQueries = QMap; - SearchQueries _searchQueries; - - using PeerSearchCache = QMap; - PeerSearchCache _peerSearchCache; - - using PeerSearchQueries = QMap; - PeerSearchQueries _peerSearchQueries; + QMap _searchCache; + Api::SingleMessageSearch _singleMessageSearch; + QMap _searchQueries; + QMap _peerSearchCache; + QMap _peerSearchQueries; QPixmap _widthAnimationCache; diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index 02e4e2ffd..5c57e2d44 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -1,5 +1,7 @@ <(src_loc)/api/api_sending.cpp <(src_loc)/api/api_sending.h +<(src_loc)/api/api_single_message_search.cpp +<(src_loc)/api/api_single_message_search.h <(src_loc)/boxes/peers/add_participants_box.cpp <(src_loc)/boxes/peers/add_participants_box.h <(src_loc)/boxes/peers/edit_contact_box.cpp