Added ability to search messages from specific peer in dialogs.

This commit is contained in:
23rd 2022-03-21 17:35:31 +03:00 committed by John Preston
parent 89ab23e70f
commit a1d21cf452
2 changed files with 160 additions and 21 deletions

View File

@ -187,6 +187,11 @@ dialogCalendar: IconButton(dialogsMenuToggle) {
rippleAreaPosition: point(3px, 3px); rippleAreaPosition: point(3px, 3px);
rippleAreaSize: 34px; 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; dialogsChatTypeSkip: 20px;
dialogsChatIcon: icon {{ "dialogs/dialogs_chat", dialogsChatIconFg, point(1px, 4px) }}; dialogsChatIcon: icon {{ "dialogs/dialogs_chat", dialogsChatIconFg, point(1px, 4px) }};

View File

@ -8,7 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/controls/history_view_compose_search.h" #include "history/view/controls/history_view_compose_search.h"
#include "api/api_messages_search.h" #include "api/api_messages_search.h"
#include "boxes/peer_list_box.h" // PaintUserpicCallback
#include "data/data_session.h" #include "data/data_session.h"
#include "dialogs/dialogs_search_from_controllers.h" // SearchFromBox
#include "history/history.h" #include "history/history.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
@ -25,19 +27,42 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace HistoryView { namespace HistoryView {
namespace { namespace {
[[nodiscard]] inline bool HasChooseFrom(not_null<History*> 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 { class TopBar final : public Ui::RpWidget {
public: public:
TopBar(not_null<Ui::RpWidget*> parent); TopBar(not_null<Ui::RpWidget*> parent);
[[nodiscard]] rpl::producer<QString> searchRequests() const; [[nodiscard]] PeerData *from() const;
[[nodiscard]] rpl::producer<SearchRequest> searchRequests() const;
[[nodiscard]] rpl::producer<PeerData*> fromValue() const;
void setFrom(PeerData *peer);
private: private:
void clearItems();
void requestSearch();
void requestSearchDelayed();
base::unique_qptr<Ui::IconButton> _cancel; base::unique_qptr<Ui::IconButton> _cancel;
base::unique_qptr<Ui::MultiSelect> _select; base::unique_qptr<Ui::MultiSelect> _select;
rpl::variable<PeerData*> _from = nullptr;;
base::Timer _searchTimer; base::Timer _searchTimer;
rpl::event_stream<QString> _searchRequests; rpl::event_stream<SearchRequest> _searchRequests;
}; };
TopBar::TopBar(not_null<Ui::RpWidget*> parent) TopBar::TopBar(not_null<Ui::RpWidget*> parent)
@ -47,7 +72,7 @@ TopBar::TopBar(not_null<Ui::RpWidget*> parent)
this, this,
st::searchInChatMultiSelect, st::searchInChatMultiSelect,
tr::lng_dlg_filter())) tr::lng_dlg_filter()))
, _searchTimer([=] { _searchRequests.fire(_select->getQuery()); }) { , _searchTimer([=] { requestSearch(); }) {
parent->geometryValue( parent->geometryValue(
) | rpl::start_with_next([=](const QRect &r) { ) | rpl::start_with_next([=](const QRect &r) {
@ -72,12 +97,12 @@ TopBar::TopBar(not_null<Ui::RpWidget*> parent)
p.fillRect(r, st::dialogsBg); p.fillRect(r, st::dialogsBg);
}, lifetime()); }, lifetime());
_select->setQueryChangedCallback([=](const QString &query) { _select->setQueryChangedCallback([=](const QString &) {
_searchTimer.callOnce(AutoSearchTimeout); requestSearchDelayed();
}); });
_select->setSubmittedCallback([=](Qt::KeyboardModifiers) { _select->setSubmittedCallback([=](Qt::KeyboardModifiers) {
_searchRequests.fire(_select->getQuery()); requestSearch();
}); });
_select->setCancelledCallback([=] { _select->setCancelledCallback([=] {
@ -85,19 +110,71 @@ TopBar::TopBar(not_null<Ui::RpWidget*> parent)
}); });
} }
rpl::producer<QString> 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<SearchRequest> TopBar::searchRequests() const {
return _searchRequests.events(); return _searchRequests.events();
} }
rpl::producer<PeerData*> 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 { class BottomBar final : public Ui::RpWidget {
public: public:
using Index = int; using Index = int;
BottomBar(not_null<Ui::RpWidget*> parent); BottomBar(not_null<Ui::RpWidget*> parent, bool fastShowChooseFrom);
void setTotal(int total); void setTotal(int total);
[[nodiscard]] rpl::producer<Index> showItemRequests() const; [[nodiscard]] rpl::producer<Index> showItemRequests() const;
[[nodiscard]] rpl::producer<> showCalendarRequests() const; [[nodiscard]] rpl::producer<> showCalendarRequests() const;
[[nodiscard]] rpl::producer<> showBoxFromRequests() const;
void buttonFromToggleOn(rpl::producer<bool> &&visible);
void buttonCalendarToggleOn(rpl::producer<bool> &&visible);
private: private:
void updateText(int current); void updateText(int current);
@ -106,22 +183,27 @@ private:
base::unique_qptr<Ui::IconButton> _next; base::unique_qptr<Ui::IconButton> _next;
base::unique_qptr<Ui::IconButton> _jumpToDate; base::unique_qptr<Ui::IconButton> _jumpToDate;
base::unique_qptr<Ui::IconButton> _chooseFromUser;
base::unique_qptr<Ui::FlatLabel> _counter; base::unique_qptr<Ui::FlatLabel> _counter;
int _total = -1; int _total = -1;
rpl::variable<int> _current = 0; rpl::variable<int> _current = 0;
}; };
BottomBar::BottomBar(not_null<Ui::RpWidget*> parent) BottomBar::BottomBar(not_null<Ui::RpWidget*> parent, bool fastShowChooseFrom)
: Ui::RpWidget(parent) : Ui::RpWidget(parent)
// Icons are swaped. // Icons are swaped.
, _previous(base::make_unique_q<Ui::IconButton>(this, st::calendarNext)) , _previous(base::make_unique_q<Ui::IconButton>(this, st::calendarNext))
, _next(base::make_unique_q<Ui::IconButton>(this, st::calendarPrevious)) , _next(base::make_unique_q<Ui::IconButton>(this, st::calendarPrevious))
, _jumpToDate(base::make_unique_q<Ui::IconButton>(this, st::dialogCalendar)) , _jumpToDate(base::make_unique_q<Ui::IconButton>(this, st::dialogCalendar))
, _chooseFromUser(
base::make_unique_q<Ui::IconButton>(this, st::dialogSearchFrom))
, _counter(base::make_unique_q<Ui::FlatLabel>( , _counter(base::make_unique_q<Ui::FlatLabel>(
this, this,
st::defaultSettingsRightLabel)) { st::defaultSettingsRightLabel)) {
_chooseFromUser->setVisible(fastShowChooseFrom);
parent->geometryValue( parent->geometryValue(
) | rpl::start_with_next([=](const QRect &r) { ) | rpl::start_with_next([=](const QRect &r) {
const auto height = st::historyComposeButton.height; const auto height = st::historyComposeButton.height;
@ -129,8 +211,11 @@ BottomBar::BottomBar(not_null<Ui::RpWidget*> parent)
moveToLeft(0, r.height() - height); moveToLeft(0, r.height() - height);
}, lifetime()); }, lifetime());
auto mapSize = rpl::map([=] { return size(); });
rpl::merge( rpl::merge(
_counter->sizeValue() | rpl::map([=] { return size(); }), _jumpToDate->shownValue() | mapSize,
_chooseFromUser->shownValue() | mapSize,
_counter->sizeValue() | mapSize,
sizeValue() sizeValue()
) | rpl::start_with_next([=](const QSize &s) { ) | rpl::start_with_next([=](const QSize &s) {
_previous->moveToRight(0, (s.height() - _previous->height()) / 2); _previous->moveToRight(0, (s.height() - _previous->height()) / 2);
@ -138,13 +223,18 @@ BottomBar::BottomBar(not_null<Ui::RpWidget*> parent)
_previous->width(), _previous->width(),
(s.height() - _next->height()) / 2); (s.height() - _next->height()) / 2);
const auto left = st::topBarActionSkip; auto left = st::topBarActionSkip;
_jumpToDate->moveToLeft( const auto list = std::vector<not_null<Ui::RpWidget*>>{
left, _jumpToDate.get(),
(s.height() - _jumpToDate->height()) / 2); _chooseFromUser.get(),
_counter->moveToLeft( _counter.get() };
_jumpToDate->x() + _jumpToDate->width(), for (const auto &w : list) {
(s.height() - _counter->height()) / 2); if (w->isHidden()) {
continue;
}
w->moveToLeft(left, (s.height() - w->height()) / 2);
left += w->width();
}
}, lifetime()); }, lifetime());
paintRequest( paintRequest(
@ -208,6 +298,26 @@ rpl::producer<> BottomBar::showCalendarRequests() const {
return _jumpToDate->clicks() | rpl::to_empty; return _jumpToDate->clicks() | rpl::to_empty;
} }
rpl::producer<> BottomBar::showBoxFromRequests() const {
return _chooseFromUser->clicks() | rpl::to_empty;
}
void BottomBar::buttonFromToggleOn(rpl::producer<bool> &&visible) {
std::move(
visible
) | rpl::start_with_next([=](bool value) {
_chooseFromUser->setVisible(value);
}, _chooseFromUser->lifetime());
}
void BottomBar::buttonCalendarToggleOn(rpl::producer<bool> &&visible) {
std::move(
visible
) | rpl::start_with_next([=](bool value) {
_jumpToDate->setVisible(value);
}, _jumpToDate->lifetime());
}
} // namespace } // namespace
class ComposeSearch::Inner final { class ComposeSearch::Inner final {
@ -247,17 +357,17 @@ ComposeSearch::Inner::Inner(
: _window(window) : _window(window)
, _history(history) , _history(history)
, _topBar(base::make_unique_q<TopBar>(parent)) , _topBar(base::make_unique_q<TopBar>(parent))
, _bottomBar(base::make_unique_q<BottomBar>(parent)) , _bottomBar(base::make_unique_q<BottomBar>(parent, HasChooseFrom(history)))
, _apiSearch(&window->session(), history) { , _apiSearch(&window->session(), history) {
showAnimated(); showAnimated();
_topBar->searchRequests( _topBar->searchRequests(
) | rpl::start_with_next([=](const QString &query) { ) | rpl::start_with_next([=](const SearchRequest &search) {
if (query.isEmpty()) { if (search.query.isEmpty() && !search.from) {
return; return;
} }
_apiFound = {}; _apiFound = {};
_apiSearch.searchMessages(query, nullptr); _apiSearch.searchMessages(search.query, search.from);
}, _topBar->lifetime()); }, _topBar->lifetime());
_apiSearch.messagesFounds( _apiSearch.messagesFounds(
@ -303,6 +413,30 @@ ComposeSearch::Inner::Inner(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
_window->showCalendar({ _history }, QDate()); _window->showCalendar({ _history }, QDate());
}, _bottomBar->lifetime()); }, _bottomBar->lifetime());
_bottomBar->showBoxFromRequests(
) | rpl::start_with_next([=] {
const auto peer = _history->peer;
auto box = Dialogs::SearchFromBox(
peer,
crl::guard(_bottomBar.get(), [=](not_null<PeerData*> 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() { void ComposeSearch::Inner::showAnimated() {