diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 93b2b0043..7053293e9 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4079,6 +4079,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "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_views" = "Views"; "lng_stats_overview_message_public_share#one" = "{count} public share"; "lng_stats_overview_message_public_share#other" = "{count} public shares"; diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.cpp index 76b267fa8..c43bd1c4c 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.cpp @@ -15,7 +15,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #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" @@ -151,13 +150,13 @@ rpl::producer PublicForwardsController::totalCountChanges() const { } // namespace -void AddPublicForwards( +PublicShares AddPublicForwards( not_null container, Fn showPeerHistory, not_null peer, FullMsgId contextId) { if (!peer->isChannel()) { - return; + return rpl::never(); } struct State final { @@ -174,18 +173,9 @@ void AddPublicForwards( 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, @@ -197,13 +187,16 @@ void AddPublicForwards( { const auto &subtitlePadding = st::settingsButton.padding; ::Settings::AddSubsectionTitle( - wrap->entity(), + container, std::move(title), { 0, -subtitlePadding.top(), 0, -subtitlePadding.bottom() }); } - state->delegate.setContent(wrap->entity()->add( - object_ptr(wrap->entity(), &state->controller))); + state->delegate.setContent(container->add( + object_ptr(container, &state->controller))); state->controller.setDelegate(&state->delegate); + + return state->controller.totalCountChanges( + ) | rpl::distinct_until_changed(); } } // 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 index 43cb3c7a8..89b83bba7 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.h +++ b/Telegram/SourceFiles/info/statistics/info_statistics_public_forwards.h @@ -15,7 +15,9 @@ class VerticalLayout; namespace Info::Statistics { -void AddPublicForwards( +using PublicShares = rpl::producer; + +[[nodiscard]] PublicShares AddPublicForwards( not_null container, Fn showPeerHistory, not_null peer, diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp index f6f77876b..1966d9fb2 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp @@ -45,7 +45,15 @@ struct Descriptor final { struct AnyStats final { Data::ChannelStatistics channel; Data::SupergroupStatistics supergroup; - Data::StatisticalGraph message; + struct Message { + explicit operator bool() const { + return !graph.chart.empty(); + } + Data::StatisticalGraph graph; + int publicForwards = 0; + int privateForwards = 0; + int views = 0; + } message; }; void ProcessZoom( @@ -211,9 +219,9 @@ void FillStatistic( // s.weekGraph, // tr::lng_chart_title_group_week(), // Type::StackLinear); - } else if (const auto graph = stats.message; graph.chart) { + } else if (const auto message = stats.message) { addChart( - graph, + message.graph, tr::lng_chart_title_message_interaction(), Type::DoubleLinear); } @@ -278,6 +286,10 @@ void AddHeader( st::statisticsLayerMargins + st::statisticsChartHeaderPadding); header->resizeToWidth(header->width()); header->setTitle(text(tr::now)); + if (!endDate || !startDate) { + header->setSubTitle({}); + return; + } const auto formatter = u"d MMM yyyy"_q; const auto from = QDateTime::fromSecsSinceEpoch(startDate); const auto to = QDateTime::fromSecsSinceEpoch(endDate); @@ -335,7 +347,9 @@ void FillOverview( const auto addPrimary = [&](const Value &v) { return Ui::CreateChild( container, - Lang::FormatCountToShort(v.value).string, + (v.value >= 0) + ? Lang::FormatCountToShort(v.value).string + : QString(), st::statisticsOverviewValue); }; const auto addSub = [&]( @@ -352,6 +366,7 @@ void FillOverview( container, text(), st::statisticsOverviewSubtext); + sub->setTextColorOverride(st::windowSubTextFg->c); primary->geometryValue( ) | rpl::start_with_next([=](const QRect &g) { @@ -369,8 +384,11 @@ void FillOverview( }; const auto isChannel = (!!channel); + const auto isMessage = (!!stats.message); const auto topLeftLabel = isChannel ? addPrimary(channel.memberCount) + : isMessage + ? addPrimary({ .value = float64(stats.message.views) }) : addPrimary(supergroup.memberCount); const auto topRightLabel = isChannel ? Ui::CreateChild( @@ -378,12 +396,18 @@ void FillOverview( QString("%1%").arg(0.01 * std::round(channel.enabledNotificationsPercentage * 100.)), st::statisticsOverviewValue) + : isMessage + ? addPrimary({ .value = float64(stats.message.publicForwards) }) : addPrimary(supergroup.messageCount); const auto bottomLeftLabel = isChannel ? addPrimary(channel.meanViewCount) + : isMessage + ? addPrimary({ .value = float64(stats.message.privateForwards) }) : addPrimary(supergroup.viewerCount); const auto bottomRightLabel = isChannel ? addPrimary(channel.meanShareCount) + : isMessage + ? addPrimary({ .value = -1. }) : addPrimary(supergroup.senderCount); if (const auto &s = channel) { addSub( @@ -419,6 +443,25 @@ void FillOverview( bottomRightLabel, s.senderCount, tr::lng_stats_overview_group_mean_post_count); + } else if (const auto &s = stats.message) { + if (s.views >= 0) { + addSub( + topLeftLabel, + {}, + tr::lng_stats_overview_message_views); + } + if (s.publicForwards >= 0) { + addSub( + topRightLabel, + {}, + tr::lng_stats_overview_message_public_shares); + } + if (s.privateForwards >= 0) { + addSub( + bottomLeftLabel, + {}, + tr::lng_stats_overview_message_private_shares); + } } container->showChildren(); container->resize(container->width(), topLeftLabel->height() * 5); @@ -555,24 +598,7 @@ Widget::Widget( loaded->events_starting_with(false) | rpl::map(!rpl::mappers::_1), _showFinished.events()); - const auto applyStats = [=](const AnyStats &anyStats) { - const auto isMessage = !anyStats.message.chart.empty(); - if (!anyStats.channel && !anyStats.supergroup && !isMessage) { - return; - } - if (!isMessage) { - FillOverview(inner, anyStats); - FillStatistic(inner, descriptor, anyStats); - if (const auto channel = anyStats.channel) { - const auto showSection = [controller]( - std::shared_ptr memento) { - controller->showSection(std::move(memento)); - }; - FillRecentPosts(inner, descriptor, channel, showSection); - } - } else { - FillStatistic(inner, descriptor, anyStats); - } + const auto finishLoading = [=] { loaded->fire(true); inner->resizeToWidth(width()); inner->showChildren(); @@ -584,22 +610,55 @@ Widget::Widget( descriptor.api->request( descriptor.peer ) | rpl::start_with_done([=] { - applyStats({ + const auto anyStats = AnyStats{ descriptor.api->channelStats(), descriptor.api->supergroupStats(), - }); + }; + + FillOverview(inner, anyStats); + FillStatistic(inner, descriptor, anyStats); + if (const auto channel = anyStats.channel) { + const auto showSection = [controller]( + std::shared_ptr memento) { + controller->showSection(std::move(memento)); + }; + FillRecentPosts(inner, descriptor, channel, showSection); + } + finishLoading(); }, inner->lifetime()); } else { + const auto weak = base::make_weak(controller); + descriptor.api->requestMessage( descriptor.peer, contextId.msg ) | rpl::take( 1 ) | rpl::start_with_next([=](const Data::StatisticalGraph &data) { - applyStats({ .message = data }); + descriptor.api->request( + descriptor.peer + ) | rpl::start_with_done([=] { + const auto channel = descriptor.api->channelStats(); + auto info = Data::StatisticsMessageInteractionInfo(); + for (const auto &r : channel.recentMessageInteractions) { + if (r.messageId == contextId.msg) { + info = r; + break; + } + } + + const auto wrapAbove = inner->add( + object_ptr>( + inner, + object_ptr(inner))); + wrapAbove->toggle(false, anim::type::instant); + + const auto wrapBelow = inner->add( + object_ptr>( + inner, + object_ptr(inner))); + wrapBelow->toggle(false, anim::type::instant); - { - const auto weak = base::make_weak(controller); auto showPeerHistory = [=](FullMsgId fullId) { if (const auto strong = weak.get()) { controller->showPeerHistory( @@ -608,16 +667,32 @@ Widget::Widget( fullId.msg); } }; - AddPublicForwards( - inner, + auto sharesCount = AddPublicForwards( + wrapBelow->entity(), std::move(showPeerHistory), descriptor.peer, contextId); - } + std::move(sharesCount) | rpl::take( + 1 + ) | rpl::start_with_next([=](int count) { + const auto stats = AnyStats{ + .message = { + .graph = data, + .publicForwards = count, + .privateForwards = info.forwardsCount - count, + .views = info.viewsCount, + } + }; + FillOverview(wrapAbove->entity(), stats); + FillStatistic(wrapAbove->entity(), descriptor, stats); - inner->resizeToWidth(width()); + wrapAbove->toggle(true, anim::type::instant); + wrapBelow->toggle(true, anim::type::instant); + finishLoading(); + }, inner->lifetime()); + }, inner->lifetime()); }, inner->lifetime()); } }, lifetime);