Support tags search in sublists.

This commit is contained in:
John Preston 2024-01-30 17:52:04 +04:00
parent 0163938e00
commit 30548c2859
9 changed files with 195 additions and 68 deletions

View file

@ -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 = [&] {

View file

@ -4797,18 +4797,31 @@ void HistoryWidget::searchInChat() {
}
}
void HistoryWidget::searchInChatEmbedded(std::optional<QString> 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<QString> query) {
controller(),
_history,
from,
query.value_or(QString()));
query);
update();
setInnerFocus();
_composeSearch->activations(
) | rpl::start_with_next([=](not_null<HistoryItem*> 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)) {

View file

@ -251,7 +251,7 @@ public:
[[nodiscard]] rpl::producer<> cancelRequests() const {
return _cancelRequests.events();
}
void searchInChatEmbedded(std::optional<QString> 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;

View file

@ -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<Dialogs::SearchTags>(
&_history->owner(),
reactions->myTagsValue(sublist),
std::move(fullTagsList),
_searchTagsSelected);
const auto parent = _searchTags->lifetime().make_state<Ui::RpWidget>(
@ -822,6 +822,7 @@ public:
void setInnerFocus();
void setQuery(const QString &query);
[[nodiscard]] rpl::producer<not_null<HistoryItem*>> activations() const;
[[nodiscard]] rpl::producer<> destroyRequests() const;
[[nodiscard]] rpl::lifetime &lifetime();
@ -845,6 +846,7 @@ private:
rpl::event_stream<BottomBar::Index> jumps;
} _pendingJump;
rpl::event_stream<not_null<HistoryItem*>> _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<not_null<HistoryItem*>> {
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<not_null<HistoryItem*>> ComposeSearch::activations() const {
return _inner->activations();
}
rpl::producer<> ComposeSearch::destroyRequests() const {
return _inner->destroyRequests();
}

View file

@ -33,6 +33,7 @@ public:
void setInnerFocus();
void setQuery(const QString &query);
[[nodiscard]] rpl::producer<not_null<HistoryItem*>> activations() const;
[[nodiscard]] rpl::producer<> destroyRequests() const;
[[nodiscard]] rpl::lifetime &lifetime();

View file

@ -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 &params) {
_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<Data::SavedSublist*> 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 &params) {
QPixmap SublistWidget::grabForShowAnimation(
const Window::SectionSlideParams &params) {
_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<HistoryView::ComposeSearch>(
this,
controller(),
_history,
sublist->peer(),
query);
updateControlsGeometry();
setInnerFocus();
_composeSearch->activations(
) | rpl::start_with_next([=](not_null<HistoryItem*> 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<Window::SectionMemento> SublistWidget::createMemento() {
auto result = std::make_shared<SublistMemento>(sublist());
saveState(result.get());
@ -323,7 +377,30 @@ bool SublistWidget::showMessage(
PeerId peerId,
const Window::SectionShow &params,
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<OriginMessage>(&params.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<SublistMemento*> 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<HistoryItem*> item) {

View file

@ -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 &params);
void setupOpenChatButton();
void setupAboutHiddenAuthor();
@ -189,7 +196,9 @@ private:
std::unique_ptr<Ui::ScrollArea> _scroll;
std::unique_ptr<Ui::FlatButton> _openChatButton;
std::unique_ptr<Ui::RpWidget> _aboutHiddenAuthor;
std::unique_ptr<ComposeSearch> _composeSearch;
FullMsgId _lastShownAt;
CornerButtons _cornerButtons;
};

View file

@ -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<HistoryView::SublistMemento>(sublist));
} else if (!Data::SearchTagsFromQuery(query).empty()) {
inChat = controller()->session().data().history(
controller()->session().user());
}
const auto searchIn = [&](not_null<Window::Controller*> 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);
}
}
}

View file

@ -148,6 +148,9 @@ public:
MsgId messageId) {
return false;
}
virtual bool searchInChatEmbedded(Dialogs::Key chat, QString query) {
return false;
}
[[nodiscard]] virtual bool preventsClose(
Fn<void()> &&continueCallback) const {