Correctly handle reactions from channels.
This commit is contained in:
parent
29d0c8c2ec
commit
918af601cf
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_account.h"
|
#include "main/main_account.h"
|
||||||
#include "main/main_app_config.h"
|
#include "main/main_app_config.h"
|
||||||
|
#include "main/session/send_as_peers.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
|
@ -82,6 +83,30 @@ constexpr auto kTopReactionsLimit = 14;
|
||||||
: config->get<int>("reactions_user_max_default", 1);
|
: config->get<int>("reactions_user_max_default", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsMyRecent(
|
||||||
|
const MTPDmessagePeerReaction &data,
|
||||||
|
const ReactionId &id,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
const base::flat_map<
|
||||||
|
ReactionId,
|
||||||
|
std::vector<RecentReaction>> &recent,
|
||||||
|
bool ignoreChosen) {
|
||||||
|
if (peer->id == peer->session().userPeerId()) {
|
||||||
|
return true;
|
||||||
|
} else if (!ignoreChosen) {
|
||||||
|
return data.is_my();
|
||||||
|
}
|
||||||
|
const auto j = recent.find(id);
|
||||||
|
if (j == end(recent)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto k = ranges::find(
|
||||||
|
j->second,
|
||||||
|
peer,
|
||||||
|
&RecentReaction::peer);
|
||||||
|
return (k != end(j->second)) && k->my;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
PossibleItemReactionsRef LookupPossibleReactions(
|
PossibleItemReactionsRef LookupPossibleReactions(
|
||||||
|
@ -953,7 +978,6 @@ void MessageReactions::add(const ReactionId &id, bool addToRecent) {
|
||||||
Expects(!id.empty());
|
Expects(!id.empty());
|
||||||
|
|
||||||
const auto history = _item->history();
|
const auto history = _item->history();
|
||||||
const auto self = history->session().user();
|
|
||||||
const auto myLimit = SentReactionsLimit(_item);
|
const auto myLimit = SentReactionsLimit(_item);
|
||||||
if (ranges::contains(chosen(), id)) {
|
if (ranges::contains(chosen(), id)) {
|
||||||
return;
|
return;
|
||||||
|
@ -973,7 +997,7 @@ void MessageReactions::add(const ReactionId &id, bool addToRecent) {
|
||||||
_recent.erase(j);
|
_recent.erase(j);
|
||||||
} else {
|
} else {
|
||||||
j->second.erase(
|
j->second.erase(
|
||||||
ranges::remove(j->second, self, &RecentReaction::peer),
|
ranges::remove(j->second, true, &RecentReaction::my),
|
||||||
end(j->second));
|
end(j->second));
|
||||||
if (j->second.empty()) {
|
if (j->second.empty()) {
|
||||||
_recent.erase(j);
|
_recent.erase(j);
|
||||||
|
@ -982,9 +1006,14 @@ void MessageReactions::add(const ReactionId &id, bool addToRecent) {
|
||||||
}
|
}
|
||||||
return removed;
|
return removed;
|
||||||
}), end(_list));
|
}), end(_list));
|
||||||
if (_item->canViewReactions() || history->peer->isUser()) {
|
const auto peer = history->peer;
|
||||||
|
if (_item->canViewReactions() || peer->isUser()) {
|
||||||
auto &list = _recent[id];
|
auto &list = _recent[id];
|
||||||
list.insert(begin(list), RecentReaction{ self });
|
const auto from = peer->session().sendAsPeers().resolveChosen(peer);
|
||||||
|
list.insert(begin(list), RecentReaction{
|
||||||
|
.peer = from,
|
||||||
|
.my = true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const auto i = ranges::find(_list, id, &MessageReaction::id);
|
const auto i = ranges::find(_list, id, &MessageReaction::id);
|
||||||
if (i != end(_list)) {
|
if (i != end(_list)) {
|
||||||
|
@ -1018,13 +1047,16 @@ void MessageReactions::remove(const ReactionId &id) {
|
||||||
_list.erase(i);
|
_list.erase(i);
|
||||||
}
|
}
|
||||||
if (j != end(_recent)) {
|
if (j != end(_recent)) {
|
||||||
|
if (removed) {
|
||||||
|
j->second.clear();
|
||||||
|
_recent.erase(j);
|
||||||
|
} else {
|
||||||
j->second.erase(
|
j->second.erase(
|
||||||
ranges::remove(j->second, self, &RecentReaction::peer),
|
ranges::remove(j->second, true, &RecentReaction::my),
|
||||||
end(j->second));
|
end(j->second));
|
||||||
if (j->second.empty()) {
|
if (j->second.empty()) {
|
||||||
_recent.erase(j);
|
_recent.erase(j);
|
||||||
} else {
|
}
|
||||||
Assert(!removed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto &owner = history->owner();
|
auto &owner = history->owner();
|
||||||
|
@ -1034,7 +1066,8 @@ void MessageReactions::remove(const ReactionId &id) {
|
||||||
|
|
||||||
bool MessageReactions::checkIfChanged(
|
bool MessageReactions::checkIfChanged(
|
||||||
const QVector<MTPReactionCount> &list,
|
const QVector<MTPReactionCount> &list,
|
||||||
const QVector<MTPMessagePeerReaction> &recent) const {
|
const QVector<MTPMessagePeerReaction> &recent,
|
||||||
|
bool min) const {
|
||||||
auto &owner = _item->history()->owner();
|
auto &owner = _item->history()->owner();
|
||||||
if (owner.reactions().sending(_item)) {
|
if (owner.reactions().sending(_item)) {
|
||||||
// We'll apply non-stale data from the request response.
|
// We'll apply non-stale data from the request response.
|
||||||
|
@ -1066,13 +1099,18 @@ bool MessageReactions::checkIfChanged(
|
||||||
for (const auto &reaction : recent) {
|
for (const auto &reaction : recent) {
|
||||||
reaction.match([&](const MTPDmessagePeerReaction &data) {
|
reaction.match([&](const MTPDmessagePeerReaction &data) {
|
||||||
const auto id = ReactionFromMTP(data.vreaction());
|
const auto id = ReactionFromMTP(data.vreaction());
|
||||||
if (ranges::contains(_list, id, &MessageReaction::id)) {
|
if (!ranges::contains(_list, id, &MessageReaction::id)) {
|
||||||
parsed[id].push_back(RecentReaction{
|
return;
|
||||||
.peer = owner.peer(peerFromMTP(data.vpeer_id())),
|
}
|
||||||
|
const auto peerId = peerFromMTP(data.vpeer_id());
|
||||||
|
const auto peer = owner.peer(peerId);
|
||||||
|
const auto my = IsMyRecent(data, id, peer, _recent, min);
|
||||||
|
parsed[id].push_back({
|
||||||
|
.peer = peer,
|
||||||
.unread = data.is_unread(),
|
.unread = data.is_unread(),
|
||||||
.big = data.is_big(),
|
.big = data.is_big(),
|
||||||
|
.my = my,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return !ranges::equal(_recent, parsed, [](
|
return !ranges::equal(_recent, parsed, [](
|
||||||
|
@ -1081,7 +1119,7 @@ bool MessageReactions::checkIfChanged(
|
||||||
return ranges::equal(a.second, b.second, [](
|
return ranges::equal(a.second, b.second, [](
|
||||||
const RecentReaction &a,
|
const RecentReaction &a,
|
||||||
const RecentReaction &b) {
|
const RecentReaction &b) {
|
||||||
return (a.peer == b.peer) && (a.big == b.big);
|
return (a.peer == b.peer) && (a.big == b.big) && (a.my == b.my);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1089,7 +1127,7 @@ bool MessageReactions::checkIfChanged(
|
||||||
bool MessageReactions::change(
|
bool MessageReactions::change(
|
||||||
const QVector<MTPReactionCount> &list,
|
const QVector<MTPReactionCount> &list,
|
||||||
const QVector<MTPMessagePeerReaction> &recent,
|
const QVector<MTPMessagePeerReaction> &recent,
|
||||||
bool ignoreChosen) {
|
bool min) {
|
||||||
auto &owner = _item->history()->owner();
|
auto &owner = _item->history()->owner();
|
||||||
if (owner.reactions().sending(_item)) {
|
if (owner.reactions().sending(_item)) {
|
||||||
// We'll apply non-stale data from the request response.
|
// We'll apply non-stale data from the request response.
|
||||||
|
@ -1102,7 +1140,7 @@ bool MessageReactions::change(
|
||||||
count.match([&](const MTPDreactionCount &data) {
|
count.match([&](const MTPDreactionCount &data) {
|
||||||
const auto id = ReactionFromMTP(data.vreaction());
|
const auto id = ReactionFromMTP(data.vreaction());
|
||||||
const auto &chosen = data.vchosen_order();
|
const auto &chosen = data.vchosen_order();
|
||||||
if (!ignoreChosen && chosen) {
|
if (!min && chosen) {
|
||||||
order[id] = chosen->v;
|
order[id] = chosen->v;
|
||||||
}
|
}
|
||||||
const auto i = ranges::find(_list, id, &MessageReaction::id);
|
const auto i = ranges::find(_list, id, &MessageReaction::id);
|
||||||
|
@ -1112,10 +1150,10 @@ bool MessageReactions::change(
|
||||||
_list.push_back({
|
_list.push_back({
|
||||||
.id = id,
|
.id = id,
|
||||||
.count = nowCount,
|
.count = nowCount,
|
||||||
.my = (!ignoreChosen && chosen)
|
.my = (!min && chosen)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const auto nowMy = ignoreChosen ? i->my : chosen.has_value();
|
const auto nowMy = min ? i->my : chosen.has_value();
|
||||||
if (i->count != nowCount || i->my != nowMy) {
|
if (i->count != nowCount || i->my != nowMy) {
|
||||||
i->count = nowCount;
|
i->count = nowCount;
|
||||||
i->my = nowMy;
|
i->my = nowMy;
|
||||||
|
@ -1125,13 +1163,13 @@ bool MessageReactions::change(
|
||||||
existing.emplace(id);
|
existing.emplace(id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!ignoreChosen && !order.empty()) {
|
if (!min && !order.empty()) {
|
||||||
const auto min = std::numeric_limits<int>::min();
|
const auto minimal = std::numeric_limits<int>::min();
|
||||||
const auto proj = [&](const MessageReaction &reaction) {
|
const auto proj = [&](const MessageReaction &reaction) {
|
||||||
return reaction.my ? order[reaction.id] : min;
|
return reaction.my ? order[reaction.id] : minimal;
|
||||||
};
|
};
|
||||||
const auto correctOrder = [&] {
|
const auto correctOrder = [&] {
|
||||||
auto previousOrder = min;
|
auto previousOrder = minimal;
|
||||||
for (const auto &reaction : _list) {
|
for (const auto &reaction : _list) {
|
||||||
const auto nowOrder = proj(reaction);
|
const auto nowOrder = proj(reaction);
|
||||||
if (nowOrder < previousOrder) {
|
if (nowOrder < previousOrder) {
|
||||||
|
@ -1156,21 +1194,28 @@ bool MessageReactions::change(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const auto selfId = owner.session().userPeerId();
|
||||||
auto parsed = base::flat_map<ReactionId, std::vector<RecentReaction>>();
|
auto parsed = base::flat_map<ReactionId, std::vector<RecentReaction>>();
|
||||||
for (const auto &reaction : recent) {
|
for (const auto &reaction : recent) {
|
||||||
reaction.match([&](const MTPDmessagePeerReaction &data) {
|
reaction.match([&](const MTPDmessagePeerReaction &data) {
|
||||||
const auto id = ReactionFromMTP(data.vreaction());
|
const auto id = ReactionFromMTP(data.vreaction());
|
||||||
const auto i = ranges::find(_list, id, &MessageReaction::id);
|
const auto i = ranges::find(_list, id, &MessageReaction::id);
|
||||||
if (i != end(_list)) {
|
if (i == end(_list)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto &list = parsed[id];
|
auto &list = parsed[id];
|
||||||
if (list.size() < i->count) {
|
if (list.size() >= i->count) {
|
||||||
list.push_back(RecentReaction{
|
return;
|
||||||
.peer = owner.peer(peerFromMTP(data.vpeer_id())),
|
}
|
||||||
|
const auto peerId = peerFromMTP(data.vpeer_id());
|
||||||
|
const auto peer = owner.peer(peerId);
|
||||||
|
const auto my = IsMyRecent(data, id, peer, _recent, min);
|
||||||
|
list.push_back({
|
||||||
|
.peer = peer,
|
||||||
.unread = data.is_unread(),
|
.unread = data.is_unread(),
|
||||||
.big = data.is_big(),
|
.big = data.is_big(),
|
||||||
|
.my = my,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (_recent != parsed) {
|
if (_recent != parsed) {
|
||||||
|
|
|
@ -225,14 +225,14 @@ struct RecentReaction {
|
||||||
not_null<PeerData*> peer;
|
not_null<PeerData*> peer;
|
||||||
bool unread = false;
|
bool unread = false;
|
||||||
bool big = false;
|
bool big = false;
|
||||||
|
bool my = false;
|
||||||
|
|
||||||
inline friend constexpr bool operator==(
|
friend inline auto operator<=>(
|
||||||
const RecentReaction &a,
|
const RecentReaction &a,
|
||||||
const RecentReaction &b) noexcept {
|
const RecentReaction &b) = default;
|
||||||
return (a.peer.get() == b.peer.get())
|
friend inline bool operator==(
|
||||||
&& (a.unread == b.unread)
|
const RecentReaction &a,
|
||||||
&& (a.big == b.big);
|
const RecentReaction &b) = default;
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class MessageReactions final {
|
class MessageReactions final {
|
||||||
|
@ -247,7 +247,8 @@ public:
|
||||||
bool ignoreChosen);
|
bool ignoreChosen);
|
||||||
[[nodiscard]] bool checkIfChanged(
|
[[nodiscard]] bool checkIfChanged(
|
||||||
const QVector<MTPReactionCount> &list,
|
const QVector<MTPReactionCount> &list,
|
||||||
const QVector<MTPMessagePeerReaction> &recent) const;
|
const QVector<MTPMessagePeerReaction> &recent,
|
||||||
|
bool ignoreChosen) const;
|
||||||
[[nodiscard]] const std::vector<MessageReaction> &list() const;
|
[[nodiscard]] const std::vector<MessageReaction> &list() const;
|
||||||
[[nodiscard]] auto recent() const
|
[[nodiscard]] auto recent() const
|
||||||
-> const base::flat_map<ReactionId, std::vector<RecentReaction>> &;
|
-> const base::flat_map<ReactionId, std::vector<RecentReaction>> &;
|
||||||
|
|
|
@ -3199,7 +3199,7 @@ bool HistoryItem::changeReactions(const MTPMessageReactions *reactions) {
|
||||||
const auto &recent = data.vrecent_reactions().value_or_empty();
|
const auto &recent = data.vrecent_reactions().value_or_empty();
|
||||||
if (min && hasUnreadReaction()) {
|
if (min && hasUnreadReaction()) {
|
||||||
// We can't update reactions from min if we have unread.
|
// We can't update reactions from min if we have unread.
|
||||||
if (_reactions->checkIfChanged(list, recent)) {
|
if (_reactions->checkIfChanged(list, recent, min)) {
|
||||||
updateReactionsUnknown();
|
updateReactionsUnknown();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in New Issue