From 8497b83f7cec285233158ff918075791784c2391 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 9 Oct 2023 04:41:13 +0300 Subject: [PATCH] Added list of public forwards to statistics of single message. --- Telegram/CMakeLists.txt | 2 + Telegram/Resources/langs/lang.strings | 4 + .../info_statistics_public_forwards.cpp | 209 ++++++++++++++++++ .../info_statistics_public_forwards.h | 24 ++ .../info_statistics_recent_message.cpp | 1 - .../statistics/info_statistics_widget.cpp | 22 ++ 6 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.cpp create mode 100644 Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 0890cfc554..9c825c7950 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -884,6 +884,8 @@ PRIVATE info/profile/info_profile_widget.h info/settings/info_settings_widget.cpp info/settings/info_settings_widget.h + info/statistics/info_statistics_public_forwards.cpp + info/statistics/info_statistics_public_forwards.h info/statistics/info_statistics_recent_message.cpp info/statistics/info_statistics_recent_message.h info/statistics/info_statistics_widget.cpp diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 3d734f98eb..93b2b0043a 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4077,6 +4077,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_stats_overview_messages" = "Messages"; "lng_stats_overview_group_mean_view_count" = "Viewing Members"; "lng_stats_overview_group_mean_post_count" = "Posting Members"; +"lng_stats_overview_message_private_shares" = "Private Shares"; +"lng_stats_overview_message_public_shares" = "Public Shares"; +"lng_stats_overview_message_public_share#one" = "{count} public share"; +"lng_stats_overview_message_public_share#other" = "{count} public shares"; "lng_stats_recent_messages_title" = "Recent posts"; "lng_stats_recent_messages_views#one" = "{count} view"; diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.cpp new file mode 100644 index 0000000000..76b267fa88 --- /dev/null +++ b/Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.cpp @@ -0,0 +1,209 @@ +/* +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 "info/statistics/info_statistics_public_forwards.h" + +#include "api/api_statistics.h" +#include "boxes/peer_list_controllers.h" +#include "data/data_channel.h" +#include "data/data_session.h" +#include "history/history_item.h" +#include "lang/lang_keys.h" +#include "main/main_session.h" +#include "settings/settings_common.h" +#include "ui/wrap/slide_wrap.h" +#include "ui/wrap/vertical_layout.h" +#include "styles/style_settings.h" + +namespace Info::Statistics { +namespace { + +class PeerListRowWithMsgId : public PeerListRow { +public: + using PeerListRow::PeerListRow; + + void setMsgId(MsgId msgId); + [[nodiscard]] MsgId msgId() const; + +private: + MsgId _msgId; + +}; + +void PeerListRowWithMsgId::setMsgId(MsgId msgId) { + _msgId = msgId; +} + +MsgId PeerListRowWithMsgId::msgId() const { + return _msgId; +} + +class PublicForwardsController final : public PeerListController { +public: + explicit PublicForwardsController( + Fn showPeerHistory, + not_null peer, + FullMsgId contextId); + + Main::Session &session() const override; + void prepare() override; + void rowClicked(not_null row) override; + void loadMoreRows() override; + + [[nodiscard]] rpl::producer totalCountChanges() const; + +private: + bool appendRow(not_null peer, MsgId msgId); + + const not_null _session; + Fn _showPeerHistory; + + Api::PublicForwards _api; + Api::PublicForwards::OffsetToken _apiToken; + + bool _allLoaded = false; + + rpl::event_stream _totalCountChanges; + +}; + +PublicForwardsController::PublicForwardsController( + Fn showPeerHistory, + not_null peer, + FullMsgId contextId) +: _session(&peer->session()) +, _showPeerHistory(std::move(showPeerHistory)) +, _api(peer->asChannel(), contextId) { +} + +Main::Session &PublicForwardsController::session() const { + return *_session; +} + +void PublicForwardsController::prepare() { + loadMoreRows(); + delegate()->peerListRefreshRows(); +} + +void PublicForwardsController::loadMoreRows() { + if (_allLoaded) { + return; + } + _api.request(_apiToken, [=](const Api::PublicForwards::Slice &slice) { + _allLoaded = slice.allLoaded; + _apiToken = slice.token; + _totalCountChanges.fire_copy(slice.total); + + for (const auto &item : slice.list) { + if (const auto peer = session().data().peerLoaded(item.peer)) { + appendRow(peer, item.msg); + } + } + delegate()->peerListRefreshRows(); + }); +} + +void PublicForwardsController::rowClicked(not_null row) { + const auto rowWithMsgId = static_cast(row.get()); + crl::on_main([=, msgId = rowWithMsgId->msgId(), peer = row->peer()] { + _showPeerHistory({ peer->id, msgId }); + }); +} + +bool PublicForwardsController::appendRow( + not_null peer, + MsgId msgId) { + if (delegate()->peerListFindRow(peer->id.value)) { + return false; + } + + auto row = std::make_unique(peer); + row->setMsgId(msgId); + + const auto members = peer->asChannel()->membersCount(); + const auto message = peer->owner().message({ peer->id, msgId }); + const auto views = message ? message->viewsCount() : 0; + + const auto membersText = !members + ? QString() + : peer->isMegagroup() + ? tr::lng_chat_status_members(tr::now, lt_count_decimal, members) + : tr::lng_chat_status_subscribers(tr::now, lt_count_decimal, members); + const auto viewsText = views + ? tr::lng_stats_recent_messages_views({}, lt_count_decimal, views) + : QString(); + const auto resultText = (membersText.isEmpty() || viewsText.isEmpty()) + ? membersText + viewsText + : QString("%1, %2").arg(membersText, viewsText); + row->setCustomStatus(resultText); + + delegate()->peerListAppendRow(std::move(row)); + return true; +} + +rpl::producer PublicForwardsController::totalCountChanges() const { + return _totalCountChanges.events(); +} + +} // namespace + +void AddPublicForwards( + not_null container, + Fn showPeerHistory, + not_null peer, + FullMsgId contextId) { + if (!peer->isChannel()) { + return; + } + + struct State final { + State( + Fn c, + not_null p, + FullMsgId i) : controller(std::move(c), p, i) { + } + PeerListContentDelegateSimple delegate; + PublicForwardsController controller; + }; + const auto state = container->lifetime().make_state( + std::move(showPeerHistory), + peer, + contextId); + + const auto wrap = container->add( + object_ptr>( + container, + object_ptr(container))); + wrap->toggle(false, anim::type::instant); + + auto title = state->controller.totalCountChanges( + ) | rpl::distinct_until_changed( + ) | rpl::map([=](int total) { + if (total && !wrap->toggled()) { + wrap->toggle(true, anim::type::normal); + } + return total + ? tr::lng_stats_overview_message_public_share( + tr::now, + lt_count_decimal, + total) + : QString(); + }); + + { + const auto &subtitlePadding = st::settingsButton.padding; + ::Settings::AddSubsectionTitle( + wrap->entity(), + std::move(title), + { 0, -subtitlePadding.top(), 0, -subtitlePadding.bottom() }); + } + state->delegate.setContent(wrap->entity()->add( + object_ptr(wrap->entity(), &state->controller))); + state->controller.setDelegate(&state->delegate); +} + +} // namespace Info::Statistics diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.h b/Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.h new file mode 100644 index 0000000000..43cb3c7a8b --- /dev/null +++ b/Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.h @@ -0,0 +1,24 @@ +/* +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 + +class PeerData; + +namespace Ui { +class VerticalLayout; +} // namespace Ui + +namespace Info::Statistics { + +void AddPublicForwards( + not_null container, + Fn showPeerHistory, + not_null peer, + FullMsgId contextId); + +} // namespace Info::Statistics diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_recent_message.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_recent_message.cpp index 976023556e..b6d3346fef 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_recent_message.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_recent_message.cpp @@ -224,4 +224,3 @@ void MessagePreview::paintEvent(QPaintEvent *e) { } } // namespace Info::Statistics - diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp index 88c28e2426..f6f77876b3 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "info/info_controller.h" #include "info/info_memento.h" +#include "info/statistics/info_statistics_public_forwards.h" #include "info/statistics/info_statistics_recent_message.h" #include "lang/lang_keys.h" #include "lottie/lottie_icon.h" @@ -596,6 +597,27 @@ Widget::Widget( 1 ) | rpl::start_with_next([=](const Data::StatisticalGraph &data) { applyStats({ .message = data }); + + { + const auto weak = base::make_weak(controller); + auto showPeerHistory = [=](FullMsgId fullId) { + if (const auto strong = weak.get()) { + controller->showPeerHistory( + fullId.peer, + Window::SectionShow::Way::Forward, + fullId.msg); + } + }; + AddPublicForwards( + inner, + std::move(showPeerHistory), + descriptor.peer, + contextId); + } + + + inner->resizeToWidth(width()); + }, inner->lifetime()); } }, lifetime);