From a1d21cf452eb4d2d41cd56b06b4063204aecea3e Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 21 Mar 2022 17:35:31 +0300 Subject: [PATCH] Added ability to search messages from specific peer in dialogs. --- Telegram/SourceFiles/dialogs/dialogs.style | 5 + .../controls/history_view_compose_search.cpp | 176 +++++++++++++++--- 2 files changed, 160 insertions(+), 21 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index e3f4bbc579..f5d842caac 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -187,6 +187,11 @@ dialogCalendar: IconButton(dialogsMenuToggle) { rippleAreaPosition: point(3px, 3px); rippleAreaSize: 34px; } +dialogSearchFrom: IconButton(dialogCalendar) { + icon: icon {{ "dialogs/dialogs_search_from", lightButtonFg }}; + iconOver: icon {{ "dialogs/dialogs_search_from", lightButtonFgOver }}; + iconPosition: point(9px, 8px); +} dialogsChatTypeSkip: 20px; dialogsChatIcon: icon {{ "dialogs/dialogs_chat", dialogsChatIconFg, point(1px, 4px) }}; 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 610c25fb1f..46ec1cefcd 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_search.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_search.cpp @@ -8,7 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/controls/history_view_compose_search.h" #include "api/api_messages_search.h" +#include "boxes/peer_list_box.h" // PaintUserpicCallback #include "data/data_session.h" +#include "dialogs/dialogs_search_from_controllers.h" // SearchFromBox #include "history/history.h" #include "history/history_item.h" #include "lang/lang_keys.h" @@ -25,19 +27,42 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { namespace { +[[nodiscard]] inline bool HasChooseFrom(not_null history) { + if (const auto peer = history->peer) { + return (peer->isChat() || peer->isMegagroup()); + } + return false; +} + +struct SearchRequest { + QString query; + PeerData *from = nullptr; +}; + class TopBar final : public Ui::RpWidget { public: TopBar(not_null parent); - [[nodiscard]] rpl::producer searchRequests() const; + [[nodiscard]] PeerData *from() const; + + [[nodiscard]] rpl::producer searchRequests() const; + [[nodiscard]] rpl::producer fromValue() const; + + void setFrom(PeerData *peer); private: + void clearItems(); + void requestSearch(); + void requestSearchDelayed(); + base::unique_qptr _cancel; base::unique_qptr _select; + rpl::variable _from = nullptr;; + base::Timer _searchTimer; - rpl::event_stream _searchRequests; + rpl::event_stream _searchRequests; }; TopBar::TopBar(not_null parent) @@ -47,7 +72,7 @@ TopBar::TopBar(not_null parent) this, st::searchInChatMultiSelect, tr::lng_dlg_filter())) -, _searchTimer([=] { _searchRequests.fire(_select->getQuery()); }) { +, _searchTimer([=] { requestSearch(); }) { parent->geometryValue( ) | rpl::start_with_next([=](const QRect &r) { @@ -72,12 +97,12 @@ TopBar::TopBar(not_null parent) p.fillRect(r, st::dialogsBg); }, lifetime()); - _select->setQueryChangedCallback([=](const QString &query) { - _searchTimer.callOnce(AutoSearchTimeout); + _select->setQueryChangedCallback([=](const QString &) { + requestSearchDelayed(); }); _select->setSubmittedCallback([=](Qt::KeyboardModifiers) { - _searchRequests.fire(_select->getQuery()); + requestSearch(); }); _select->setCancelledCallback([=] { @@ -85,19 +110,71 @@ TopBar::TopBar(not_null parent) }); } -rpl::producer TopBar::searchRequests() const { +void TopBar::clearItems() { + _select->setItemRemovedCallback(nullptr); + + for (const auto &id : _select->getItems()) { + _select->removeItem(id); + } + + _select->setItemRemovedCallback([=](uint64) { + _from = nullptr; + requestSearchDelayed(); + }); +} + +void TopBar::requestSearch() { + _searchRequests.fire({ _select->getQuery(), _from.current() }); +} + +void TopBar::requestSearchDelayed() { + _searchTimer.callOnce(AutoSearchTimeout); +} + +rpl::producer TopBar::searchRequests() const { return _searchRequests.events(); } +rpl::producer TopBar::fromValue() const { + return _from.value(); +} + +PeerData *TopBar::from() const { + return _from.current(); +} + +void TopBar::setFrom(PeerData *peer) { + clearItems(); + + const auto guard = gsl::finally([&] { + _from = peer; + requestSearchDelayed(); + }); + if (!peer) { + return; + } + + _select->addItem( + peer->id.value, + tr::lng_dlg_search_from(tr::now, lt_user, peer->shortName()), + st::activeButtonBg, + PaintUserpicCallback(peer, false), + Ui::MultiSelect::AddItemWay::Default); +} + class BottomBar final : public Ui::RpWidget { public: using Index = int; - BottomBar(not_null parent); + BottomBar(not_null parent, bool fastShowChooseFrom); void setTotal(int total); [[nodiscard]] rpl::producer showItemRequests() const; [[nodiscard]] rpl::producer<> showCalendarRequests() const; + [[nodiscard]] rpl::producer<> showBoxFromRequests() const; + + void buttonFromToggleOn(rpl::producer &&visible); + void buttonCalendarToggleOn(rpl::producer &&visible); private: void updateText(int current); @@ -106,22 +183,27 @@ private: base::unique_qptr _next; base::unique_qptr _jumpToDate; + base::unique_qptr _chooseFromUser; base::unique_qptr _counter; int _total = -1; rpl::variable _current = 0; }; -BottomBar::BottomBar(not_null parent) +BottomBar::BottomBar(not_null parent, bool fastShowChooseFrom) : Ui::RpWidget(parent) // Icons are swaped. , _previous(base::make_unique_q(this, st::calendarNext)) , _next(base::make_unique_q(this, st::calendarPrevious)) , _jumpToDate(base::make_unique_q(this, st::dialogCalendar)) +, _chooseFromUser( + base::make_unique_q(this, st::dialogSearchFrom)) , _counter(base::make_unique_q( this, st::defaultSettingsRightLabel)) { + _chooseFromUser->setVisible(fastShowChooseFrom); + parent->geometryValue( ) | rpl::start_with_next([=](const QRect &r) { const auto height = st::historyComposeButton.height; @@ -129,8 +211,11 @@ BottomBar::BottomBar(not_null parent) moveToLeft(0, r.height() - height); }, lifetime()); + auto mapSize = rpl::map([=] { return size(); }); rpl::merge( - _counter->sizeValue() | rpl::map([=] { return size(); }), + _jumpToDate->shownValue() | mapSize, + _chooseFromUser->shownValue() | mapSize, + _counter->sizeValue() | mapSize, sizeValue() ) | rpl::start_with_next([=](const QSize &s) { _previous->moveToRight(0, (s.height() - _previous->height()) / 2); @@ -138,13 +223,18 @@ BottomBar::BottomBar(not_null parent) _previous->width(), (s.height() - _next->height()) / 2); - const auto left = st::topBarActionSkip; - _jumpToDate->moveToLeft( - left, - (s.height() - _jumpToDate->height()) / 2); - _counter->moveToLeft( - _jumpToDate->x() + _jumpToDate->width(), - (s.height() - _counter->height()) / 2); + auto left = st::topBarActionSkip; + const auto list = std::vector>{ + _jumpToDate.get(), + _chooseFromUser.get(), + _counter.get() }; + for (const auto &w : list) { + if (w->isHidden()) { + continue; + } + w->moveToLeft(left, (s.height() - w->height()) / 2); + left += w->width(); + } }, lifetime()); paintRequest( @@ -208,6 +298,26 @@ rpl::producer<> BottomBar::showCalendarRequests() const { return _jumpToDate->clicks() | rpl::to_empty; } +rpl::producer<> BottomBar::showBoxFromRequests() const { + return _chooseFromUser->clicks() | rpl::to_empty; +} + +void BottomBar::buttonFromToggleOn(rpl::producer &&visible) { + std::move( + visible + ) | rpl::start_with_next([=](bool value) { + _chooseFromUser->setVisible(value); + }, _chooseFromUser->lifetime()); +} + +void BottomBar::buttonCalendarToggleOn(rpl::producer &&visible) { + std::move( + visible + ) | rpl::start_with_next([=](bool value) { + _jumpToDate->setVisible(value); + }, _jumpToDate->lifetime()); +} + } // namespace class ComposeSearch::Inner final { @@ -247,17 +357,17 @@ ComposeSearch::Inner::Inner( : _window(window) , _history(history) , _topBar(base::make_unique_q(parent)) -, _bottomBar(base::make_unique_q(parent)) +, _bottomBar(base::make_unique_q(parent, HasChooseFrom(history))) , _apiSearch(&window->session(), history) { showAnimated(); _topBar->searchRequests( - ) | rpl::start_with_next([=](const QString &query) { - if (query.isEmpty()) { + ) | rpl::start_with_next([=](const SearchRequest &search) { + if (search.query.isEmpty() && !search.from) { return; } _apiFound = {}; - _apiSearch.searchMessages(query, nullptr); + _apiSearch.searchMessages(search.query, search.from); }, _topBar->lifetime()); _apiSearch.messagesFounds( @@ -303,6 +413,30 @@ ComposeSearch::Inner::Inner( ) | rpl::start_with_next([=] { _window->showCalendar({ _history }, QDate()); }, _bottomBar->lifetime()); + + _bottomBar->showBoxFromRequests( + ) | rpl::start_with_next([=] { + const auto peer = _history->peer; + auto box = Dialogs::SearchFromBox( + peer, + crl::guard(_bottomBar.get(), [=](not_null from) { + Window::Show(_window).hideLayer(); + _topBar->setFrom(from); + }), + crl::guard(_bottomBar.get(), [=] { /*_filter->setFocus();*/ })); + + Window::Show(_window).showBox(std::move(box)); + }, _bottomBar->lifetime()); + + _bottomBar->buttonCalendarToggleOn(_topBar->fromValue( + ) | rpl::map([=](PeerData *from) { + return !from; + })); + + _bottomBar->buttonFromToggleOn(_topBar->fromValue( + ) | rpl::map([=](PeerData *from) { + return HasChooseFrom(_history) && !from; + })); } void ComposeSearch::Inner::showAnimated() {