Attempt to fix a crash in reactions list view.
This commit is contained in:
parent
9eba8ccc73
commit
5fe2e649fb
|
@ -31,28 +31,50 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kContextReactionsLimit = 50;
|
constexpr auto kContextReactionsLimit = 50;
|
||||||
|
|
||||||
|
struct Peers {
|
||||||
|
std::vector<PeerId> list;
|
||||||
|
bool unknown = false;
|
||||||
|
};
|
||||||
|
inline bool operator==(const Peers &a, const Peers &b) noexcept {
|
||||||
|
return (a.list == b.list) && (a.unknown == b.unknown);
|
||||||
|
}
|
||||||
|
|
||||||
struct PeerWithReaction {
|
struct PeerWithReaction {
|
||||||
PeerId peer = 0;
|
PeerId peer = 0;
|
||||||
QString reaction;
|
QString reaction;
|
||||||
};
|
};
|
||||||
bool operator==(const PeerWithReaction &a, const PeerWithReaction &b) {
|
inline bool operator==(
|
||||||
|
const PeerWithReaction &a,
|
||||||
|
const PeerWithReaction &b) noexcept {
|
||||||
return (a.peer == b.peer) && (a.reaction == b.reaction);
|
return (a.peer == b.peer) && (a.reaction == b.reaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PeersWithReactions {
|
||||||
|
std::vector<PeerWithReaction> list;
|
||||||
|
int fullReactionsCount = 0;
|
||||||
|
bool unknown = false;
|
||||||
|
};
|
||||||
|
inline bool operator==(
|
||||||
|
const PeersWithReactions &a,
|
||||||
|
const PeersWithReactions &b) noexcept {
|
||||||
|
return (a.fullReactionsCount == b.fullReactionsCount)
|
||||||
|
&& (a.list == b.list)
|
||||||
|
&& (a.unknown == b.unknown);
|
||||||
|
}
|
||||||
|
|
||||||
struct CachedRead {
|
struct CachedRead {
|
||||||
explicit CachedRead(PeerId unknownFlag)
|
CachedRead()
|
||||||
: list(std::vector<PeerId>{ unknownFlag }) {
|
: data(Peers{ .unknown = true }) {
|
||||||
}
|
}
|
||||||
rpl::variable<std::vector<PeerId>> list;
|
rpl::variable<Peers> data;
|
||||||
mtpRequestId requestId = 0;
|
mtpRequestId requestId = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CachedReacted {
|
struct CachedReacted {
|
||||||
explicit CachedReacted(PeerId unknownFlag)
|
CachedReacted()
|
||||||
: list(
|
: data(PeersWithReactions{ .unknown = true }) {
|
||||||
std::vector<PeerWithReaction>{ PeerWithReaction{ unknownFlag } }) {
|
|
||||||
}
|
}
|
||||||
rpl::variable<std::vector<PeerWithReaction>> list;
|
rpl::variable<PeersWithReactions> data;
|
||||||
mtpRequestId requestId = 0;
|
mtpRequestId requestId = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,10 +88,7 @@ struct Context {
|
||||||
if (i != end(cachedRead)) {
|
if (i != end(cachedRead)) {
|
||||||
return i->second;
|
return i->second;
|
||||||
}
|
}
|
||||||
return cachedRead.emplace(
|
return cachedRead.emplace(item, CachedRead()).first->second;
|
||||||
item,
|
|
||||||
CachedRead(item->history()->session().userPeerId())
|
|
||||||
).first->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] CachedReacted &cacheReacted(not_null<HistoryItem*> item) {
|
[[nodiscard]] CachedReacted &cacheReacted(not_null<HistoryItem*> item) {
|
||||||
|
@ -77,10 +96,7 @@ struct Context {
|
||||||
if (i != end(cachedReacted)) {
|
if (i != end(cachedReacted)) {
|
||||||
return i->second;
|
return i->second;
|
||||||
}
|
}
|
||||||
return cachedReacted.emplace(
|
return cachedReacted.emplace(item, CachedReacted()).first->second;
|
||||||
item,
|
|
||||||
CachedReacted(item->history()->session().userPeerId())
|
|
||||||
).first->second;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -193,7 +209,7 @@ struct State {
|
||||||
return Ui::WhoReadType::Seen;
|
return Ui::WhoReadType::Seen;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<std::vector<PeerId>> WhoReadIds(
|
[[nodiscard]] rpl::producer<Peers> WhoReadIds(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
not_null<QWidget*> context) {
|
not_null<QWidget*> context) {
|
||||||
auto weak = QPointer<QWidget>(context.get());
|
auto weak = QPointer<QWidget>(context.get());
|
||||||
|
@ -213,32 +229,35 @@ struct State {
|
||||||
).done([=](const MTPVector<MTPlong> &result) {
|
).done([=](const MTPVector<MTPlong> &result) {
|
||||||
auto &entry = context->cacheRead(item);
|
auto &entry = context->cacheRead(item);
|
||||||
entry.requestId = 0;
|
entry.requestId = 0;
|
||||||
auto peers = std::vector<PeerId>();
|
auto parsed = Peers();
|
||||||
peers.reserve(std::max(int(result.v.size()), 1));
|
parsed.list.reserve(result.v.size());
|
||||||
for (const auto &id : result.v) {
|
for (const auto &id : result.v) {
|
||||||
peers.push_back(UserId(id));
|
parsed.list.push_back(UserId(id));
|
||||||
}
|
}
|
||||||
entry.list = std::move(peers);
|
entry.data = std::move(parsed);
|
||||||
}).fail([=] {
|
}).fail([=] {
|
||||||
auto &entry = context->cacheRead(item);
|
auto &entry = context->cacheRead(item);
|
||||||
entry.requestId = 0;
|
entry.requestId = 0;
|
||||||
if (ListUnknown(entry.list.current(), item)) {
|
if (entry.data.current().unknown) {
|
||||||
entry.list = std::vector<PeerId>();
|
entry.data = Peers();
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
return entry.list.value().start_existing(consumer);
|
return entry.data.value().start_existing(consumer);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::vector < PeerWithReaction> WithEmptyReactions(
|
[[nodiscard]] PeersWithReactions WithEmptyReactions(
|
||||||
const std::vector<PeerId> &peers) {
|
const Peers &peers) {
|
||||||
return peers | ranges::views::transform([](PeerId peer) {
|
return PeersWithReactions{
|
||||||
return PeerWithReaction{ .peer = peer };
|
.list = peers.list | ranges::views::transform([](PeerId peer) {
|
||||||
}) | ranges::to_vector;
|
return PeerWithReaction{.peer = peer };
|
||||||
|
}) | ranges::to_vector,
|
||||||
|
.unknown = peers.unknown,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<std::vector<PeerWithReaction>> WhoReactedIds(
|
[[nodiscard]] rpl::producer<PeersWithReactions> WhoReactedIds(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
not_null<QWidget*> context) {
|
not_null<QWidget*> context) {
|
||||||
auto weak = QPointer<QWidget>(context.get());
|
auto weak = QPointer<QWidget>(context.get());
|
||||||
|
@ -267,46 +286,47 @@ struct State {
|
||||||
const MTPDmessages_messageReactionsList &data) {
|
const MTPDmessages_messageReactionsList &data) {
|
||||||
session->data().processUsers(data.vusers());
|
session->data().processUsers(data.vusers());
|
||||||
|
|
||||||
auto peers = std::vector<PeerWithReaction>();
|
auto parsed = PeersWithReactions{
|
||||||
peers.reserve(data.vreactions().v.size());
|
.fullReactionsCount = data.vcount().v,
|
||||||
|
};
|
||||||
|
parsed.list.reserve(data.vreactions().v.size());
|
||||||
for (const auto &vote : data.vreactions().v) {
|
for (const auto &vote : data.vreactions().v) {
|
||||||
vote.match([&](const auto &data) {
|
vote.match([&](const auto &data) {
|
||||||
peers.push_back(PeerWithReaction{
|
parsed.list.push_back(PeerWithReaction{
|
||||||
.peer = peerFromUser(data.vuser_id()),
|
.peer = peerFromUser(data.vuser_id()),
|
||||||
.reaction = qs(data.vreaction()),
|
.reaction = qs(data.vreaction()),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
entry.list = std::move(peers);
|
entry.data = std::move(parsed);
|
||||||
});
|
});
|
||||||
}).fail([=] {
|
}).fail([=] {
|
||||||
auto &entry = context->cacheReacted(item);
|
auto &entry = context->cacheReacted(item);
|
||||||
entry.requestId = 0;
|
entry.requestId = 0;
|
||||||
if (ListUnknown(entry.list.current(), item)) {
|
if (entry.data.current().unknown) {
|
||||||
entry.list = std::vector<PeerWithReaction>();
|
entry.data = PeersWithReactions();
|
||||||
}
|
}
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
return entry.list.value().start_existing(consumer);
|
return entry.data.value().start_existing(consumer);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto WhoReadOrReactedIds(
|
[[nodiscard]] auto WhoReadOrReactedIds(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
not_null<QWidget*> context)
|
not_null<QWidget*> context)
|
||||||
-> rpl::producer<std::vector<PeerWithReaction>> {
|
-> rpl::producer<PeersWithReactions> {
|
||||||
return rpl::combine(
|
return rpl::combine(
|
||||||
WhoReactedIds(item, context),
|
WhoReactedIds(item, context),
|
||||||
WhoReadIds(item, context)
|
WhoReadIds(item, context)
|
||||||
) | rpl::map([=](
|
) | rpl::map([=](PeersWithReactions reacted, Peers read) {
|
||||||
std::vector<PeerWithReaction> reacted,
|
if (reacted.unknown || read.unknown) {
|
||||||
std::vector<PeerId> read) {
|
return PeersWithReactions{ .unknown = true };
|
||||||
if (ListUnknown(reacted, item) || ListUnknown(read, item)) {
|
|
||||||
return reacted;
|
|
||||||
}
|
}
|
||||||
for (const auto &peer : read) {
|
auto &list = reacted.list;
|
||||||
if (!ranges::contains(reacted, peer, &PeerWithReaction::peer)) {
|
for (const auto &peer : read.list) {
|
||||||
reacted.push_back({ .peer = peer });
|
if (!ranges::contains(list, peer, &PeerWithReaction::peer)) {
|
||||||
|
list.push_back({ .peer = peer });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return reacted;
|
return reacted;
|
||||||
|
@ -499,19 +519,20 @@ rpl::producer<Ui::WhoReadContent> WhoReacted(
|
||||||
}
|
}
|
||||||
std::move(
|
std::move(
|
||||||
idsWithReactions
|
idsWithReactions
|
||||||
) | rpl::start_with_next([=](
|
) | rpl::start_with_next([=](const PeersWithReactions &peers) {
|
||||||
const std::vector<PeerWithReaction> &peers) {
|
if (peers.unknown) {
|
||||||
if (ListUnknown(peers, item)) {
|
|
||||||
state->userpics.clear();
|
state->userpics.clear();
|
||||||
consumer.put_next(Ui::WhoReadContent{
|
consumer.put_next(Ui::WhoReadContent{
|
||||||
.type = state->current.type,
|
.type = state->current.type,
|
||||||
.unknown = true,
|
.unknown = true,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} else if (UpdateUserpics(state, item, peers)) {
|
}
|
||||||
|
state->current.fullReactionsCount = peers.fullReactionsCount;
|
||||||
|
if (UpdateUserpics(state, item, peers.list)) {
|
||||||
RegenerateParticipants(state, small, large);
|
RegenerateParticipants(state, small, large);
|
||||||
pushNext();
|
pushNext();
|
||||||
} else if (peers.empty()) {
|
} else if (peers.list.empty()) {
|
||||||
pushNext();
|
pushNext();
|
||||||
}
|
}
|
||||||
}, lifetime);
|
}, lifetime);
|
||||||
|
|
|
@ -455,7 +455,7 @@ void Action::refreshText() {
|
||||||
_st.itemStyle,
|
_st.itemStyle,
|
||||||
{ (_content.unknown
|
{ (_content.unknown
|
||||||
? tr::lng_context_seen_loading(tr::now)
|
? tr::lng_context_seen_loading(tr::now)
|
||||||
: (count == 1)
|
: (usersCount == 1)
|
||||||
? _content.participants.front().name
|
? _content.participants.front().name
|
||||||
: (_content.type == WhoReadType::Reacted
|
: (_content.type == WhoReadType::Reacted
|
||||||
|| (count > 0 && _content.fullReactionsCount > usersCount))
|
|| (count > 0 && _content.fullReactionsCount > usersCount))
|
||||||
|
|
Loading…
Reference in New Issue