diff --git a/Telegram/SourceFiles/statistics/chart_widget.cpp b/Telegram/SourceFiles/statistics/chart_widget.cpp index 98924f8a9..e2b4a3d6c 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.cpp +++ b/Telegram/SourceFiles/statistics/chart_widget.cpp @@ -871,14 +871,17 @@ int ChartWidget::resizeGetHeight(int newWidth) { _filterButtons->fillButtons(texts, colors, ids, newWidth); } + const auto filtersTopSkip = st::statisticsFilterButtonsPadding.top(); const auto filtersHeight = _filterButtons - ? _filterButtons->height() + ? (_filterButtons->height() + + st::statisticsFilterButtonsPadding.bottom()) : 0; - const auto resultHeight = st::statisticsChartHeight + const auto resultHeight = st::statisticsChartHeaderHeight + + st::statisticsChartHeight + st::statisticsChartFooterHeight + st::statisticsChartFooterSkip - + filtersHeight - + st::statisticsChartHeaderHeight; + + filtersTopSkip + + filtersHeight; { _header->setGeometry( 0, @@ -887,7 +890,10 @@ int ChartWidget::resizeGetHeight(int newWidth) { st::statisticsChartHeaderHeight); _footer->setGeometry( 0, - resultHeight - st::statisticsChartFooterHeight - filtersHeight, + resultHeight + - st::statisticsChartFooterHeight + - filtersTopSkip + - filtersHeight, newWidth, st::statisticsChartFooterHeight); if (_filterButtons) { @@ -899,6 +905,7 @@ int ChartWidget::resizeGetHeight(int newWidth) { newWidth, resultHeight - st::statisticsChartFooterHeight + - filtersTopSkip - filtersHeight - st::statisticsChartFooterSkip); @@ -1403,6 +1410,16 @@ void ChartWidget::setupFilterButtons() { void ChartWidget::setChartData( Data::StatisticalChart chartData, ChartViewType type) { + if (width() < st::statisticsChartHeight) { + sizeValue( + ) | rpl::start_with_next([=](const QSize &s) { + if (s.width() > st::statisticsChartHeight) { + setChartData(chartData, type); + _waitingSizeLifetime.destroy(); + } + }, _waitingSizeLifetime); + return; + } _chartData = std::move(chartData); FillLineColorsByKey(_chartData); diff --git a/Telegram/SourceFiles/statistics/chart_widget.h b/Telegram/SourceFiles/statistics/chart_widget.h index abca0949e..2a6aa0f0b 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.h +++ b/Telegram/SourceFiles/statistics/chart_widget.h @@ -175,6 +175,8 @@ private: bool _zoomEnabled = false; rpl::event_stream _zoomRequests; + rpl::lifetime _waitingSizeLifetime; + }; } // namespace Statistic diff --git a/Telegram/SourceFiles/statistics/statistics.style b/Telegram/SourceFiles/statistics/statistics.style index 5d21c2b27..cfe98b22e 100644 --- a/Telegram/SourceFiles/statistics/statistics.style +++ b/Telegram/SourceFiles/statistics/statistics.style @@ -12,6 +12,8 @@ using "ui/widgets/widgets.style"; statisticsChartHeight: 150px; +statisticsChartEntryPadding: margins(0px, 8px, 0px, 8px); + statisticsDetailsArrowShift: 2px; statisticsDetailsArrowStroke: 1.5; statisticsDetailsPopupMargins: margins(8px, 8px, 8px, 8px); @@ -37,6 +39,8 @@ statisticsChartFooterHeight: 52px; statisticsChartFlatCheckboxMargins: margins(4px, 4px, 4px, 4px); statisticsChartFlatCheckboxCheckWidth: 4px; +statisticsFilterButtonsPadding: margins(0px, 6px, 0px, 0px); + statisticsDetailsPopupHeaderStyle: TextStyle(defaultTextStyle) { font: font(9px semibold); } diff --git a/Telegram/SourceFiles/statistics/statistics_box.cpp b/Telegram/SourceFiles/statistics/statistics_box.cpp index 0efa57f81..bf7ec1a95 100644 --- a/Telegram/SourceFiles/statistics/statistics_box.cpp +++ b/Telegram/SourceFiles/statistics/statistics_box.cpp @@ -25,6 +25,149 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { +struct Descriptor final { + not_null peer; + not_null api; + not_null toastParent; +}; + +void ProcessZoom( + const Descriptor &d, + not_null widget, + const QString &zoomToken, + Statistic::ChartViewType type) { + if (zoomToken.isEmpty()) { + return; + } + widget->zoomRequests( + ) | rpl::start_with_next([=](float64 x) { + d.api->requestZoom( + d.peer, + zoomToken, + x + ) | rpl::start_with_next_error_done([=]( + const Data::StatisticalGraph &graph) { + if (graph.chart) { + widget->setZoomedChartData(graph.chart, x, type); + } else if (!graph.error.isEmpty()) { + Ui::Toast::Show(d.toastParent, graph.error); + } + }, [=](const QString &error) { + }, [=] { + }, widget->lifetime()); + }, widget->lifetime()); +} + +void ProcessChart( + const Descriptor &d, + not_null widget, + const Data::StatisticalGraph &graphData, + rpl::producer &&title, + Statistic::ChartViewType type) { + if (graphData.chart) { + widget->setChartData(graphData.chart, type); + ProcessZoom(d, widget, graphData.zoomToken, type); + widget->setTitle(std::move(title)); + } else if (!graphData.zoomToken.isEmpty()) { + d.api->requestZoom( + d.peer, + graphData.zoomToken, + 0 + ) | rpl::start_with_next_error_done([=]( + const Data::StatisticalGraph &graph) { + if (graph.chart) { + widget->setChartData(graph.chart, type); + ProcessZoom(d, widget, graph.zoomToken, type); + widget->setTitle(rpl::duplicate(title)); + } else if (!graph.error.isEmpty()) { + Ui::Toast::Show(d.toastParent, graph.error); + } + }, [=](const QString &error) { + }, [=] { + }, widget->lifetime()); + } +} + +void FillChannelStatistic( + not_null box, + const Descriptor &descriptor, + const Data::ChannelStatistics &stats) { + using Type = Statistic::ChartViewType; + const auto &padding = st::statisticsChartEntryPadding; + const auto addSkip = [&] { + Settings::AddSkip(box->verticalLayout(), padding.bottom()); + Settings::AddDivider(box->verticalLayout()); + Settings::AddSkip(box->verticalLayout(), padding.top()); + }; + Settings::AddSkip(box->verticalLayout(), padding.top()); + ProcessChart( + descriptor, + box->addRow(object_ptr(box)), + stats.memberCountGraph, + tr::lng_chart_title_member_count(), + Type::Linear); + addSkip(); + ProcessChart( + descriptor, + box->addRow(object_ptr(box)), + stats.joinGraph, + tr::lng_chart_title_join(), + Type::Linear); + addSkip(); + ProcessChart( + descriptor, + box->addRow(object_ptr(box)), + stats.muteGraph, + tr::lng_chart_title_mute(), + Type::Linear); + addSkip(); + ProcessChart( + descriptor, + box->addRow(object_ptr(box)), + stats.viewCountByHourGraph, + tr::lng_chart_title_view_count_by_hour(), + Type::Linear); + addSkip(); + ProcessChart( + descriptor, + box->addRow(object_ptr(box)), + stats.viewCountBySourceGraph, + tr::lng_chart_title_view_count_by_source(), + Type::Stack); + addSkip(); + ProcessChart( + descriptor, + box->addRow(object_ptr(box)), + stats.joinBySourceGraph, + tr::lng_chart_title_join_by_source(), + Type::Stack); + addSkip(); + ProcessChart( + descriptor, + box->addRow(object_ptr(box)), + stats.languageGraph, + tr::lng_chart_title_language(), + Type::StackLinear); + addSkip(); + ProcessChart( + descriptor, + box->addRow(object_ptr(box)), + stats.messageInteractionGraph, + tr::lng_chart_title_message_interaction(), + Type::DoubleLinear); + addSkip(); + ProcessChart( + descriptor, + box->addRow(object_ptr(box)), + stats.instantViewInteractionGraph, + tr::lng_chart_title_instant_view_interaction(), + Type::DoubleLinear); + addSkip(); + + box->verticalLayout()->resizeToWidth(box->width()); + box->showChildren(); +} + void FillLoading( not_null box, rpl::producer toggleOn) { @@ -69,117 +212,26 @@ void FillLoading( } // namespace void StatisticsBox(not_null box, not_null peer) { - + box->setTitle(tr::lng_stats_title()); const auto loaded = box->lifetime().make_state>(); FillLoading( box, loaded->events_starting_with(false) | rpl::map(!rpl::mappers::_1)); - const auto chartWidget = box->addRow( - object_ptr(box)); - const auto chartWidget2 = box->addRow( - object_ptr(box)); - const auto chartWidget3 = box->addRow( - object_ptr(box)); - const auto chartWidget4 = box->addRow( - object_ptr(box)); - const auto chartWidget5 = box->addRow( - object_ptr(box)); - const auto api = chartWidget->lifetime().make_state( - &peer->session().api()); - - const auto processZoom = [=]( - not_null widget, - const QString &zoomToken, - Statistic::ChartViewType type) { - if (!zoomToken.isEmpty()) { - widget->zoomRequests( - ) | rpl::start_with_next([=](float64 x) { - api->requestZoom( - peer, - zoomToken, - x - ) | rpl::start_with_next_error_done([=]( - const Data::StatisticalGraph &graph) { - if (graph.chart) { - widget->setZoomedChartData(graph.chart, x, type); - } else if (!graph.error.isEmpty()) { - Ui::Toast::Show( - box->uiShow()->toastParent(), - graph.error); - } - }, [=](const QString &error) { - }, [=] { - }, widget->lifetime()); - }, widget->lifetime()); - } + const auto descriptor = Descriptor{ + peer, + box->lifetime().make_state(&peer->session().api()), + box->uiShow()->toastParent(), }; - const auto processChart = [=]( - not_null widget, - const Data::StatisticalGraph &graphData, - rpl::producer &&title, - Statistic::ChartViewType type) { - if (graphData.chart) { - widget->setChartData(graphData.chart, type); - processZoom(widget, graphData.zoomToken, type); - widget->setTitle(std::move(title)); - } else if (!graphData.zoomToken.isEmpty()) { - api->requestZoom( - peer, - graphData.zoomToken, - 0 - ) | rpl::start_with_next_error_done([=]( - const Data::StatisticalGraph &graph) { - if (graph.chart) { - widget->setChartData(graph.chart, type); - processZoom(widget, graph.zoomToken, type); - widget->setTitle(rpl::duplicate(title)); - } else if (!graph.error.isEmpty()) { - Ui::Toast::Show( - box->uiShow()->toastParent(), - graph.error); - } - }, [=](const QString &error) { - }, [=] { - }, widget->lifetime()); - } - }; - - api->request( - peer + descriptor.api->request( + descriptor.peer ) | rpl::start_with_done([=] { - const auto stats = api->channelStats(); + const auto stats = descriptor.api->channelStats(); if (!stats) { return; } + FillChannelStatistic(box, descriptor, stats); loaded->fire(true); - using Type = Statistic::ChartViewType; - processChart( - chartWidget, - stats.memberCountGraph, - tr::lng_chart_title_member_count(), - Type::Linear); - processChart( - chartWidget2, - stats.joinGraph, - tr::lng_chart_title_join(), - Type::Linear); - processChart( - chartWidget3, - stats.muteGraph, - tr::lng_chart_title_mute(), - Type::Linear); - processChart( - chartWidget4, - stats.viewCountBySourceGraph, - tr::lng_chart_title_view_count_by_source(), - Type::Stack); - processChart( - chartWidget5, - stats.joinBySourceGraph, - tr::lng_chart_title_join_by_source(), - Type::Stack); - }, chartWidget->lifetime()); - box->setTitle(tr::lng_stats_title()); + }, box->lifetime()); }