Added list of public forwards for story statistics.

This commit is contained in:
23rd 2023-11-28 05:30:16 +03:00 committed by John Preston
parent dfe55b26a2
commit 2542ec5d93
8 changed files with 157 additions and 56 deletions

View file

@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "data/data_channel.h"
#include "data/data_peer.h"
#include "data/data_session.h"
#include "history/history.h"
#include "main/main_session.h"
@ -352,7 +351,7 @@ Data::SupergroupStatistics Statistics::supergroupStats() const {
PublicForwards::PublicForwards(
not_null<ChannelData*> channel,
FullMsgId fullId)
Data::RecentPostId fullId)
: StatisticsRequestSender(channel)
, _fullId(fullId) {
}
@ -360,9 +359,20 @@ PublicForwards::PublicForwards(
void PublicForwards::request(
const Data::PublicForwardsSlice::OffsetToken &token,
Fn<void(Data::PublicForwardsSlice)> done) {
if (_requestId) {
return;
if (!_requestId) {
if (_fullId.messageId) {
requestMessage(token, std::move(done));
} else if (_fullId.storyId) {
requestStory(token, std::move(done));
}
}
}
void PublicForwards::requestMessage(
const Data::PublicForwardsSlice::OffsetToken &token,
Fn<void(Data::PublicForwardsSlice)> done) {
Expects(_fullId.messageId);
const auto offsetPeer = channel()->owner().peer(token.fullId.peer);
const auto tlOffsetPeer = offsetPeer
? offsetPeer->input
@ -370,13 +380,13 @@ void PublicForwards::request(
constexpr auto kLimit = tl::make_int(100);
_requestId = makeRequest(MTPstats_GetMessagePublicForwards(
channel()->inputChannel,
MTP_int(_fullId.msg),
MTP_int(_fullId.messageId.msg),
MTP_int(token.rate),
tlOffsetPeer,
MTP_int(token.fullId.msg),
kLimit
)).done([=, channel = channel()](const MTPmessages_Messages &result) {
using Messages = QVector<FullMsgId>;
using Messages = QVector<Data::RecentPostId>;
_requestId = 0;
auto nextToken = Data::PublicForwardsSlice::OffsetToken();
@ -393,7 +403,7 @@ void PublicForwards::request(
MessageFlags(),
NewMessageType::Existing);
nextToken.fullId = { peerId, msgId };
result.push_back(nextToken.fullId);
result.push_back({ .messageId = nextToken.fullId });
}
}
}
@ -448,11 +458,79 @@ void PublicForwards::request(
}).send();
}
void PublicForwards::requestStory(
const Data::PublicForwardsSlice::OffsetToken &token,
Fn<void(Data::PublicForwardsSlice)> done) {
Expects(_fullId.storyId);
constexpr auto kLimit = tl::make_int(100);
_requestId = makeRequest(MTPstats_GetStoryPublicForwards(
channel()->input,
MTP_int(_fullId.storyId.story),
MTP_string(token.storyOffset),
kLimit
)).done([=, channel = channel()](
const MTPstats_PublicForwards &tlForwards) {
using Messages = QVector<Data::RecentPostId>;
_requestId = 0;
const auto &data = tlForwards.data();
channel->owner().processUsers(data.vusers());
channel->owner().processChats(data.vchats());
const auto nextToken = Data::PublicForwardsSlice::OffsetToken({
.storyOffset = data.vnext_offset().value_or_empty(),
});
const auto allLoaded = nextToken.storyOffset.isEmpty()
|| (nextToken.storyOffset == token.storyOffset);
const auto fullCount = data.vcount().v;
auto recentList = Messages();
for (const auto &tlForward : data.vforwards().v) {
tlForward.match([&](const MTPDpublicForwardMessage &data) {
const auto &message = data.vmessage();
const auto msgId = IdFromMessage(message);
const auto peerId = PeerFromMessage(message);
const auto lastDate = DateFromMessage(message);
if (const auto peer = channel->owner().peerLoaded(peerId)) {
if (!lastDate) {
return;
}
channel->owner().addNewMessage(
message,
MessageFlags(),
NewMessageType::Existing);
recentList.push_back({ .messageId = { peerId, msgId } });
}
}, [&](const MTPDpublicForwardStory &data) {
data.vstory().match([&](const MTPDstoryItem &d) {
recentList.push_back({
.storyId = { peerFromMTP(data.vpeer()), d.vid().v }
});
}, [](const auto &) {
});
});
}
_lastTotal = std::max(_lastTotal, fullCount);
done({
.list = std::move(recentList),
.total = _lastTotal,
.allLoaded = allLoaded,
.token = nextToken,
});
}).fail([=] {
_requestId = 0;
}).send();
}
MessageStatistics::MessageStatistics(
not_null<ChannelData*> channel,
FullMsgId fullId)
: StatisticsRequestSender(channel)
, _publicForwards(channel, fullId)
, _publicForwards(channel, { .messageId = fullId })
, _fullId(fullId) {
}
@ -460,7 +538,7 @@ MessageStatistics::MessageStatistics(
not_null<ChannelData*> channel,
FullStoryId storyId)
: StatisticsRequestSender(channel)
, _publicForwards(channel, {})
, _publicForwards(channel, { .storyId = storyId })
, _storyId(storyId) {
}
@ -476,7 +554,7 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
const Data::StatisticalGraph &messageGraph,
const Data::StatisticalGraph &reactionsGraph,
const Data::StatisticsMessageInteractionInfo &info) {
_publicForwards.request({}, [=](Data::PublicForwardsSlice slice) {
const auto callback = [=](Data::PublicForwardsSlice slice) {
const auto total = slice.total;
_firstSlice = std::move(slice);
done({
@ -487,7 +565,8 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
.views = info.viewsCount,
.reactions = info.reactionsCount,
});
});
};
_publicForwards.request({}, callback);
};
const auto requestPrivateForwards = [=](
@ -553,22 +632,27 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
MTP_vector<MTPint>(1, MTP_int(_storyId.story)))
).done([=](const MTPstories_Stories &result) {
const auto &storyItem = result.data().vstories().v.front();
storyItem.match([&](const MTPDstoryItem &data) {
auto info = storyItem.match([&](const MTPDstoryItem &data) {
if (!data.vviews()) {
return;
return Data::StatisticsMessageInteractionInfo();
}
const auto &tlViews = data.vviews()->data();
done({
.messageInteractionGraph = messageGraph,
.reactionsByEmotionGraph = reactionsGraph,
.publicForwards = -1,
.privateForwards = tlViews.vforwards_count().value_or(0),
.views = tlViews.vviews_count().v,
.reactions = tlViews.vreactions_count().value_or(0),
});
return Data::StatisticsMessageInteractionInfo{
.storyId = data.vid().v,
.viewsCount = tlViews.vviews_count().v,
.forwardsCount = tlViews.vforwards_count().value_or(0),
.reactionsCount = tlViews.vreactions_count().value_or(0),
};
}, [](const auto &) {
return Data::StatisticsMessageInteractionInfo();
});
requestFirstPublicForwards(
messageGraph,
reactionsGraph,
std::move(info));
}).fail([=](const MTP::Error &error) {
requestFirstPublicForwards(messageGraph, reactionsGraph, {});
}).send();
};

View file

@ -68,14 +68,23 @@ private:
class PublicForwards final : public StatisticsRequestSender {
public:
PublicForwards(not_null<ChannelData*> channel, FullMsgId fullId);
PublicForwards(
not_null<ChannelData*> channel,
Data::RecentPostId fullId);
void request(
const Data::PublicForwardsSlice::OffsetToken &token,
Fn<void(Data::PublicForwardsSlice)> done);
private:
const FullMsgId _fullId;
void requestMessage(
const Data::PublicForwardsSlice::OffsetToken &token,
Fn<void(Data::PublicForwardsSlice)> done);
void requestStory(
const Data::PublicForwardsSlice::OffsetToken &token,
Fn<void(Data::PublicForwardsSlice)> done);
const Data::RecentPostId _fullId;
mtpRequestId _requestId = 0;
int _lastTotal = 0;

View file

@ -133,12 +133,27 @@ struct AnyStatistics final {
Data::StoryStatistics story;
};
struct RecentPostId final {
FullMsgId messageId;
FullStoryId storyId;
[[nodiscard]] bool valid() const {
return messageId || storyId;
}
explicit operator bool() const {
return valid();
}
friend inline auto operator<=>(RecentPostId, RecentPostId) = default;
friend inline bool operator==(RecentPostId, RecentPostId) = default;
};
struct PublicForwardsSlice final {
struct OffsetToken final {
int rate = 0;
FullMsgId fullId;
QString storyOffset;
};
QVector<FullMsgId> list;
QVector<RecentPostId> list;
int total = 0;
bool allLoaded = false;
OffsetToken token;

View file

@ -11,23 +11,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Info::Statistics {
struct RecentPostId final {
FullMsgId messageId;
FullStoryId storyId;
[[nodiscard]] bool valid() const {
return messageId || storyId;
}
explicit operator bool() const {
return valid();
}
friend inline auto operator<=>(RecentPostId, RecentPostId) = default;
friend inline bool operator==(RecentPostId, RecentPostId) = default;
};
struct SavedState final {
Data::AnyStatistics stats;
base::flat_map<RecentPostId, QImage> recentPostPreviews;
base::flat_map<Data::RecentPostId, QImage> recentPostPreviews;
Data::PublicForwardsSlice publicForwardsFirstSlice;
int recentPostsExpanded = 0;
};

View file

@ -641,7 +641,7 @@ void InnerWidget::load() {
.message = _contextId ? data : Data::StoryStatistics(),
.story = _storyId ? data : Data::StoryStatistics(),
};
if (_contextId) {
if (_contextId || _storyId) {
_state.publicForwardsFirstSlice = api->firstSlice();
}
fill();
@ -726,13 +726,14 @@ void InnerWidget::fill() {
descriptor.peer,
tr::lng_stats_inviters_title());
}
} else if (message) {
} else if (_state.stats.message || _state.stats.story) {
using namespace Data;
AddPublicForwards(
_state.publicForwardsFirstSlice,
inner,
[=](FullMsgId id) { _showRequests.fire({ .history = id }); },
descriptor.peer,
_contextId);
RecentPostId{ .messageId = _contextId, .storyId = _storyId });
}
}
@ -762,7 +763,7 @@ void InnerWidget::fillRecentPosts() {
messageWrap,
rpl::never<QString>(),
st::statisticsRecentPostButton));
const auto fullRecentId = RecentPostId{
const auto fullRecentId = Data::RecentPostId{
.messageId = maybeItem ? maybeItem->fullId() : FullMsgId(),
.storyId = maybeStory ? maybeStory->fullId() : FullStoryId(),
};
@ -886,7 +887,8 @@ void InnerWidget::restoreState(not_null<Memento*> memento) {
_state = memento->state();
if (_state.stats.channel
|| _state.stats.supergroup
|| _state.stats.message) {
|| _state.stats.message
|| _state.stats.story) {
fill();
} else {
load();

View file

@ -91,11 +91,11 @@ void AddSubtitle(
return resultText;
}
struct Descriptor final {
struct PublicForwardsDescriptor final {
Data::PublicForwardsSlice firstSlice;
Fn<void(FullMsgId)> showPeerHistory;
not_null<PeerData*> peer;
FullMsgId contextId;
Data::RecentPostId contextId;
};
struct MembersDescriptor final {
@ -229,7 +229,7 @@ void MembersController::rowClicked(not_null<PeerListRow*> row) {
class PublicForwardsController final : public PeerListController {
public:
explicit PublicForwardsController(Descriptor d);
explicit PublicForwardsController(PublicForwardsDescriptor d);
Main::Session &session() const override;
void prepare() override;
@ -251,7 +251,7 @@ private:
};
PublicForwardsController::PublicForwardsController(Descriptor d)
PublicForwardsController::PublicForwardsController(PublicForwardsDescriptor d)
: _session(&d.peer->session())
, _showPeerHistory(std::move(d.showPeerHistory))
, _api(d.peer->asChannel(), d.contextId)
@ -282,8 +282,11 @@ void PublicForwardsController::applySlice(
_apiToken = slice.token;
for (const auto &item : slice.list) {
if (const auto peer = session().data().peerLoaded(item.peer)) {
appendRow(peer, item.msg);
// TODO support stories.
if (const auto fullId = item.messageId) {
if (const auto peer = session().data().peerLoaded(fullId.peer)) {
appendRow(peer, fullId.msg);
}
}
}
delegate()->peerListRefreshRows();
@ -617,23 +620,24 @@ void AddPublicForwards(
not_null<Ui::VerticalLayout*> container,
Fn<void(FullMsgId)> showPeerHistory,
not_null<PeerData*> peer,
FullMsgId contextId) {
Data::RecentPostId contextId) {
if (!peer->isChannel()) {
return;
}
struct State final {
State(Descriptor d) : controller(std::move(d)) {
State(PublicForwardsDescriptor d) : controller(std::move(d)) {
}
PeerListContentDelegateSimple delegate;
PublicForwardsController controller;
};
const auto state = container->lifetime().make_state<State>(Descriptor{
auto d = PublicForwardsDescriptor{
firstSlice,
std::move(showPeerHistory),
peer,
contextId,
});
};
const auto state = container->lifetime().make_state<State>(std::move(d));
if (const auto total = firstSlice.total; total > 0) {
AddSubtitle(

View file

@ -17,6 +17,7 @@ namespace Data {
struct Boost;
struct BoostsListSlice;
struct PublicForwardsSlice;
struct RecentPostId;
struct SupergroupStatistics;
} // namespace Data
@ -27,7 +28,7 @@ void AddPublicForwards(
not_null<Ui::VerticalLayout*> container,
Fn<void(FullMsgId)> showPeerHistory,
not_null<PeerData*> peer,
FullMsgId contextId);
Data::RecentPostId contextId);
void AddMembersList(
Data::SupergroupStatistics data,

View file

@ -349,7 +349,7 @@ void MessagePreview::paintEvent(QPaintEvent *e) {
void MessagePreview::saveState(SavedState &state) const {
if (!_lifetimeDownload) {
const auto fullId = RecentPostId{ _messageId, _storyId };
const auto fullId = Data::RecentPostId{ _messageId, _storyId };
state.recentPostPreviews[fullId] = _preview;
}
}