Replaced statistics box with info layer widget.

This commit is contained in:
23rd 2023-10-02 18:36:25 +03:00 committed by John Preston
parent 79442fde97
commit 77d23ad182
8 changed files with 196 additions and 74 deletions

View File

@ -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_widget.cpp
info/statistics/info_statistics_widget.h
info/stories/info_stories_inner_widget.cpp
info/stories/info_stories_inner_widget.h
info/stories/info_stories_provider.cpp
@ -1281,8 +1283,6 @@ PRIVATE
settings/settings_type.h
settings/settings_websites.cpp
settings/settings_websites.h
statistics/statistics_box.cpp
statistics/statistics_box.h
storage/details/storage_file_utilities.cpp
storage/details/storage_file_utilities.h
storage/details/storage_settings_scheme.cpp

View File

@ -106,6 +106,7 @@ public:
Downloads,
Stories,
PollResults,
Statistics,
};
using SettingsType = ::Settings::Type;
using MediaType = Storage::SharedMediaType;

View File

@ -5,10 +5,12 @@ 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 "statistics/statistics_box.h"
#include "info/statistics/info_statistics_widget.h"
#include "api/api_statistics.h"
#include "data/data_peer.h"
#include "info/info_controller.h"
#include "info/info_memento.h"
#include "lang/lang_keys.h"
#include "lottie/lottie_icon.h"
#include "main/main_session.h"
@ -19,11 +21,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/layers/generic_box.h"
#include "ui/rect.h"
#include "ui/toast/toast.h"
#include "ui/widgets/scroll_area.h"
#include "ui/wrap/slide_wrap.h"
#include "styles/style_boxes.h"
#include "styles/style_settings.h"
#include "styles/style_statistics.h"
namespace Info::Statistics {
namespace {
struct Descriptor final {
@ -99,36 +103,37 @@ void ProcessChart(
}
void FillStatistic(
not_null<Ui::GenericBox*> box,
not_null<Ui::VerticalLayout*> content,
const Descriptor &descriptor,
const AnyStats &stats) {
using Type = Statistic::ChartViewType;
const auto &padding = st::statisticsChartEntryPadding;
const auto &m = st::boxRowPadding;
const auto &m = st::statisticsLayerMargins;
const auto addSkip = [&](not_null<Ui::VerticalLayout*> c) {
Settings::AddSkip(c, padding.bottom());
Settings::AddDivider(c);
Settings::AddSkip(c, padding.top());
::Settings::AddSkip(c, padding.bottom());
::Settings::AddDivider(c);
::Settings::AddSkip(c, padding.top());
};
const auto addChart = [&](
const Data::StatisticalGraph &graphData,
rpl::producer<QString> &&title,
Statistic::ChartViewType type) {
const auto wrap = box->addRow(
const auto wrap = content->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
box,
object_ptr<Ui::VerticalLayout>(box)),
{});
content,
object_ptr<Ui::VerticalLayout>(content)));
ProcessChart(
descriptor,
wrap,
wrap->entity()->add(object_ptr<Statistic::ChartWidget>(box), m),
wrap->entity()->add(
object_ptr<Statistic::ChartWidget>(content),
m),
graphData,
std::move(title),
type);
addSkip(wrap->entity());
};
addSkip(box->verticalLayout());
addSkip(content);
if (const auto s = stats.channel) {
addChart(
s.memberCountGraph,
@ -203,24 +208,27 @@ void FillStatistic(
}
void FillLoading(
not_null<Ui::GenericBox*> box,
rpl::producer<bool> toggleOn) {
const auto emptyWrap = box->verticalLayout()->add(
not_null<Ui::VerticalLayout*> container,
rpl::producer<bool> toggleOn,
rpl::producer<> showFinished) {
const auto emptyWrap = container->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
box->verticalLayout(),
object_ptr<Ui::VerticalLayout>(box->verticalLayout())));
container,
object_ptr<Ui::VerticalLayout>(container)));
emptyWrap->toggleOn(std::move(toggleOn), anim::type::instant);
const auto content = emptyWrap->entity();
auto icon = Settings::CreateLottieIcon(
auto icon = ::Settings::CreateLottieIcon(
content,
{ .name = u"stats"_q, .sizeOverride = Size(st::changePhoneIconSize) },
st::settingsBlockedListIconPadding);
content->add(std::move(icon.widget));
box->setShowFinishedCallback([animate = std::move(icon.animate)] {
(
std::move(showFinished) | rpl::take(1)
) | rpl::start_with_next([animate = std::move(icon.animate)] {
animate(anim::repeat::loop);
});
}, icon.widget->lifetime());
content->add(std::move(icon.widget));
content->add(
object_ptr<Ui::CenterWrap<>>(
@ -240,10 +248,12 @@ void FillLoading(
st::statisticsLoadingSubtext)),
st::changePhoneDescriptionPadding + st::boxRowPadding);
Settings::AddSkip(content, st::settingsBlockedListIconPadding.top());
::Settings::AddSkip(content, st::settingsBlockedListIconPadding.top());
}
void FillOverview(not_null<Ui::GenericBox*> box, const AnyStats &stats) {
void FillOverview(
not_null<Ui::VerticalLayout*> content,
const AnyStats &stats) {
using Value = Data::StatisticalValue;
const auto &channel = stats.channel;
@ -251,9 +261,11 @@ void FillOverview(not_null<Ui::GenericBox*> box, const AnyStats &stats) {
const auto startDate = channel ? channel.startDate : supergroup.startDate;
const auto endDate = channel ? channel.endDate : supergroup.endDate;
Settings::AddSkip(box->verticalLayout());
::Settings::AddSkip(content);
{
const auto header = box->addRow(object_ptr<Statistic::Header>(box));
const auto header = content->add(
object_ptr<Statistic::Header>(content),
st::statisticsLayerMargins);
header->resize(header->width(), st::statisticsChartHeaderHeight);
header->setTitle(tr::lng_stats_overview_title(tr::now));
const auto formatter = u"MMM d"_q;
@ -265,7 +277,7 @@ void FillOverview(not_null<Ui::GenericBox*> box, const AnyStats &stats) {
+ ' '
+ QLocale().toString(to.date(), formatter));
}
Settings::AddSkip(box->verticalLayout());
::Settings::AddSkip(content);
struct Second final {
QColor color;
@ -286,7 +298,9 @@ void FillOverview(not_null<Ui::GenericBox*> box, const AnyStats &stats) {
};
};
const auto container = box->addRow(object_ptr<Ui::RpWidget>(box));
const auto container = content->add(
object_ptr<Ui::RpWidget>(content),
st::statisticsLayerMargins);
const auto addPrimary = [&](const Value &v) {
return Ui::CreateChild<Ui::FlatLabel>(
@ -397,33 +411,98 @@ void FillOverview(not_null<Ui::GenericBox*> box, const AnyStats &stats) {
} // namespace
void StatisticsBox(not_null<Ui::GenericBox*> box, not_null<PeerData*> peer) {
box->setTitle(tr::lng_stats_title());
const auto loaded = box->lifetime().make_state<rpl::event_stream<bool>>();
Memento::Memento(not_null<Controller*> controller)
: Memento(controller->peer()) {
}
Memento::Memento(not_null<PeerData*> peer)
: ContentMemento(peer, nullptr, {}) {
}
Memento::~Memento() = default;
Section Memento::section() const {
return Section(Section::Type::Statistics);
}
object_ptr<ContentWidget> Memento::createWidget(
QWidget *parent,
not_null<Controller*> controller,
const QRect &geometry) {
auto result = object_ptr<Widget>(parent, controller);
return result;
}
Widget::Widget(
QWidget *parent,
not_null<Controller*> controller)
: ContentWidget(parent, controller) {
const auto peer = controller->peer();
if (!peer) {
return;
}
const auto inner = setInnerWidget(object_ptr<Ui::VerticalLayout>(this));
auto &lifetime = inner->lifetime();
const auto loaded = lifetime.make_state<rpl::event_stream<bool>>();
FillLoading(
box,
loaded->events_starting_with(false) | rpl::map(!rpl::mappers::_1));
inner,
loaded->events_starting_with(false) | rpl::map(!rpl::mappers::_1),
_showFinished.events());
const auto descriptor = Descriptor{
peer,
box->lifetime().make_state<Api::Statistics>(&peer->session().api()),
box->uiShow()->toastParent(),
lifetime.make_state<Api::Statistics>(&peer->session().api()),
controller->uiShow()->toastParent(),
};
descriptor.api->request(
descriptor.peer
) | rpl::start_with_done([=] {
const auto anyStats = AnyStats{
descriptor.api->channelStats(),
descriptor.api->supergroupStats(),
};
if (!anyStats.channel && !anyStats.supergroup) {
return;
}
FillOverview(box, anyStats);
FillStatistic(box, descriptor, anyStats);
loaded->fire(true);
box->verticalLayout()->resizeToWidth(box->width());
box->showChildren();
}, box->lifetime());
_showFinished.events(
) | rpl::take(1) | rpl::start_with_next([=] {
descriptor.api->request(
descriptor.peer
) | rpl::start_with_done([=] {
const auto anyStats = AnyStats{
descriptor.api->channelStats(),
descriptor.api->supergroupStats(),
};
if (!anyStats.channel && !anyStats.supergroup) {
return;
}
FillOverview(inner, anyStats);
FillStatistic(inner, descriptor, anyStats);
loaded->fire(true);
inner->resizeToWidth(width());
inner->showChildren();
}, inner->lifetime());
}, lifetime);
}
bool Widget::showInternal(not_null<ContentMemento*> memento) {
return false;
}
rpl::producer<QString> Widget::title() {
return tr::lng_stats_title();
}
rpl::producer<bool> Widget::desiredShadowVisibility() const {
return rpl::single<bool>(true);
}
void Widget::showFinished() {
_showFinished.fire({});
}
std::shared_ptr<ContentMemento> Widget::doCreateMemento() {
auto result = std::make_shared<Memento>(controller());
return result;
}
std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer) {
return std::make_shared<Info::Memento>(
std::vector<std::shared_ptr<ContentMemento>>(
1,
std::make_shared<Memento>(peer)));
}
} // namespace Info::Statistics

View File

@ -0,0 +1,47 @@
/*
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
#include "info/info_content_widget.h"
namespace Info::Statistics {
class Memento final : public ContentMemento {
public:
Memento(not_null<Controller*> controller);
Memento(not_null<PeerData*> peer);
~Memento();
object_ptr<ContentWidget> createWidget(
QWidget *parent,
not_null<Controller*> controller,
const QRect &geometry) override;
Section section() const override;
};
class Widget final : public ContentWidget {
public:
Widget(QWidget *parent, not_null<Controller*> controller);
bool showInternal(not_null<ContentMemento*> memento) override;
rpl::producer<QString> title() override;
rpl::producer<bool> desiredShadowVisibility() const override;
void showFinished() override;
private:
std::shared_ptr<ContentMemento> doCreateMemento() override;
rpl::event_stream<> _showFinished;
};
[[nodiscard]] std::shared_ptr<Info::Memento> Make(not_null<PeerData*> peer);
} // namespace Info::Statistics

View File

@ -265,6 +265,7 @@ ChartWidget::Footer::Footer(not_null<Ui::RpWidget*> parent)
if (s.isNull()) {
return;
}
const auto was = xPercentageLimits();
const auto w = float64(st::statisticsChartFooterSideWidth);
_width = s.width() - w;
_widthBetweenSides = s.width() - w * 2.;
@ -272,6 +273,9 @@ ChartWidget::Footer::Footer(not_null<Ui::RpWidget*> parent)
s - QSize(0, st::statisticsChartLineWidth * 2),
st::boxRadius);
_frame = _mask;
if (_widthBetweenSides && was.max) {
setXPercentageLimits(was);
}
prepareCache(s.height());
}, lifetime());
@ -361,9 +365,11 @@ ChartWidget::Footer::Footer(not_null<Ui::RpWidget*> parent)
Limits ChartWidget::Footer::xPercentageLimits() const {
return {
.min = _leftSide.min / _widthBetweenSides,
.max = (_rightSide.min - st::statisticsChartFooterSideWidth)
/ _widthBetweenSides,
.min = _widthBetweenSides ? _leftSide.min / _widthBetweenSides : 0.,
.max = _widthBetweenSides
? (_rightSide.min - st::statisticsChartFooterSideWidth)
/ _widthBetweenSides
: 0.,
};
}

View File

@ -10,6 +10,8 @@ using "ui/basic.style";
using "window/window.style";
using "ui/widgets/widgets.style";
statisticsLayerMargins: margins(20px, 0px, 20px, 0px);
statisticsChartHeight: 150px;
statisticsChartEntryPadding: margins(0px, 8px, 0px, 8px);

View File

@ -1,16 +0,0 @@
/*
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 GenericBox;
} // namespace Ui
void StatisticsBox(not_null<Ui::GenericBox*> box, not_null<PeerData*> peer);

View File

@ -66,6 +66,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/info_memento.h"
#include "info/info_controller.h"
#include "info/profile/info_profile_values.h"
#include "info/statistics/info_statistics_widget.h"
#include "info/stories/info_stories_widget.h"
#include "data/notify/data_notify_settings.h"
#include "data/data_changes.h"
@ -85,7 +86,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/application.h"
#include "export/export_manager.h"
#include "boxes/peers/edit_peer_info_box.h"
#include "statistics/statistics_box.h"
#include "styles/style_chat.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
@ -1003,10 +1003,13 @@ void Filler::addViewStatistics() {
#ifdef _DEBUG
if (const auto channel = _peer->asChannel()) {
if (channel->flags() & ChannelDataFlag::CanGetStatistics) {
const auto navigation = _controller;
const auto controller = _controller;
const auto weak = base::make_weak(_thread);
const auto peer = _peer;
_addAction(tr::lng_stats_title(tr::now), [=] {
navigation->show(Box(StatisticsBox, peer));
if (const auto strong = weak.get()) {
controller->showSection(Info::Statistics::Make(peer));
}
}, nullptr);
}
}