mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-06 15:13:57 +02:00
Track message reactions.
This commit is contained in:
parent
a1439163ce
commit
f5c7b206bb
8 changed files with 222 additions and 0 deletions
|
@ -445,6 +445,8 @@ PRIVATE
|
||||||
data/data_media_types.h
|
data/data_media_types.h
|
||||||
data/data_messages.cpp
|
data/data_messages.cpp
|
||||||
data/data_messages.h
|
data/data_messages.h
|
||||||
|
data/data_message_reactions.cpp
|
||||||
|
data/data_message_reactions.h
|
||||||
data/data_msg_id.h
|
data/data_msg_id.h
|
||||||
data/data_notify_settings.cpp
|
data/data_notify_settings.cpp
|
||||||
data/data_notify_settings.h
|
data/data_notify_settings.h
|
||||||
|
|
|
@ -1617,6 +1617,19 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case mtpc_updateMessageReactions: {
|
||||||
|
const auto &d = update.c_updateMessageReactions();
|
||||||
|
const auto peer = peerFromMTP(d.vpeer());
|
||||||
|
if (const auto history = session().data().historyLoaded(peer)) {
|
||||||
|
const auto item = session().data().message(
|
||||||
|
peer,
|
||||||
|
d.vmsg_id().v);
|
||||||
|
if (item) {
|
||||||
|
item->updateReactions(d.vreactions());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
// Messages being read.
|
// Messages being read.
|
||||||
case mtpc_updateReadHistoryInbox: {
|
case mtpc_updateReadHistoryInbox: {
|
||||||
auto &d = update.c_updateReadHistoryInbox();
|
auto &d = update.c_updateReadHistoryInbox();
|
||||||
|
|
114
Telegram/SourceFiles/data/data_message_reactions.cpp
Normal file
114
Telegram/SourceFiles/data/data_message_reactions.cpp
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "data/data_message_reactions.h"
|
||||||
|
|
||||||
|
#include "history/history.h"
|
||||||
|
#include "history/history_item.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "apiwrap.h"
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
|
||||||
|
std::vector<QString> MessageReactions::SuggestList() {
|
||||||
|
constexpr auto utf = [](const char *utf) {
|
||||||
|
return QString::fromUtf8(utf);
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
utf("\xE2\x9D\xA4\xEF\xB8\x8F"), // :heart:
|
||||||
|
utf("\xF0\x9F\x91\x8D"), // :like:
|
||||||
|
utf("\xF0\x9F\x98\x82"), // :joy:
|
||||||
|
utf("\xF0\x9F\x98\xB3"), // :flushed:
|
||||||
|
utf("\xF0\x9F\x98\x94"), // :pensive:
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageReactions::MessageReactions(not_null<HistoryItem*> item)
|
||||||
|
: _item(item) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageReactions::add(const QString &reaction) {
|
||||||
|
if (_chosen == reaction) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_chosen.isEmpty()) {
|
||||||
|
const auto i = _list.find(_chosen);
|
||||||
|
Assert(i != end(_list));
|
||||||
|
--i->second;
|
||||||
|
if (!i->second) {
|
||||||
|
_list.erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_chosen = reaction;
|
||||||
|
if (!reaction.isEmpty()) {
|
||||||
|
++_list[reaction];
|
||||||
|
}
|
||||||
|
sendRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageReactions::set(
|
||||||
|
const QVector<MTPReactionCount> &list,
|
||||||
|
bool ignoreChosen) {
|
||||||
|
if (_requestId) {
|
||||||
|
// We'll apply non-stale data from the request response.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto existing = base::flat_set<QString>();
|
||||||
|
for (const auto &count : list) {
|
||||||
|
count.match([&](const MTPDreactionCount &data) {
|
||||||
|
const auto reaction = qs(data.vreaction());
|
||||||
|
if (data.is_chosen() && !ignoreChosen) {
|
||||||
|
_chosen = reaction;
|
||||||
|
}
|
||||||
|
_list[reaction] = data.vcount().v;
|
||||||
|
existing.emplace(reaction);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (_list.size() != existing.size()) {
|
||||||
|
for (auto i = begin(_list); i != end(_list);) {
|
||||||
|
if (!existing.contains(i->first)) {
|
||||||
|
i = _list.erase(i);
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!_chosen.isEmpty() && !_list.contains(_chosen)) {
|
||||||
|
_chosen = QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const base::flat_map<QString, int> &MessageReactions::list() const {
|
||||||
|
return _list;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MessageReactions::chosen() const {
|
||||||
|
return _chosen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageReactions::sendRequest() {
|
||||||
|
const auto api = &_item->history()->session().api();
|
||||||
|
if (_requestId) {
|
||||||
|
api->request(_requestId).cancel();
|
||||||
|
}
|
||||||
|
const auto flags = _chosen.isEmpty()
|
||||||
|
? MTPmessages_SendReaction::Flag(0)
|
||||||
|
: MTPmessages_SendReaction::Flag::f_reaction;
|
||||||
|
_requestId = api->request(MTPmessages_SendReaction(
|
||||||
|
MTP_flags(flags),
|
||||||
|
_item->history()->peer->input,
|
||||||
|
MTP_int(_item->id),
|
||||||
|
MTP_string(_chosen)
|
||||||
|
)).done([=](const MTPUpdates &result) {
|
||||||
|
_requestId = 0;
|
||||||
|
api->applyUpdates(result);
|
||||||
|
}).fail([=](const MTP::Error &error) {
|
||||||
|
_requestId = 0;
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Data
|
34
Telegram/SourceFiles/data/data_message_reactions.h
Normal file
34
Telegram/SourceFiles/data/data_message_reactions.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
|
||||||
|
class MessageReactions final {
|
||||||
|
public:
|
||||||
|
static std::vector<QString> SuggestList();
|
||||||
|
|
||||||
|
explicit MessageReactions(not_null<HistoryItem*> item);
|
||||||
|
|
||||||
|
void add(const QString &reaction);
|
||||||
|
void set(const QVector<MTPReactionCount> &list, bool ignoreChosen);
|
||||||
|
[[nodiscard]] const base::flat_map<QString, int> &list() const;
|
||||||
|
[[nodiscard]] QString chosen() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void sendRequest();
|
||||||
|
|
||||||
|
const not_null<HistoryItem*> _item;
|
||||||
|
|
||||||
|
QString _chosen;
|
||||||
|
base::flat_map<QString, int> _list;
|
||||||
|
mtpRequestId _requestId = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Data
|
|
@ -61,6 +61,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
|
#include "data/data_message_reactions.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_poll.h"
|
#include "data/data_poll.h"
|
||||||
|
@ -1683,6 +1684,17 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto itemId = item->fullId();
|
const auto itemId = item->fullId();
|
||||||
|
if (item->canReact()) {
|
||||||
|
auto reactionMenu = std::make_unique<Ui::PopupMenu>(
|
||||||
|
this,
|
||||||
|
st::reactionMenu);
|
||||||
|
for (const auto &text : Data::MessageReactions::SuggestList()) {
|
||||||
|
reactionMenu->addAction(text, [=] {
|
||||||
|
item->addReaction(text);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_menu->addAction("Reaction", std::move(reactionMenu));
|
||||||
|
}
|
||||||
if (canSendMessages) {
|
if (canSendMessages) {
|
||||||
_menu->addAction(tr::lng_context_reply_msg(tr::now), [=] {
|
_menu->addAction(tr::lng_context_reply_msg(tr::now), [=] {
|
||||||
_widget->replyToMessage(itemId);
|
_widget->replyToMessage(itemId);
|
||||||
|
|
|
@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_scheduled_messages.h" // kScheduledUntilOnlineTimestamp
|
#include "data/data_scheduled_messages.h" // kScheduledUntilOnlineTimestamp
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_message_reactions.h"
|
||||||
#include "data/data_messages.h"
|
#include "data/data_messages.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
#include "data/data_folder.h"
|
#include "data/data_folder.h"
|
||||||
|
@ -741,6 +742,38 @@ bool HistoryItem::suggestDeleteAllReport() const {
|
||||||
return !isPost() && !out();
|
return !isPost() && !out();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryItem::canReact() const {
|
||||||
|
return IsServerMsgId(id) && !out() && !_history->peer->isSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryItem::addReaction(const QString &reaction) {
|
||||||
|
if (!_reactions) {
|
||||||
|
_reactions = std::make_unique<Data::MessageReactions>(this);
|
||||||
|
}
|
||||||
|
_reactions->add(reaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryItem::updateReactions(const MTPMessageReactions &reactions) {
|
||||||
|
reactions.match([&](const MTPDmessageReactions &data) {
|
||||||
|
if (data.vresults().v.isEmpty()) {
|
||||||
|
_reactions = nullptr;
|
||||||
|
return;
|
||||||
|
} else if (!_reactions) {
|
||||||
|
_reactions = std::make_unique<Data::MessageReactions>(this);
|
||||||
|
}
|
||||||
|
_reactions->set(data.vresults().v, data.is_min());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const base::flat_map<QString, int> &HistoryItem::reactions() const {
|
||||||
|
static const auto kEmpty = base::flat_map<QString, int>();
|
||||||
|
return _reactions ? _reactions->list() : kEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString HistoryItem::chosenReaction() const {
|
||||||
|
return _reactions ? _reactions->chosen() : QString();
|
||||||
|
}
|
||||||
|
|
||||||
bool HistoryItem::hasDirectLink() const {
|
bool HistoryItem::hasDirectLink() const {
|
||||||
return isRegular() && _history->peer->isChannel();
|
return isRegular() && _history->peer->isChannel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ struct RippleAnimation;
|
||||||
namespace Data {
|
namespace Data {
|
||||||
struct MessagePosition;
|
struct MessagePosition;
|
||||||
class Media;
|
class Media;
|
||||||
|
class MessageReactions;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
|
@ -389,6 +390,12 @@ public:
|
||||||
[[nodiscard]] bool suggestBanReport() const;
|
[[nodiscard]] bool suggestBanReport() const;
|
||||||
[[nodiscard]] bool suggestDeleteAllReport() const;
|
[[nodiscard]] bool suggestDeleteAllReport() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool canReact() const;
|
||||||
|
void addReaction(const QString &reaction);
|
||||||
|
void updateReactions(const MTPMessageReactions &reactions);
|
||||||
|
[[nodiscard]] const base::flat_map<QString, int> &reactions() const;
|
||||||
|
[[nodiscard]] QString chosenReaction() const;
|
||||||
|
|
||||||
[[nodiscard]] bool hasDirectLink() const;
|
[[nodiscard]] bool hasDirectLink() const;
|
||||||
|
|
||||||
[[nodiscard]] FullMsgId fullId() const;
|
[[nodiscard]] FullMsgId fullId() const;
|
||||||
|
@ -489,6 +496,7 @@ protected:
|
||||||
|
|
||||||
SavedMediaData _savedLocalEditMediaData;
|
SavedMediaData _savedLocalEditMediaData;
|
||||||
std::unique_ptr<Data::Media> _media;
|
std::unique_ptr<Data::Media> _media;
|
||||||
|
std::unique_ptr<Data::MessageReactions> _reactions;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,12 @@ historyThemeSize: size(272px, 176px);
|
||||||
|
|
||||||
historyMinimalWidth: 380px;
|
historyMinimalWidth: 380px;
|
||||||
|
|
||||||
|
reactionMenu: PopupMenu(defaultPopupMenu) {
|
||||||
|
menu: Menu(defaultMenu) {
|
||||||
|
widthMin: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
historyScroll: ScrollArea(defaultScrollArea) {
|
historyScroll: ScrollArea(defaultScrollArea) {
|
||||||
bg: historyScrollBg;
|
bg: historyScrollBg;
|
||||||
bgOver: historyScrollBgOver;
|
bgOver: historyScrollBgOver;
|
||||||
|
|
Loading…
Add table
Reference in a new issue