mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-13 04:37:11 +02:00
Support tags in ComposeSearch.
This commit is contained in:
parent
323500f6dd
commit
39b80c98c7
12 changed files with 220 additions and 51 deletions
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "apiwrap.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_message_reaction_id.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "history/history.h"
|
||||
|
@ -43,6 +44,23 @@ constexpr auto kSearchPerPage = 50;
|
|||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] QString RequestToToken(
|
||||
const MessagesSearch::Request &request) {
|
||||
auto result = request.query;
|
||||
if (request.from) {
|
||||
result += '\n' + QString::number(request.from->id.value);
|
||||
}
|
||||
for (const auto &tag : request.tags) {
|
||||
result += '\n';
|
||||
if (const auto customId = tag.custom()) {
|
||||
result += u"custom"_q + QString::number(customId);
|
||||
} else {
|
||||
result += u"emoji"_q + tag.emoji();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MessagesSearch::MessagesSearch(not_null<History*> history)
|
||||
|
@ -54,9 +72,8 @@ MessagesSearch::~MessagesSearch() {
|
|||
base::take(_searchInHistoryRequest));
|
||||
}
|
||||
|
||||
void MessagesSearch::searchMessages(const QString &query, PeerData *from) {
|
||||
_query = query;
|
||||
_from = from;
|
||||
void MessagesSearch::searchMessages(Request request) {
|
||||
_request = std::move(request);
|
||||
_offsetId = {};
|
||||
searchRequest();
|
||||
}
|
||||
|
@ -69,8 +86,7 @@ void MessagesSearch::searchMore() {
|
|||
}
|
||||
|
||||
void MessagesSearch::searchRequest() {
|
||||
const auto nextToken = _query
|
||||
+ QString::number(_from ? _from->id.value : 0);
|
||||
const auto nextToken = RequestToToken(_request);
|
||||
if (!_offsetId) {
|
||||
const auto it = _cacheOfStartByToken.find(nextToken);
|
||||
if (it != end(_cacheOfStartByToken)) {
|
||||
|
@ -80,18 +96,21 @@ void MessagesSearch::searchRequest() {
|
|||
}
|
||||
}
|
||||
auto callback = [=](Fn<void()> finish) {
|
||||
const auto flags = _from
|
||||
? MTP_flags(MTPmessages_Search::Flag::f_from_id)
|
||||
: MTP_flags(0);
|
||||
using Flag = MTPmessages_Search::Flag;
|
||||
const auto from = _request.from;
|
||||
const auto fromPeer = _history->peer->isUser() ? nullptr : from;
|
||||
const auto savedPeer = _history->peer->isSelf() ? from : nullptr;
|
||||
_requestId = _history->session().api().request(MTPmessages_Search(
|
||||
flags,
|
||||
MTP_flags((fromPeer ? Flag::f_from_id : Flag())
|
||||
| (savedPeer ? Flag::f_saved_peer_id : Flag())
|
||||
| (_request.tags.empty() ? Flag() : Flag::f_saved_reaction)),
|
||||
_history->peer->input,
|
||||
MTP_string(_query),
|
||||
(_from
|
||||
? _from->input
|
||||
: MTP_inputPeerEmpty()),
|
||||
MTPInputPeer(), // saved_peer_id
|
||||
MTPVector<MTPReaction>(), // saved_reaction
|
||||
MTP_string(_request.query),
|
||||
(fromPeer ? fromPeer->input : MTP_inputPeerEmpty()),
|
||||
(savedPeer ? savedPeer->input : MTP_inputPeerEmpty()),
|
||||
MTP_vector_from_range(_request.tags | ranges::views::transform(
|
||||
Data::ReactionToMTP
|
||||
)),
|
||||
MTPint(), // top_msg_id
|
||||
MTP_inputMessagesFilterEmpty(),
|
||||
MTP_int(0), // min_date
|
||||
|
|
|
@ -7,10 +7,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/qt/qt_compare.h"
|
||||
#include "data/data_message_reaction_id.h"
|
||||
|
||||
class HistoryItem;
|
||||
class History;
|
||||
class PeerData;
|
||||
|
||||
namespace Data {
|
||||
struct ReactionId;
|
||||
} // namespace Data
|
||||
|
||||
namespace Api {
|
||||
|
||||
struct FoundMessages {
|
||||
|
@ -21,10 +28,23 @@ struct FoundMessages {
|
|||
|
||||
class MessagesSearch final {
|
||||
public:
|
||||
struct Request {
|
||||
QString query;
|
||||
PeerData *from = nullptr;
|
||||
std::vector<Data::ReactionId> tags;
|
||||
|
||||
friend inline bool operator==(
|
||||
const Request &,
|
||||
const Request &) = default;
|
||||
friend inline auto operator<=>(
|
||||
const Request &,
|
||||
const Request &) = default;
|
||||
};
|
||||
|
||||
explicit MessagesSearch(not_null<History*> history);
|
||||
~MessagesSearch();
|
||||
|
||||
void searchMessages(const QString &query, PeerData *from);
|
||||
void searchMessages(Request request);
|
||||
void searchMore();
|
||||
|
||||
[[nodiscard]] rpl::producer<FoundMessages> messagesFounds() const;
|
||||
|
@ -41,8 +61,7 @@ private:
|
|||
|
||||
base::flat_map<QString, TLMessages> _cacheOfStartByToken;
|
||||
|
||||
QString _query;
|
||||
PeerData *_from = nullptr;
|
||||
Request _request;
|
||||
MsgId _offsetId;
|
||||
|
||||
int _searchInHistoryRequest = 0; // Not real mtpRequestId.
|
||||
|
|
|
@ -11,12 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Api {
|
||||
|
||||
bool MessagesSearchMerged::RequestCompare::operator()(
|
||||
const Request &a,
|
||||
const Request &b) const {
|
||||
return (a.query < b.query) && (a.from < b.from);
|
||||
}
|
||||
|
||||
MessagesSearchMerged::MessagesSearchMerged(not_null<History*> history)
|
||||
: _apiSearch(history) {
|
||||
if (const auto migrated = history->migrateFrom()) {
|
||||
|
@ -88,9 +82,9 @@ void MessagesSearchMerged::clear() {
|
|||
void MessagesSearchMerged::search(const Request &search) {
|
||||
if (_migratedSearch) {
|
||||
_waitingForTotal = true;
|
||||
_migratedSearch->searchMessages(search.query, search.from);
|
||||
_migratedSearch->searchMessages(search);
|
||||
}
|
||||
_apiSearch.searchMessages(search.query, search.from);
|
||||
_apiSearch.searchMessages(search);
|
||||
}
|
||||
|
||||
void MessagesSearchMerged::searchMore() {
|
||||
|
|
|
@ -12,19 +12,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
class History;
|
||||
class PeerData;
|
||||
|
||||
namespace Data {
|
||||
struct ReactionId;
|
||||
} // namespace Data
|
||||
|
||||
namespace Api {
|
||||
|
||||
// Search in both of history and migrated history, if it exists.
|
||||
class MessagesSearchMerged final {
|
||||
public:
|
||||
struct Request {
|
||||
QString query;
|
||||
PeerData *from = nullptr;
|
||||
};
|
||||
struct RequestCompare {
|
||||
bool operator()(const Request &a, const Request &b) const;
|
||||
};
|
||||
using CachedRequests = std::set<Request, RequestCompare>;
|
||||
using Request = MessagesSearch::Request;
|
||||
using CachedRequests = base::flat_set<Request>;
|
||||
|
||||
MessagesSearchMerged(not_null<History*> history);
|
||||
|
||||
|
|
|
@ -221,7 +221,7 @@ void DeleteMessagesBox::prepare() {
|
|||
? QString()
|
||||
: QString(" (%1)").arg(total));
|
||||
});
|
||||
search->searchMessages(QString(), _moderateFrom);
|
||||
search->searchMessages({ .from = _moderateFrom });
|
||||
}
|
||||
} else {
|
||||
details.text = (_ids.size() == 1)
|
||||
|
|
|
@ -31,6 +31,15 @@ ReactionId SearchTagFromQuery(const QString &query) {
|
|||
return {};
|
||||
}
|
||||
|
||||
std::vector<ReactionId> SearchTagsFromQuery(
|
||||
const QString &query) {
|
||||
auto result = std::vector<ReactionId>();
|
||||
if (const auto tag = SearchTagFromQuery(query)) {
|
||||
result.push_back(tag);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString ReactionEntityData(const ReactionId &id) {
|
||||
if (id.empty()) {
|
||||
return {};
|
||||
|
|
|
@ -47,6 +47,8 @@ struct MessageReaction {
|
|||
|
||||
[[nodiscard]] QString SearchTagToQuery(const ReactionId &tagId);
|
||||
[[nodiscard]] ReactionId SearchTagFromQuery(const QString &query);
|
||||
[[nodiscard]] std::vector<ReactionId> SearchTagsFromQuery(
|
||||
const QString &query);
|
||||
|
||||
[[nodiscard]] QString ReactionEntityData(const ReactionId &id);
|
||||
|
||||
|
|
|
@ -1928,11 +1928,10 @@ void Widget::searchMessages(QString query, Key inChat) {
|
|||
controller()->closeFolder();
|
||||
}
|
||||
|
||||
auto tags = std::vector<Data::ReactionId>();
|
||||
if (const auto tagId = Data::SearchTagFromQuery(query)) {
|
||||
auto tags = Data::SearchTagsFromQuery(query);
|
||||
if (!tags.empty()) {
|
||||
inChat = session().data().history(session().user());
|
||||
query = QString();
|
||||
tags.push_back(tagId);
|
||||
}
|
||||
const auto inChatChanged = [&] {
|
||||
const auto inPeer = inChat.peer();
|
||||
|
|
|
@ -4818,10 +4818,12 @@ void HistoryWidget::searchInChatEmbedded(std::optional<QString> query) {
|
|||
|
||||
updateControlsGeometry();
|
||||
};
|
||||
const auto from = (PeerData*)nullptr;
|
||||
_composeSearch = std::make_unique<HistoryView::ComposeSearch>(
|
||||
this,
|
||||
controller(),
|
||||
_history,
|
||||
from,
|
||||
query.value_or(QString()));
|
||||
|
||||
update();
|
||||
|
|
|
@ -9,12 +9,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "api/api_messages_search_merged.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/data_saved_messages.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "dialogs/dialogs_search_from_controllers.h" // SearchFromBox
|
||||
#include "dialogs/dialogs_search_tags.h"
|
||||
#include "dialogs/ui/dialogs_layout.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/effects/show_animation.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
|
@ -255,7 +262,12 @@ List CreateList(
|
|||
|
||||
class TopBar final : public Ui::RpWidget {
|
||||
public:
|
||||
TopBar(not_null<Ui::RpWidget*> parent, const QString &query);
|
||||
TopBar(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<History*> history,
|
||||
PeerData *from,
|
||||
const QString &query);
|
||||
|
||||
void setInnerFocus();
|
||||
void setQuery(const QString &query);
|
||||
|
@ -275,11 +287,17 @@ protected:
|
|||
|
||||
private:
|
||||
void clearItems();
|
||||
void setupTags(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<History*> history,
|
||||
PeerData *from);
|
||||
void requestSearch(bool cache = true);
|
||||
void requestSearchDelayed();
|
||||
|
||||
base::unique_qptr<Ui::IconButton> _cancel;
|
||||
std::vector<Data::ReactionId> _searchTagsSelected;
|
||||
base::unique_qptr<Ui::MultiSelect> _select;
|
||||
std::unique_ptr<Dialogs::SearchTags> _searchTags;
|
||||
|
||||
rpl::variable<PeerData*> _from = nullptr;
|
||||
|
||||
|
@ -293,29 +311,39 @@ private:
|
|||
rpl::event_stream<not_null<QKeyEvent*>> _keyEvents;
|
||||
};
|
||||
|
||||
TopBar::TopBar(not_null<Ui::RpWidget*> parent, const QString &query)
|
||||
TopBar::TopBar(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<History*> history,
|
||||
PeerData *from,
|
||||
const QString &query)
|
||||
: Ui::RpWidget(parent)
|
||||
, _cancel(base::make_unique_q<Ui::IconButton>(this, st::historyTopBarBack))
|
||||
, _searchTagsSelected(Data::SearchTagsFromQuery(query))
|
||||
, _select(base::make_unique_q<Ui::MultiSelect>(
|
||||
this,
|
||||
st::searchInChatMultiSelect,
|
||||
tr::lng_dlg_filter(),
|
||||
query))
|
||||
_searchTagsSelected.empty() ? query : QString()))
|
||||
, _searchTimer([=] { requestSearch(); }) {
|
||||
setupTags(window, history, from);
|
||||
|
||||
parent->geometryValue(
|
||||
) | rpl::start_with_next([=](const QRect &r) {
|
||||
rpl::combine(
|
||||
parent->geometryValue(),
|
||||
_searchTags ? _searchTags->heightValue() : rpl::single(0)
|
||||
) | rpl::start_with_next([=](const QRect &r, int tagsHeight) {
|
||||
moveToLeft(0, 0);
|
||||
resize(r.width(), st::topBarHeight);
|
||||
resize(r.width(), st::topBarHeight + tagsHeight);
|
||||
}, lifetime());
|
||||
|
||||
sizeValue(
|
||||
) | rpl::start_with_next([=](const QSize &s) {
|
||||
_cancel->moveToLeft(0, (s.height() - _cancel->height()) / 2);
|
||||
const auto height = st::topBarHeight;
|
||||
_cancel->moveToLeft(0, (height - _cancel->height()) / 2);
|
||||
|
||||
const auto selectLeft = _cancel->x() + _cancel->width();
|
||||
_select->resizeToWidth(s.width() - selectLeft);
|
||||
_select->moveToLeft(selectLeft, (s.height() - _select->height()) / 2);
|
||||
_select->moveToLeft(selectLeft, (height - _select->height()) / 2);
|
||||
|
||||
}, lifetime());
|
||||
|
||||
|
@ -337,6 +365,10 @@ TopBar::TopBar(not_null<Ui::RpWidget*> parent, const QString &query)
|
|||
_select->setCancelledCallback([=] {
|
||||
_cancelRequests.fire({});
|
||||
});
|
||||
|
||||
if (from) {
|
||||
setFrom(from);
|
||||
}
|
||||
}
|
||||
|
||||
void TopBar::keyPressEvent(QKeyEvent *e) {
|
||||
|
@ -372,8 +404,94 @@ void TopBar::clearItems() {
|
|||
});
|
||||
}
|
||||
|
||||
void TopBar::setupTags(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<History*> history,
|
||||
PeerData *from) {
|
||||
if (!_searchTagsSelected.empty()) {
|
||||
history = history->owner().history(history->session().user());
|
||||
} else if (!history->peer->isSelf()) {
|
||||
_searchTags = nullptr;
|
||||
return;
|
||||
}
|
||||
const auto reactions = &history->owner().reactions();
|
||||
const auto sublist = from
|
||||
? history->owner().savedMessages().sublist(from).get()
|
||||
: nullptr;
|
||||
_searchTags = std::make_unique<Dialogs::SearchTags>(
|
||||
&history->owner(),
|
||||
reactions->myTagsValue(sublist),
|
||||
_searchTagsSelected);
|
||||
|
||||
_searchTags->selectedValue(
|
||||
) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) {
|
||||
_searchTagsSelected = std::move(list);
|
||||
requestSearch(false);
|
||||
}, _searchTags->lifetime());
|
||||
|
||||
const auto parent = Ui::CreateChild<Ui::RpWidget>(this);
|
||||
const auto padding = st::searchInChatTagsPadding;
|
||||
const auto position = QPoint(padding.left(), padding.top());
|
||||
|
||||
_searchTags->repaintRequests() | rpl::start_with_next([=] {
|
||||
parent->update();
|
||||
}, _searchTags->lifetime());
|
||||
|
||||
widthValue() | rpl::start_with_next([=](int width) {
|
||||
width -= padding.left() + padding.right();
|
||||
_searchTags->resizeToWidth(width);
|
||||
}, _searchTags->lifetime());
|
||||
|
||||
rpl::combine(
|
||||
widthValue(),
|
||||
_searchTags->heightValue()
|
||||
) | rpl::start_with_next([=](int width, int height) {
|
||||
height += padding.top() + padding.bottom();
|
||||
parent->setGeometry(0, st::topBarHeight, width, height);
|
||||
}, _searchTags->lifetime());
|
||||
|
||||
parent->paintRequest() | rpl::start_with_next([=](const QRect &r) {
|
||||
auto p = Painter(parent);
|
||||
p.fillRect(r, st::dialogsBg);
|
||||
_searchTags->paint(p, position, crl::now(), false);
|
||||
}, parent->lifetime());
|
||||
|
||||
parent->setMouseTracking(true);
|
||||
parent->events() | rpl::start_with_next([=](not_null<QEvent*> e) {
|
||||
if (e->type() == QEvent::MouseMove) {
|
||||
const auto mouse = static_cast<QMouseEvent*>(e.get());
|
||||
const auto point = mouse->pos() - position;
|
||||
const auto handler = _searchTags->lookupHandler(point);
|
||||
ClickHandler::setActive(handler);
|
||||
parent->setCursor(handler
|
||||
? style::cur_pointer
|
||||
: style::cur_default);
|
||||
} else if (e->type() == QEvent::MouseButtonPress) {
|
||||
const auto mouse = static_cast<QMouseEvent*>(e.get());
|
||||
if (mouse->button() == Qt::LeftButton) {
|
||||
ClickHandler::pressed();
|
||||
}
|
||||
} else if (e->type() == QEvent::MouseButtonRelease) {
|
||||
const auto mouse = static_cast<QMouseEvent*>(e.get());
|
||||
if (mouse->button() == Qt::LeftButton) {
|
||||
const auto handler = ClickHandler::unpressed();
|
||||
ActivateClickHandler(parent, handler, ClickContext{
|
||||
.button = mouse->button(),
|
||||
.other = QVariant::fromValue(ClickHandlerContext{
|
||||
.sessionWindow = window,
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
}, parent->lifetime());
|
||||
}
|
||||
|
||||
void TopBar::requestSearch(bool cache) {
|
||||
const auto search = SearchRequest{ _select->getQuery(), _from.current() };
|
||||
const auto search = SearchRequest{
|
||||
_select->getQuery(),
|
||||
_from.current(),
|
||||
_searchTagsSelected
|
||||
};
|
||||
if (cache) {
|
||||
_typedRequests.insert(search);
|
||||
}
|
||||
|
@ -382,7 +500,11 @@ void TopBar::requestSearch(bool cache) {
|
|||
|
||||
void TopBar::requestSearchDelayed() {
|
||||
// Check cached queries.
|
||||
const auto search = SearchRequest{ _select->getQuery(), _from.current() };
|
||||
const auto search = SearchRequest{
|
||||
_select->getQuery(),
|
||||
_from.current(),
|
||||
_searchTagsSelected
|
||||
};
|
||||
if (_typedRequests.contains(search)) {
|
||||
requestSearch(false);
|
||||
return;
|
||||
|
@ -655,6 +777,7 @@ public:
|
|||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<History*> history,
|
||||
PeerData *from,
|
||||
const QString &query);
|
||||
~Inner();
|
||||
|
||||
|
@ -693,10 +816,11 @@ ComposeSearch::Inner::Inner(
|
|||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<History*> history,
|
||||
PeerData *from,
|
||||
const QString &query)
|
||||
: _window(window)
|
||||
, _history(history)
|
||||
, _topBar(base::make_unique_q<TopBar>(parent, query))
|
||||
, _topBar(base::make_unique_q<TopBar>(parent, window, history, from, query))
|
||||
, _bottomBar(base::make_unique_q<BottomBar>(parent, HasChooseFrom(history)))
|
||||
, _list(CreateList(parent, history))
|
||||
, _apiSearch(history) {
|
||||
|
@ -720,7 +844,7 @@ ComposeSearch::Inner::Inner(
|
|||
|
||||
_topBar->searchRequests(
|
||||
) | rpl::start_with_next([=](const SearchRequest &search) {
|
||||
if (search.query.isEmpty() && !search.from) {
|
||||
if (search.query.isEmpty() && !search.from && search.tags.empty()) {
|
||||
return;
|
||||
}
|
||||
_apiSearch.clear();
|
||||
|
@ -893,8 +1017,9 @@ ComposeSearch::ComposeSearch(
|
|||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<History*> history,
|
||||
PeerData *from,
|
||||
const QString &query)
|
||||
: _inner(std::make_unique<Inner>(parent, window, history, query)) {
|
||||
: _inner(std::make_unique<Inner>(parent, window, history, from, query)) {
|
||||
}
|
||||
|
||||
ComposeSearch::~ComposeSearch() {
|
||||
|
|
|
@ -25,6 +25,7 @@ public:
|
|||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<History*> history,
|
||||
PeerData *from = nullptr,
|
||||
const QString &query = QString());
|
||||
~ComposeSearch();
|
||||
|
||||
|
|
|
@ -912,6 +912,7 @@ searchInChatPeerListItem: PeerListItem(defaultPeerListItem) {
|
|||
searchInChatPeerList: PeerList(defaultPeerList) {
|
||||
item: searchInChatPeerListItem;
|
||||
}
|
||||
searchInChatTagsPadding: margins(6px, 0px, 6px, 0px);
|
||||
|
||||
msgServiceGiftBoxSize: size(236px, 231px); // Plus msgServiceGiftBoxTopSkip.
|
||||
msgServiceGiftBoxRadius: 20px;
|
||||
|
|
Loading…
Add table
Reference in a new issue