From 30548c2859591259f7cc74c5983bf538564facbe Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 30 Jan 2024 17:52:04 +0400 Subject: [PATCH] Support tags search in sublists. --- .../SourceFiles/dialogs/dialogs_widget.cpp | 4 +- .../SourceFiles/history/history_widget.cpp | 46 ++++++-- Telegram/SourceFiles/history/history_widget.h | 3 +- .../controls/history_view_compose_search.cpp | 63 ++++++----- .../controls/history_view_compose_search.h | 1 + .../view/history_view_sublist_section.cpp | 104 ++++++++++++++++-- .../view/history_view_sublist_section.h | 9 ++ Telegram/SourceFiles/mainwidget.cpp | 30 +++-- Telegram/SourceFiles/window/section_widget.h | 3 + 9 files changed, 195 insertions(+), 68 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 77d02b8ed..3dd0866d1 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1930,7 +1930,9 @@ void Widget::searchMessages(QString query, Key inChat) { auto tags = Data::SearchTagsFromQuery(query); if (!tags.empty()) { - inChat = session().data().history(session().user()); + if (!inChat.sublist()) { + inChat = session().data().history(session().user()); + } query = QString(); } const auto inChatChanged = [&] { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index d59e7c36a..6583d98ff 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -4797,18 +4797,31 @@ void HistoryWidget::searchInChat() { } } -void HistoryWidget::searchInChatEmbedded(std::optional query) { - if (!_history) { - return; - } else if (_composeSearch) { - if (query) { - _composeSearch->setQuery(*query); +bool HistoryWidget::searchInChatEmbedded(Dialogs::Key chat, QString query) { + const auto peer = chat.peer(); + if (!peer || peer != controller()->singlePeer()) { + return false; + } else if (_peer != peer) { + const auto weak = Ui::MakeWeak(this); + controller()->showPeerHistory(peer); + if (!weak) { + return false; } - _composeSearch->setInnerFocus(); - return; } + if (_peer != peer) { + return false; + } else if (_composeSearch) { + _composeSearch->setQuery(query); + _composeSearch->setInnerFocus(); + return true; + } + switchToSearch(query); + return true; +} + +void HistoryWidget::switchToSearch(QString query) { const auto search = crl::guard(_list, [=] { - if (!_history) { + if (!_peer) { return; } const auto update = [=] { @@ -4824,18 +4837,27 @@ void HistoryWidget::searchInChatEmbedded(std::optional query) { controller(), _history, from, - query.value_or(QString())); + query); update(); setInnerFocus(); + + _composeSearch->activations( + ) | rpl::start_with_next([=](not_null item) { + controller()->showPeerHistory( + item->history()->peer->id, + ::Window::SectionShow::Way::ClearStack, + item->fullId().msg); + }, _composeSearch->lifetime()); + _composeSearch->destroyRequests( ) | rpl::take( 1 ) | rpl::start_with_next([=] { _composeSearch = nullptr; - update(); - setInnerFocus(); + update(); + setInnerFocus(); }, _composeSearch->lifetime()); }); if (!preventsClose(search)) { diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 6ec45fba4..3dc348933 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -251,7 +251,7 @@ public: [[nodiscard]] rpl::producer<> cancelRequests() const { return _cancelRequests.events(); } - void searchInChatEmbedded(std::optional query = {}); + bool searchInChatEmbedded(Dialogs::Key chat, QString query); void updateNotifyControls(); @@ -642,6 +642,7 @@ private: bool kbWasHidden() const; void searchInChat(); + void switchToSearch(QString query); MTP::Sender _api; FullReplyTo _replyTo; 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 5d3b1eee1..14e56a3fb 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_search.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_search.cpp @@ -329,6 +329,9 @@ TopBar::TopBar( , _window(window) , _history(history) , _searchTimer([=] { requestSearch(); }) { + if (from) { + setFrom(from); + } refreshTags(); moveToLeft(0, 0); @@ -367,10 +370,6 @@ TopBar::TopBar( _select->setCancelledCallback([=] { _cancelRequests.fire({}); }); - - if (from) { - setFrom(from); - } } void TopBar::keyPressEvent(QKeyEvent *e) { @@ -425,14 +424,15 @@ void TopBar::refreshTags() { _searchTags = nullptr; return; } - const auto from = _from.current(); - const auto reactions = &_history->owner().reactions(); - const auto sublist = from - ? _history->owner().savedMessages().sublist(from).get() - : nullptr; + auto fullTagsList = _from.value() | rpl::map([=](PeerData *from) { + const auto sublist = from + ? _history->owner().savedMessages().sublist(from).get() + : nullptr; + return _history->owner().reactions().myTagsValue(sublist); + }) | rpl::flatten_latest(); _searchTags = std::make_unique( &_history->owner(), - reactions->myTagsValue(sublist), + std::move(fullTagsList), _searchTagsSelected); const auto parent = _searchTags->lifetime().make_state( @@ -822,6 +822,7 @@ public: void setInnerFocus(); void setQuery(const QString &query); + [[nodiscard]] rpl::producer> activations() const; [[nodiscard]] rpl::producer<> destroyRequests() const; [[nodiscard]] rpl::lifetime &lifetime(); @@ -845,6 +846,7 @@ private: rpl::event_stream jumps; } _pendingJump; + rpl::event_stream> _activations; rpl::event_stream<> _destroyRequests; }; @@ -881,8 +883,10 @@ ComposeSearch::Inner::Inner( _topBar->searchRequests( ) | rpl::start_with_next([=](const SearchRequest &search) { - if (search.query.isEmpty() && !search.from && search.tags.empty()) { - return; + if (search.query.isEmpty() && search.tags.empty()) { + if (!search.from || _history->peer->isSelf()) { + return; + } } _apiSearch.clear(); _apiSearch.search(search); @@ -910,8 +914,12 @@ ComposeSearch::Inner::Inner( _apiSearch.newFounds( ) | rpl::start_with_next([=] { const auto &apiData = _apiSearch.messages(); + const auto weak = Ui::MakeWeak(_bottomBar.get()); _bottomBar->setTotal(apiData.total); - _list.controller->addItems(apiData.messages, true); + if (weak) { + // Activating the first search result may switch the chat. + _list.controller->addItems(apiData.messages, true); + } }, _topBar->lifetime()); _apiSearch.nextFounds( @@ -922,16 +930,6 @@ ComposeSearch::Inner::Inner( _list.controller->addItems(_apiSearch.messages().messages, false); }, _topBar->lifetime()); - const auto goToMessage = [=](const FullMsgId &itemId) { - const auto item = _history->owner().message(itemId); - if (item) { - _window->showPeerHistory( - item->history()->peer->id, - ::Window::SectionShow::Way::ClearStack, - item->fullId().msg); - } - }; - rpl::merge( _pendingJump.jumps.events() | rpl::filter(rpl::mappers::_1 >= 0), _bottomBar->showItemRequests() @@ -947,8 +945,14 @@ ComposeSearch::Inner::Inner( return; } _pendingJump.data = {}; - goToMessage(messages[index]); - hideList(); + const auto item = _history->owner().message(messages[index]); + if (item) { + const auto weak = Ui::MakeWeak(_topBar.get()); + _activations.fire_copy(item); + if (weak) { + hideList(); + } + } }, _bottomBar->lifetime()); _list.controller->showItemRequests( @@ -1039,6 +1043,11 @@ void ComposeSearch::Inner::hideList() { } } +auto ComposeSearch::Inner::activations() const +-> rpl::producer> { + return _activations.events(); +} + rpl::producer<> ComposeSearch::Inner::destroyRequests() const { return _destroyRequests.events(); } @@ -1074,6 +1083,10 @@ void ComposeSearch::setQuery(const QString &query) { _inner->setQuery(query); } +rpl::producer> ComposeSearch::activations() const { + return _inner->activations(); +} + rpl::producer<> ComposeSearch::destroyRequests() const { return _inner->destroyRequests(); } 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 9090c0daa..67c995ddd 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_search.h +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_search.h @@ -33,6 +33,7 @@ public: void setInnerFocus(); void setQuery(const QString &query); + [[nodiscard]] rpl::producer> activations() const; [[nodiscard]] rpl::producer<> destroyRequests() const; [[nodiscard]] rpl::lifetime &lifetime(); diff --git a/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp b/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp index e96738d0d..5f64ad27f 100644 --- a/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_sublist_section.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_peer_values.h" #include "data/data_user.h" +#include "history/view/controls/history_view_compose_search.h" #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" @@ -221,7 +222,7 @@ Data::Thread *SublistWidget::cornerButtonsThread() { } FullMsgId SublistWidget::cornerButtonsCurrentId() { - return {}; + return _lastShownAt; } bool SublistWidget::cornerButtonsIgnoreVisibility() { @@ -249,12 +250,20 @@ bool SublistWidget::cornerButtonsHas(CornerButtonType type) { void SublistWidget::showAtPosition( Data::MessagePosition position, FullMsgId originId) { - _inner->showAtPosition( - position, - {}, - _cornerButtons.doneJumpFrom(position.fullId, originId)); + showAtPosition(position, originId, {}); } +void SublistWidget::showAtPosition( + Data::MessagePosition position, + FullMsgId originItemId, + const Window::SectionShow ¶ms) { + _lastShownAt = position.fullId; + controller()->setActiveChatEntry(activeChat()); + _inner->showAtPosition( + position, + params, + _cornerButtons.doneJumpFrom(position.fullId, originItemId)); +} void SublistWidget::updateAdaptiveLayout() { _topBarShadow->moveToLeft( controller()->adaptive().isOneColumn() ? 0 : st::lineWidth, @@ -266,13 +275,14 @@ not_null SublistWidget::sublist() const { } Dialogs::RowDescriptor SublistWidget::activeChat() const { - return { - _sublist, - FullMsgId(_history->peer->id, ShowAtUnreadMsgId) - }; + const auto messageId = _lastShownAt + ? _lastShownAt + : FullMsgId(_history->peer->id, ShowAtUnreadMsgId); + return { _sublist, messageId }; } -QPixmap SublistWidget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) { +QPixmap SublistWidget::grabForShowAnimation( + const Window::SectionSlideParams ¶ms) { _topBar->updateControlsVisibility(); if (params.withTopBarShadow) _topBarShadow->hide(); auto result = Ui::GrabWidget(this); @@ -286,7 +296,11 @@ void SublistWidget::checkActivation() { } void SublistWidget::doSetInnerFocus() { - _inner->setFocus(); + if (_composeSearch) { + _composeSearch->setInnerFocus(); + } else { + _inner->setFocus(); + } } bool SublistWidget::showInternal( @@ -313,6 +327,46 @@ void SublistWidget::setInternalState( restoreState(memento); } +bool SublistWidget::searchInChatEmbedded(Dialogs::Key chat, QString query) { + const auto sublist = chat.sublist(); + if (!sublist || sublist != _sublist) { + return false; + } else if (_composeSearch) { + _composeSearch->setQuery(query); + _composeSearch->setInnerFocus(); + return true; + } + _composeSearch = std::make_unique( + this, + controller(), + _history, + sublist->peer(), + query); + + updateControlsGeometry(); + setInnerFocus(); + + _composeSearch->activations( + ) | rpl::start_with_next([=](not_null item) { + controller()->showPeerHistory( + item->history()->peer->id, + ::Window::SectionShow::Way::ClearStack, + item->fullId().msg); + }, _composeSearch->lifetime()); + + _composeSearch->destroyRequests( + ) | rpl::take( + 1 + ) | rpl::start_with_next([=] { + _composeSearch = nullptr; + + updateControlsGeometry(); + setInnerFocus(); + }, _composeSearch->lifetime()); + + return true; +} + std::shared_ptr SublistWidget::createMemento() { auto result = std::make_shared(sublist()); saveState(result.get()); @@ -323,7 +377,30 @@ bool SublistWidget::showMessage( PeerId peerId, const Window::SectionShow ¶ms, MsgId messageId) { - return false; // We want 'Go to original' to work. + const auto id = FullMsgId(_history->peer->id, messageId); + const auto message = _history->owner().message(id); + if (!message || message->savedSublist() != _sublist) { + return false; + } + const auto originMessage = [&]() -> HistoryItem* { + using OriginMessage = Window::SectionShow::OriginMessage; + if (const auto origin = std::get_if(¶ms.origin)) { + if (const auto returnTo = session().data().message(origin->id)) { + if (returnTo->savedSublist() == _sublist) { + return returnTo; + } + } + } + return nullptr; + }(); + const auto currentReplyReturn = _cornerButtons.replyReturn(); + const auto originItemId = !originMessage + ? FullMsgId() + : (currentReplyReturn != originMessage) + ? originMessage->fullId() + : FullMsgId(); + showAtPosition(message->position(), originItemId, params); + return true; } void SublistWidget::saveState(not_null memento) { @@ -555,6 +632,9 @@ void SublistWidget::listSelectionChanged(SelectedItems &&items) { } } _topBar->showSelected(state); + if ((state.count > 0) && _composeSearch) { + _composeSearch->hideAnimated(); + } } void SublistWidget::listMarkReadTill(not_null item) { diff --git a/Telegram/SourceFiles/history/view/history_view_sublist_section.h b/Telegram/SourceFiles/history/view/history_view_sublist_section.h index ff6d34ace..3a4bed40b 100644 --- a/Telegram/SourceFiles/history/view/history_view_sublist_section.h +++ b/Telegram/SourceFiles/history/view/history_view_sublist_section.h @@ -33,6 +33,7 @@ class Element; class TopBarWidget; class SublistMemento; class TranslateBar; +class ComposeSearch; class SublistWidget final : public Window::SectionWidget @@ -75,6 +76,8 @@ public: return Window::SectionActionResult::Fallback; } + bool searchInChatEmbedded(Dialogs::Key chat, QString query) override; + // Float player interface. bool floatPlayerHandleWheelEvent(QEvent *e) override; QRect floatPlayerAvailableRect() override; @@ -163,6 +166,10 @@ private: void showAtPosition( Data::MessagePosition position, FullMsgId originId = {}); + void showAtPosition( + Data::MessagePosition position, + FullMsgId originItemId, + const Window::SectionShow ¶ms); void setupOpenChatButton(); void setupAboutHiddenAuthor(); @@ -189,7 +196,9 @@ private: std::unique_ptr _scroll; std::unique_ptr _openChatButton; std::unique_ptr _aboutHiddenAuthor; + std::unique_ptr _composeSearch; + FullMsgId _lastShownAt; CornerButtons _cornerButtons; }; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 8431c90ac..34813a30a 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -49,6 +49,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item_helpers.h" // GetErrorTextForSending. #include "history/view/media/history_view_media.h" #include "history/view/history_view_service_message.h" +#include "history/view/history_view_sublist_section.h" #include "lang/lang_keys.h" #include "lang/lang_cloud_manager.h" #include "inline_bots/inline_bot_layout_item.h" @@ -727,28 +728,23 @@ void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) { _dialogs->setInnerFocus(); } } else { - if (!Data::SearchTagsFromQuery(query).empty()) { + if (const auto sublist = inChat.sublist()) { + controller()->showSection( + std::make_shared(sublist)); + } else if (!Data::SearchTagsFromQuery(query).empty()) { inChat = controller()->session().data().history( controller()->session().user()); } - const auto searchIn = [&](not_null window) { - if (const auto controller = window->sessionController()) { - controller->content()->searchMessages(query, inChat); - controller->widget()->activate(); - } - }; - const auto account = &session().account(); - if (const auto peer = inChat.peer()) { - if (peer == controller()->singlePeer()) { - if (_history->peer() != peer) { - controller()->showPeerHistory(peer); + if ((!_mainSection + || !_mainSection->searchInChatEmbedded(inChat, query)) + && !_history->searchInChatEmbedded(inChat, query)) { + const auto account = &session().account(); + if (const auto window = Core::App().windowFor(account)) { + if (const auto controller = window->sessionController()) { + controller->content()->searchMessages(query, inChat); + controller->widget()->activate(); } - _history->searchInChatEmbedded(query); - } else if (const auto window = Core::App().windowFor(peer)) { - searchIn(window); } - } else if (const auto window = Core::App().windowFor(account)) { - searchIn(window); } } } diff --git a/Telegram/SourceFiles/window/section_widget.h b/Telegram/SourceFiles/window/section_widget.h index 10cf3f1e9..c428c4d0f 100644 --- a/Telegram/SourceFiles/window/section_widget.h +++ b/Telegram/SourceFiles/window/section_widget.h @@ -148,6 +148,9 @@ public: MsgId messageId) { return false; } + virtual bool searchInChatEmbedded(Dialogs::Key chat, QString query) { + return false; + } [[nodiscard]] virtual bool preventsClose( Fn &&continueCallback) const {