mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Search by tag on click in Saved Messages.
This commit is contained in:
parent
94a542a1d1
commit
d1a0dfbb97
10 changed files with 102 additions and 20 deletions
|
@ -11,6 +11,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
|
QString SearchTagToQuery(const ReactionId &tagId) {
|
||||||
|
if (const auto customId = tagId.custom()) {
|
||||||
|
return u"#tag-custom:%1"_q.arg(customId);
|
||||||
|
} else if (!tagId) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
return u"#tag-emoji:"_q + tagId.emoji();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactionId SearchTagFromQuery(const QString &query) {
|
||||||
|
const auto list = query.split(QChar(' '));
|
||||||
|
const auto tag = list.isEmpty() ? QString() : list[0];
|
||||||
|
if (tag.startsWith(u"#tag-custom:"_q)) {
|
||||||
|
return ReactionId{ DocumentId(tag.mid(12).toULongLong()) };
|
||||||
|
} else if (tag.startsWith(u"#tag-emoji:"_q)) {
|
||||||
|
return ReactionId{ tag.mid(11) };
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
QString ReactionEntityData(const ReactionId &id) {
|
QString ReactionEntityData(const ReactionId &id) {
|
||||||
if (id.empty()) {
|
if (id.empty()) {
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -27,6 +27,10 @@ struct ReactionId {
|
||||||
return custom ? *custom : DocumentId();
|
return custom ? *custom : DocumentId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return !empty();
|
||||||
|
}
|
||||||
|
|
||||||
friend inline auto operator<=>(
|
friend inline auto operator<=>(
|
||||||
const ReactionId &,
|
const ReactionId &,
|
||||||
const ReactionId &) = default;
|
const ReactionId &) = default;
|
||||||
|
@ -41,6 +45,9 @@ struct MessageReaction {
|
||||||
bool my = false;
|
bool my = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] QString SearchTagToQuery(const ReactionId &tagId);
|
||||||
|
[[nodiscard]] ReactionId SearchTagFromQuery(const QString &query);
|
||||||
|
|
||||||
[[nodiscard]] QString ReactionEntityData(const ReactionId &id);
|
[[nodiscard]] QString ReactionEntityData(const ReactionId &id);
|
||||||
|
|
||||||
[[nodiscard]] ReactionId ReactionFromMTP(const MTPReaction &reaction);
|
[[nodiscard]] ReactionId ReactionFromMTP(const MTPReaction &reaction);
|
||||||
|
|
|
@ -2968,13 +2968,17 @@ bool InnerWidget::hasFilteredResults() const {
|
||||||
return !_filterResults.empty() && _hashtagResults.empty();
|
return !_filterResults.empty() && _hashtagResults.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::searchInChat(Key key, PeerData *from) {
|
void InnerWidget::searchInChat(
|
||||||
|
Key key,
|
||||||
|
PeerData *from,
|
||||||
|
std::vector<Data::ReactionId> tags) {
|
||||||
_searchInMigrated = nullptr;
|
_searchInMigrated = nullptr;
|
||||||
const auto sublist = key.sublist();
|
const auto sublist = key.sublist();
|
||||||
const auto peer = sublist ? session().user().get() : key.peer();
|
const auto peer = sublist ? session().user().get() : key.peer();
|
||||||
if (peer) {
|
if (peer) {
|
||||||
if (const auto migrateTo = peer->migrateTo()) {
|
if (const auto migrateTo = peer->migrateTo()) {
|
||||||
return searchInChat(peer->owner().history(migrateTo), from);
|
const auto to = peer->owner().history(migrateTo);
|
||||||
|
return searchInChat(to, from, tags);
|
||||||
} else if (const auto migrateFrom = peer->migrateFrom()) {
|
} else if (const auto migrateFrom = peer->migrateFrom()) {
|
||||||
_searchInMigrated = peer->owner().history(migrateFrom);
|
_searchInMigrated = peer->owner().history(migrateFrom);
|
||||||
}
|
}
|
||||||
|
@ -2990,7 +2994,8 @@ void InnerWidget::searchInChat(Key key, PeerData *from) {
|
||||||
list()
|
list()
|
||||||
) | rpl::then(
|
) | rpl::then(
|
||||||
reactions->myTagsUpdates() | rpl::map(list)
|
reactions->myTagsUpdates() | rpl::map(list)
|
||||||
));
|
),
|
||||||
|
tags);
|
||||||
|
|
||||||
_searchTags->selectedValue(
|
_searchTags->selectedValue(
|
||||||
) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) {
|
) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) {
|
||||||
|
|
|
@ -139,7 +139,10 @@ public:
|
||||||
}
|
}
|
||||||
[[nodiscard]] bool hasFilteredResults() const;
|
[[nodiscard]] bool hasFilteredResults() const;
|
||||||
|
|
||||||
void searchInChat(Key key, PeerData *from);
|
void searchInChat(
|
||||||
|
Key key,
|
||||||
|
PeerData *from,
|
||||||
|
std::vector<Data::ReactionId> tags);
|
||||||
[[nodiscard]] auto searchTagsValue() const
|
[[nodiscard]] auto searchTagsValue() const
|
||||||
-> rpl::producer<std::vector<Data::ReactionId>>;
|
-> rpl::producer<std::vector<Data::ReactionId>>;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "dialogs/dialogs_search_tags.h"
|
#include "dialogs/dialogs_search_tags.h"
|
||||||
|
|
||||||
|
#include "base/qt/qt_key_modifiers.h"
|
||||||
#include "data/stickers/data_custom_emoji.h"
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_message_reactions.h"
|
#include "data/data_message_reactions.h"
|
||||||
|
@ -30,14 +31,24 @@ struct SearchTags::Tag {
|
||||||
|
|
||||||
SearchTags::SearchTags(
|
SearchTags::SearchTags(
|
||||||
not_null<Data::Session*> owner,
|
not_null<Data::Session*> owner,
|
||||||
rpl::producer<std::vector<Data::Reaction>> tags)
|
rpl::producer<std::vector<Data::Reaction>> tags,
|
||||||
: _owner(owner) {
|
std::vector<Data::ReactionId> selected)
|
||||||
|
: _owner(owner)
|
||||||
|
, _added(selected) {
|
||||||
std::move(
|
std::move(
|
||||||
tags
|
tags
|
||||||
) | rpl::start_with_next([=](const std::vector<Data::Reaction> &list) {
|
) | rpl::start_with_next([=](const std::vector<Data::Reaction> &list) {
|
||||||
fill(list);
|
fill(list);
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
|
||||||
|
// Mark the `selected` reactions as selected in `_tags`.
|
||||||
|
for (const auto &id : selected) {
|
||||||
|
const auto i = ranges::find(_tags, id, &Tag::id);
|
||||||
|
if (i != end(_tags)) {
|
||||||
|
i->selected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
style::PaletteChanged(
|
style::PaletteChanged(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
_normalBg = _selectedBg = QImage();
|
_normalBg = _selectedBg = QImage();
|
||||||
|
@ -54,13 +65,17 @@ void SearchTags::fill(const std::vector<Data::Reaction> &list) {
|
||||||
return std::make_shared<LambdaClickHandler>(crl::guard(this, [=] {
|
return std::make_shared<LambdaClickHandler>(crl::guard(this, [=] {
|
||||||
const auto i = ranges::find(_tags, id, &Tag::id);
|
const auto i = ranges::find(_tags, id, &Tag::id);
|
||||||
if (i != end(_tags)) {
|
if (i != end(_tags)) {
|
||||||
|
if (!i->selected && !base::IsShiftPressed()) {
|
||||||
|
for (auto &tag : _tags) {
|
||||||
|
tag.selected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
i->selected = !i->selected;
|
i->selected = !i->selected;
|
||||||
_selectedChanges.fire({});
|
_selectedChanges.fire({});
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
for (const auto &reaction : list) {
|
const auto push = [&](Data::ReactionId id) {
|
||||||
const auto id = reaction.id;
|
|
||||||
const auto customId = id.custom();
|
const auto customId = id.custom();
|
||||||
_tags.push_back({
|
_tags.push_back({
|
||||||
.id = id,
|
.id = id,
|
||||||
|
@ -75,6 +90,14 @@ void SearchTags::fill(const std::vector<Data::Reaction> &list) {
|
||||||
if (!customId) {
|
if (!customId) {
|
||||||
_owner->reactions().preloadImageFor(id);
|
_owner->reactions().preloadImageFor(id);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
for (const auto &reaction : list) {
|
||||||
|
push(reaction.id);
|
||||||
|
}
|
||||||
|
for (const auto &reaction : _added) {
|
||||||
|
if (!ranges::contains(_tags, reaction, &Tag::id)) {
|
||||||
|
push(reaction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (_width > 0) {
|
if (_width > 0) {
|
||||||
layout();
|
layout();
|
||||||
|
|
|
@ -25,7 +25,8 @@ class SearchTags final : public base::has_weak_ptr {
|
||||||
public:
|
public:
|
||||||
SearchTags(
|
SearchTags(
|
||||||
not_null<Data::Session*> owner,
|
not_null<Data::Session*> owner,
|
||||||
rpl::producer<std::vector<Data::Reaction>> tags);
|
rpl::producer<std::vector<Data::Reaction>> tags,
|
||||||
|
std::vector<Data::ReactionId> selected);
|
||||||
~SearchTags();
|
~SearchTags();
|
||||||
|
|
||||||
void resizeToWidth(int width);
|
void resizeToWidth(int width);
|
||||||
|
@ -61,6 +62,7 @@ private:
|
||||||
[[nodiscard]] const QImage &validateBg(bool selected) const;
|
[[nodiscard]] const QImage &validateBg(bool selected) const;
|
||||||
|
|
||||||
const not_null<Data::Session*> _owner;
|
const not_null<Data::Session*> _owner;
|
||||||
|
std::vector<Data::ReactionId> _added;
|
||||||
std::vector<Tag> _tags;
|
std::vector<Tag> _tags;
|
||||||
rpl::event_stream<> _selectedChanges;
|
rpl::event_stream<> _selectedChanges;
|
||||||
rpl::event_stream<> _repaintRequests;
|
rpl::event_stream<> _repaintRequests;
|
||||||
|
|
|
@ -1911,7 +1911,7 @@ void Widget::showMainMenu() {
|
||||||
controller()->widget()->showMainMenu();
|
controller()->widget()->showMainMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::searchMessages(const QString &query, Key inChat) {
|
void Widget::searchMessages(QString query, Key inChat) {
|
||||||
if (_childList) {
|
if (_childList) {
|
||||||
const auto forum = controller()->shownForum().current();
|
const auto forum = controller()->shownForum().current();
|
||||||
const auto topic = inChat.topic();
|
const auto topic = inChat.topic();
|
||||||
|
@ -1926,6 +1926,12 @@ void Widget::searchMessages(const QString &query, Key inChat) {
|
||||||
controller()->closeFolder();
|
controller()->closeFolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto tags = std::vector<Data::ReactionId>();
|
||||||
|
if (const auto tagId = Data::SearchTagFromQuery(query)) {
|
||||||
|
inChat = session().data().history(session().user());
|
||||||
|
query = QString();
|
||||||
|
tags.push_back(tagId);
|
||||||
|
}
|
||||||
const auto inChatChanged = [&] {
|
const auto inChatChanged = [&] {
|
||||||
const auto inPeer = inChat.peer();
|
const auto inPeer = inChat.peer();
|
||||||
const auto inTopic = inChat.topic();
|
const auto inTopic = inChat.topic();
|
||||||
|
@ -1948,10 +1954,12 @@ void Widget::searchMessages(const QString &query, Key inChat) {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}();
|
}();
|
||||||
if ((currentSearchQuery() != query) || inChatChanged) {
|
if ((currentSearchQuery() != query)
|
||||||
|
|| inChatChanged
|
||||||
|
|| _searchTags != tags) {
|
||||||
if (inChat) {
|
if (inChat) {
|
||||||
cancelSearch();
|
cancelSearch();
|
||||||
setSearchInChat(inChat);
|
setSearchInChat(inChat, nullptr, tags);
|
||||||
}
|
}
|
||||||
setSearchQuery(query);
|
setSearchQuery(query);
|
||||||
applyFilterUpdate(true);
|
applyFilterUpdate(true);
|
||||||
|
@ -2595,9 +2603,12 @@ void Widget::searchInChat(Key chat) {
|
||||||
searchMessages(QString(), chat);
|
searchMessages(QString(), chat);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Widget::setSearchInChat(Key chat, PeerData *from) {
|
bool Widget::setSearchInChat(
|
||||||
|
Key chat,
|
||||||
|
PeerData *from,
|
||||||
|
std::vector<Data::ReactionId> tags) {
|
||||||
if (_childList) {
|
if (_childList) {
|
||||||
if (_childList->setSearchInChat(chat, from)) {
|
if (_childList->setSearchInChat(chat, from, tags)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
hideChildList();
|
hideChildList();
|
||||||
|
@ -2634,7 +2645,8 @@ bool Widget::setSearchInChat(Key chat, PeerData *from) {
|
||||||
if (_layout != Layout::Main) {
|
if (_layout != Layout::Main) {
|
||||||
return false;
|
return false;
|
||||||
} else if (const auto migrateTo = peer->migrateTo()) {
|
} else if (const auto migrateTo = peer->migrateTo()) {
|
||||||
return setSearchInChat(peer->owner().history(migrateTo), from);
|
const auto to = peer->owner().history(migrateTo);
|
||||||
|
return setSearchInChat(to, from, tags);
|
||||||
} else if (const auto migrateFrom = peer->migrateFrom()) {
|
} else if (const auto migrateFrom = peer->migrateFrom()) {
|
||||||
_searchInMigrated = peer->owner().history(migrateFrom);
|
_searchInMigrated = peer->owner().history(migrateFrom);
|
||||||
}
|
}
|
||||||
|
@ -2653,7 +2665,8 @@ bool Widget::setSearchInChat(Key chat, PeerData *from) {
|
||||||
if (_searchInChat && _layout == Layout::Main) {
|
if (_searchInChat && _layout == Layout::Main) {
|
||||||
controller()->closeFolder();
|
controller()->closeFolder();
|
||||||
}
|
}
|
||||||
_inner->searchInChat(_searchInChat, _searchFromAuthor);
|
_searchTags = std::move(tags);
|
||||||
|
_inner->searchInChat(_searchInChat, _searchFromAuthor, _searchTags);
|
||||||
_searchTagsLifetime = _inner->searchTagsValue(
|
_searchTagsLifetime = _inner->searchTagsValue(
|
||||||
) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) {
|
) | rpl::start_with_next([=](std::vector<Data::ReactionId> &&list) {
|
||||||
if (_searchTags != list) {
|
if (_searchTags != list) {
|
||||||
|
|
|
@ -117,7 +117,7 @@ public:
|
||||||
|
|
||||||
void scrollToEntry(const RowDescriptor &entry);
|
void scrollToEntry(const RowDescriptor &entry);
|
||||||
|
|
||||||
void searchMessages(const QString &query, Key inChat = {});
|
void searchMessages(QString query, Key inChat = {});
|
||||||
void searchTopics();
|
void searchTopics();
|
||||||
void searchMore();
|
void searchMore();
|
||||||
|
|
||||||
|
@ -180,7 +180,10 @@ private:
|
||||||
void trackScroll(not_null<Ui::RpWidget*> widget);
|
void trackScroll(not_null<Ui::RpWidget*> widget);
|
||||||
[[nodiscard]] bool searchForPeersRequired(const QString &query) const;
|
[[nodiscard]] bool searchForPeersRequired(const QString &query) const;
|
||||||
[[nodiscard]] bool searchForTopicsRequired(const QString &query) const;
|
[[nodiscard]] bool searchForTopicsRequired(const QString &query) const;
|
||||||
bool setSearchInChat(Key chat, PeerData *from = nullptr);
|
bool setSearchInChat(
|
||||||
|
Key chat,
|
||||||
|
PeerData *from = nullptr,
|
||||||
|
std::vector<Data::ReactionId> tags = {});
|
||||||
void showCalendar();
|
void showCalendar();
|
||||||
void showSearchFrom();
|
void showSearchFrom();
|
||||||
void showMainMenu();
|
void showMainMenu();
|
||||||
|
|
|
@ -2965,8 +2965,14 @@ void Message::refreshReactions() {
|
||||||
if (!_reactions) {
|
if (!_reactions) {
|
||||||
const auto handlerFactory = [=](ReactionId id) {
|
const auto handlerFactory = [=](ReactionId id) {
|
||||||
const auto weak = base::make_weak(this);
|
const auto weak = base::make_weak(this);
|
||||||
return std::make_shared<LambdaClickHandler>([=] {
|
return std::make_shared<LambdaClickHandler>([=](
|
||||||
|
ClickContext context) {
|
||||||
if (const auto strong = weak.get()) {
|
if (const auto strong = weak.get()) {
|
||||||
|
if (strong->data()->reactionsAreTags()) {
|
||||||
|
const auto tag = Data::SearchTagToQuery(id);
|
||||||
|
HashtagClickHandler(tag).onClick(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
strong->data()->toggleReaction(
|
strong->data()->toggleReaction(
|
||||||
id,
|
id,
|
||||||
HistoryItem::ReactionSource::Existing);
|
HistoryItem::ReactionSource::Existing);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0d111bd4633324533195aa0a840730b4bf6ba75b
|
Subproject commit bc78a03b12b40ee6264ad2235465197b89588288
|
Loading…
Add table
Reference in a new issue