diff --git a/Telegram/SourceFiles/api/api_messages_search.cpp b/Telegram/SourceFiles/api/api_messages_search.cpp index 13a0e96bf7..ac348199bc 100644 --- a/Telegram/SourceFiles/api/api_messages_search.cpp +++ b/Telegram/SourceFiles/api/api_messages_search.cpp @@ -58,9 +58,23 @@ constexpr auto kSearchPerPage = 50; result += u"emoji"_q + tag.emoji(); } } + switch (request.filter) { + case SearchFilter::NoFilter: break; + case SearchFilter::Pinned: result += u"\npinned"_q; break; + } return result; } +[[nodiscard]] MTPMessagesFilter PrepareFilter(SearchFilter filter) { + switch (filter) { + case SearchFilter::Pinned: + return MTP_inputMessagesFilterPinned(); + case SearchFilter::NoFilter: + return MTP_inputMessagesFilterEmpty(); + } + return MTP_inputMessagesFilterEmpty(); +} + } // namespace MessagesSearch::MessagesSearch(not_null history) @@ -113,7 +127,7 @@ void MessagesSearch::searchRequest() { Data::ReactionToMTP )), MTP_int(_request.topMsgId), // top_msg_id - MTP_inputMessagesFilterEmpty(), + PrepareFilter(_request.filter), MTP_int(0), // min_date MTP_int(0), // max_date MTP_int(_offsetId), // offset_id diff --git a/Telegram/SourceFiles/api/api_messages_search.h b/Telegram/SourceFiles/api/api_messages_search.h index b650b87994..99b222b703 100644 --- a/Telegram/SourceFiles/api/api_messages_search.h +++ b/Telegram/SourceFiles/api/api_messages_search.h @@ -20,6 +20,11 @@ struct ReactionId; namespace Api { +enum class SearchFilter { + NoFilter, + Pinned, +}; + struct FoundMessages { int total = -1; MessageIdsList messages; @@ -33,6 +38,7 @@ public: PeerData *from = nullptr; std::vector tags; MsgId topMsgId; + SearchFilter filter = SearchFilter::NoFilter; friend inline bool operator==( const Request &, 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 9171f2a9f1..6d232c4bd2 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_search.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_search.cpp @@ -866,6 +866,7 @@ public: void setInnerFocus(); void setQuery(const QString &query); void setTopMsgId(MsgId topMsgId); + void setSearchFilter(Api::SearchFilter filter); [[nodiscard]] rpl::producer activations() const; [[nodiscard]] rpl::producer<> destroyRequests() const; @@ -892,6 +893,8 @@ private: } _pendingJump; MsgId _topMsgId; + Api::SearchFilter _searchFilter = Api::SearchFilter::NoFilter; + rpl::variable _filterAllowsFrom = true; rpl::event_stream _activations; rpl::event_stream<> _destroyRequests; @@ -942,6 +945,7 @@ ComposeSearch::Inner::Inner( } } search.topMsgId = _topMsgId; + search.filter = _searchFilter; _apiSearch.clear(); _list.controller->addItems({}, true); @@ -1063,9 +1067,11 @@ ComposeSearch::Inner::Inner( return !from; })); - _bottomBar->buttonFromToggleOn(_topBar->fromValue( - ) | rpl::map([=](PeerData *from) { - return HasChooseFrom(_history) && !from; + _bottomBar->buttonFromToggleOn(rpl::combine( + _topBar->fromValue(), + _filterAllowsFrom.value() + ) | rpl::map([=](PeerData *from, bool allowed) { + return allowed && HasChooseFrom(_history) && !from; })); if (!query.isEmpty()) { @@ -1090,6 +1096,11 @@ void ComposeSearch::Inner::setTopMsgId(MsgId topMsgId) { _topMsgId = topMsgId; } +void ComposeSearch::Inner::setSearchFilter(Api::SearchFilter filter) { + _searchFilter = filter; + _filterAllowsFrom = (filter != Api::SearchFilter::Pinned); +} + void ComposeSearch::Inner::showAnimated() { // Don't animate bottom bar. _bottomBar->show(); @@ -1152,6 +1163,10 @@ void ComposeSearch::setTopMsgId(MsgId topMsgId) { _inner->setTopMsgId(topMsgId); } +void ComposeSearch::setSearchFilter(Api::SearchFilter filter) { + _inner->setSearchFilter(filter); +} + rpl::producer ComposeSearch::activations() const { return _inner->activations(); } diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_search.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_search.h index dc8c3140d1..8b25830ec0 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_search.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_search.h @@ -11,6 +11,10 @@ namespace Window { class SessionController; } // namespace Window +namespace Api { +enum class SearchFilter; +} // namespace Api + namespace Ui { class RpWidget; } // namespace Ui @@ -34,6 +38,7 @@ public: void setQuery(const QString &query); void setTopMsgId(MsgId topMsgId); + void setSearchFilter(Api::SearchFilter filter); struct Activation { not_null item; diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp index d9f9196f49..20f9a8164f 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp @@ -10,6 +10,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_top_bar_widget.h" #include "history/view/history_view_translate_bar.h" #include "history/view/history_view_list_widget.h" +#include "history/view/controls/history_view_compose_search.h" +#include "api/api_messages_search.h" +#include "data/data_forum_topic.h" #include "data/data_chat_participant_status.h" #include "history/history.h" #include "history/history_item_components.h" @@ -34,7 +37,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/event_filter.h" #include "base/call_delayed.h" #include "base/qt/qt_key_modifiers.h" +#include "core/application.h" #include "core/file_utilities.h" +#include "core/shortcuts.h" #include "main/main_session.h" #include "data/data_session.h" #include "data/data_user.h" @@ -158,6 +163,10 @@ PinnedWidget::PinnedWidget( ) | rpl::on_next([=] { clearSelected(); }, _topBar->lifetime()); + _topBar->searchRequest( + ) | rpl::on_next([=] { + searchInPinned(); + }, _topBar->lifetime()); _translateBar->raise(); _topBarShadow->raise(); @@ -184,6 +193,7 @@ PinnedWidget::PinnedWidget( setupClearButton(); setupTranslateBar(); + setupShortcuts(); Window::SetupSwipeBackSection(this, _scroll.get(), _inner); } @@ -236,6 +246,62 @@ void PinnedWidget::setupTranslateBar() { _translateBar->finishAnimating(); } +void PinnedWidget::setupShortcuts() { + Shortcuts::Requests( + ) | rpl::filter([=] { + return Ui::AppInFocus() + && Ui::InFocusChain(this) + && !controller()->isLayerShown() + && (Core::App().activeWindow() == &controller()->window()) + && !_history->peer->isSelf(); + }) | rpl::on_next([=](not_null request) { + using Command = Shortcuts::Command; + request->check(Command::Search, 1) && request->handle([=] { + searchInPinned(); + return true; + }); + }, lifetime()); +} + +void PinnedWidget::searchInPinned() { + if (_history->peer->isSelf()) { + return; + } + if (_composeSearch) { + _composeSearch->setInnerFocus(); + return; + } + _composeSearch = std::make_unique( + this, + controller(), + _history, + nullptr); + _composeSearch->setSearchFilter(Api::SearchFilter::Pinned); + if (const auto topic = _thread->asTopic()) { + _composeSearch->setTopMsgId(topic->rootId()); + } + + _topBarShadow->hide(); + _clearButton->hide(); + updateControlsGeometry(); + doSetInnerFocus(); + + _composeSearch->activations( + ) | rpl::on_next([=](ComposeSearch::Activation activation) { + showAtPosition(activation.item->position()); + }, _composeSearch->lifetime()); + + _composeSearch->destroyRequests( + ) | rpl::take(1) | rpl::on_next([=] { + _composeSearch = nullptr; + + _topBarShadow->show(); + _clearButton->show(); + updateControlsGeometry(); + doSetInnerFocus(); + }, _composeSearch->lifetime()); +} + void PinnedWidget::cornerButtonsShowAtPosition( Data::MessagePosition position) { showAtPosition(position); @@ -312,7 +378,11 @@ void PinnedWidget::checkActivation() { } void PinnedWidget::doSetInnerFocus() { - _inner->setFocus(); + if (_composeSearch) { + _composeSearch->setInnerFocus(); + } else { + _inner->setFocus(); + } } bool PinnedWidget::showInternal( diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.h b/Telegram/SourceFiles/history/view/history_view_pinned_section.h index 23b7f0a137..a24f0b1c84 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.h +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.h @@ -31,6 +31,7 @@ namespace HistoryView { class Element; class TopBarWidget; +class ComposeSearch; class PinnedMemento; class TranslateBar; @@ -170,6 +171,8 @@ private: void setupClearButton(); void setupTranslateBar(); + void setupShortcuts(); + void searchInPinned(); void confirmDeleteSelected(); void confirmForwardSelected(); @@ -193,6 +196,7 @@ private: bool _skipScrollEvent = false; std::unique_ptr _scroll; std::unique_ptr _clearButton; + std::unique_ptr _composeSearch; CornerButtons _cornerButtons; diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index 6545f70d32..6397d451cc 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -1028,8 +1028,13 @@ int TopBarWidget::countSelectedButtonsTop(float64 selectedShown) { } void TopBarWidget::updateSearchVisibility() { + const auto pinnedInSavedMessages = (_activeChat.section == Section::Pinned) + && _activeChat.key.peer() + && _activeChat.key.peer()->isSelf(); const auto searchAllowedMode = (_activeChat.section == Section::History) || (_activeChat.section == Section::Replies) + || (_activeChat.section == Section::Pinned + && !pinnedInSavedMessages) || (_activeChat.section == Section::SavedSublist && _activeChat.key.sublist()); _search->setVisible(searchAllowedMode && !_chooseForReportReason);