From ec5e846374245bd5b59f4780b934b33d649f255a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 11 Oct 2023 02:40:10 +0300 Subject: [PATCH] Added initial ability to save and restore state of statistical info. --- Telegram/SourceFiles/data/data_statistics.h | 6 + .../info_statistics_inner_widget.cpp | 176 ++++++++++-------- .../statistics/info_statistics_inner_widget.h | 11 ++ .../statistics/info_statistics_widget.cpp | 28 +++ .../info/statistics/info_statistics_widget.h | 16 ++ 5 files changed, 163 insertions(+), 74 deletions(-) diff --git a/Telegram/SourceFiles/data/data_statistics.h b/Telegram/SourceFiles/data/data_statistics.h index 88a85e22c2..0ca8eb6487 100644 --- a/Telegram/SourceFiles/data/data_statistics.h +++ b/Telegram/SourceFiles/data/data_statistics.h @@ -113,4 +113,10 @@ struct MessageStatistics final { int views = 0; }; +struct AnyStatistics final { + Data::ChannelStatistics channel; + Data::SupergroupStatistics supergroup; + Data::MessageStatistics message; +}; + } // namespace Data diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp index dc5312019d..b338768303 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "info/statistics/info_statistics_inner_widget.h" +#include "info/statistics/info_statistics_widget.h" #include "api/api_statistics.h" #include "apiwrap.h" #include "data/data_peer.h" @@ -42,12 +43,6 @@ struct Descriptor final { not_null toastParent; }; -struct AnyStats final { - Data::ChannelStatistics channel; - Data::SupergroupStatistics supergroup; - Data::MessageStatistics message; -}; - void ProcessZoom( const Descriptor &d, not_null widget, @@ -112,7 +107,7 @@ void ProcessChart( void FillStatistic( not_null content, const Descriptor &descriptor, - const AnyStats &stats) { + const Data::AnyStatistics &stats) { using Type = Statistic::ChartViewType; const auto &padding = st::statisticsChartEntryPadding; const auto &m = st::statisticsLayerMargins; @@ -266,7 +261,7 @@ void FillLoading( void AddHeader( not_null content, tr::phrase<> text, - const AnyStats &stats) { + const Data::AnyStatistics &stats) { const auto startDate = stats.channel ? stats.channel.startDate : stats.supergroup.startDate; @@ -294,7 +289,7 @@ void AddHeader( void FillOverview( not_null content, - const AnyStats &stats) { + const Data::AnyStatistics &stats) { using Value = Data::StatisticalValue; const auto &channel = stats.channel; @@ -552,11 +547,14 @@ InnerWidget::InnerWidget( , _controller(controller) , _peer(peer) , _contextId(contextId) { +} + +void InnerWidget::load() { const auto inner = this; const auto descriptor = Descriptor{ - peer, - lifetime().make_state(&peer->session().api()), + _peer, + lifetime().make_state(&_peer->session().api()), _controller->uiShow()->toastParent(), }; @@ -573,84 +571,27 @@ InnerWidget::InnerWidget( _showFinished.events( ) | rpl::take(1) | rpl::start_with_next([=] { - if (!contextId) { + if (!_contextId) { descriptor.api->request( descriptor.peer ) | rpl::start_with_done([=] { - const auto anyStats = AnyStats{ + _loadedStats = Data::AnyStatistics{ descriptor.api->channelStats(), descriptor.api->supergroupStats(), }; + fill(); - FillOverview(inner, anyStats); - FillStatistic(inner, descriptor, anyStats); - const auto &channel = anyStats.channel; - const auto &supergroup = anyStats.supergroup; - if (channel) { - auto showMessage = [=](FullMsgId fullId) { - _showRequests.fire({ .messageStatistic = fullId }); - }; - FillRecentPosts(inner, descriptor, channel, showMessage); - } else if (supergroup) { - const auto showPeerInfo = [=](not_null peer) { - _showRequests.fire({ .info = peer->id }); - }; - const auto addSkip = [&]( - not_null c) { - ::Settings::AddSkip(c); - ::Settings::AddDivider(c); - ::Settings::AddSkip(c); - ::Settings::AddSkip(c); - }; - if (!supergroup.topSenders.empty()) { - AddMembersList( - { .topSenders = supergroup.topSenders }, - inner, - showPeerInfo, - descriptor.peer, - tr::lng_stats_members_title()); - } - if (!supergroup.topAdministrators.empty()) { - addSkip(inner); - AddMembersList( - { .topAdministrators - = supergroup.topAdministrators }, - inner, - showPeerInfo, - descriptor.peer, - tr::lng_stats_admins_title()); - } - if (!supergroup.topInviters.empty()) { - addSkip(inner); - AddMembersList( - { .topInviters = supergroup.topInviters }, - inner, - showPeerInfo, - descriptor.peer, - tr::lng_stats_inviters_title()); - } - } finishLoading(); }, lifetime()); } else { const auto lifetimeApi = lifetime().make_state(); const auto api = lifetimeApi->make_state( descriptor.peer->asChannel(), - contextId); + _contextId); api->request([=](const Data::MessageStatistics &data) { - const auto stats = AnyStats{ .message = data }; - FillOverview(inner, stats); - FillStatistic(inner, descriptor, stats); - auto showPeerHistory = [=](FullMsgId fullId) { - _showRequests.fire({ .history = fullId }); - }; - AddPublicForwards( - *api, - inner, - std::move(showPeerHistory), - descriptor.peer, - contextId); + _loadedStats = Data::AnyStatistics{ .message = data }; + fill(); finishLoading(); lifetimeApi->destroy(); @@ -659,6 +600,93 @@ InnerWidget::InnerWidget( }, lifetime()); } +void InnerWidget::fill() { + const auto inner = this; + const auto descriptor = Descriptor{ + _peer, + lifetime().make_state(&_peer->session().api()), + _controller->uiShow()->toastParent(), + }; + FillOverview(inner, _loadedStats); + FillStatistic(inner, descriptor, _loadedStats); + const auto &channel = _loadedStats.channel; + const auto &supergroup = _loadedStats.supergroup; + const auto &message = _loadedStats.message; + if (channel) { + auto showMessage = [=](FullMsgId fullId) { + _showRequests.fire({ .messageStatistic = fullId }); + }; + FillRecentPosts(inner, descriptor, channel, showMessage); + } else if (supergroup) { + const auto showPeerInfo = [=](not_null peer) { + _showRequests.fire({ .info = peer->id }); + }; + const auto addSkip = [&]( + not_null c) { + ::Settings::AddSkip(c); + ::Settings::AddDivider(c); + ::Settings::AddSkip(c); + ::Settings::AddSkip(c); + }; + if (!supergroup.topSenders.empty()) { + AddMembersList( + { .topSenders = supergroup.topSenders }, + inner, + showPeerInfo, + descriptor.peer, + tr::lng_stats_members_title()); + } + if (!supergroup.topAdministrators.empty()) { + addSkip(inner); + AddMembersList( + { .topAdministrators + = supergroup.topAdministrators }, + inner, + showPeerInfo, + descriptor.peer, + tr::lng_stats_admins_title()); + } + if (!supergroup.topInviters.empty()) { + addSkip(inner); + AddMembersList( + { .topInviters = supergroup.topInviters }, + inner, + showPeerInfo, + descriptor.peer, + tr::lng_stats_inviters_title()); + } + } else if (message) { + auto showPeerHistory = [=](FullMsgId fullId) { + _showRequests.fire({ .history = fullId }); + }; + const auto api = lifetime().make_state( + descriptor.peer->asChannel(), + _contextId); + AddPublicForwards( + *api, + inner, + std::move(showPeerHistory), + descriptor.peer, + _contextId); + } +} + +void InnerWidget::saveState(not_null memento) { + memento->setStates(base::take(_loadedStats)); +} + +void InnerWidget::restoreState(not_null memento) { + _loadedStats = memento->states(); + if (_loadedStats.channel + || _loadedStats.supergroup + || _loadedStats.message) { + fill(); + } else { + load(); + } + Ui::RpWidget::resizeToWidth(width()); +} + rpl::producer InnerWidget::scrollToRequests() const { return _scrollToRequests.events(); } diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.h b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.h index ad7d09a698..f384d70ebe 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.h +++ b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "base/object_ptr.h" +#include "data/data_statistics.h" #include "ui/widgets/scroll_area.h" #include "ui/wrap/vertical_layout.h" @@ -17,6 +18,8 @@ class Controller; namespace Info::Statistics { +class Memento; + class InnerWidget final : public Ui::VerticalLayout { public: struct ShowRequest final { @@ -39,11 +42,19 @@ public: void showFinished(); + void saveState(not_null memento); + void restoreState(not_null memento); + private: + void load(); + void fill(); + not_null _controller; not_null _peer; FullMsgId _contextId; + Data::AnyStatistics _loadedStats; + rpl::event_stream _scrollToRequests; rpl::event_stream _showRequests; rpl::event_stream<> _showFinished; diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp index 9ed88b555b..6d9004e242 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp @@ -31,11 +31,20 @@ Section Memento::section() const { return Section(Section::Type::Statistics); } +void Memento::setStates(Memento::States states) { + _states = std::move(states); +} + +Memento::States Memento::states() { + return base::take(_states); +} + object_ptr Memento::createWidget( QWidget *parent, not_null controller, const QRect &geometry) { auto result = object_ptr(parent, controller); + result->setInternalState(geometry, this); return result; } @@ -88,6 +97,14 @@ rpl::producer Widget::title() { : tr::lng_stats_title(); } +void Widget::setInternalState( + const QRect &geometry, + not_null memento) { + setGeometry(geometry); + Ui::SendPendingMoveResizeEvents(this); + restoreState(memento); +} + rpl::producer Widget::desiredShadowVisibility() const { return rpl::single(true); } @@ -98,9 +115,20 @@ void Widget::showFinished() { std::shared_ptr Widget::doCreateMemento() { auto result = std::make_shared(controller()); + saveState(result.get()); return result; } +void Widget::saveState(not_null memento) { + memento->setScrollTop(scrollTopSave()); + _inner->saveState(memento); +} + +void Widget::restoreState(not_null memento) { + _inner->restoreState(memento); + scrollTopRestore(memento->scrollTop()); +} + std::shared_ptr Make( not_null peer, FullMsgId contextId) { diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_widget.h b/Telegram/SourceFiles/info/statistics/info_statistics_widget.h index de521d11ad..06827f4615 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_widget.h +++ b/Telegram/SourceFiles/info/statistics/info_statistics_widget.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "info/info_content_widget.h" +#include "data/data_statistics.h" namespace Info::Statistics { @@ -26,6 +27,14 @@ public: Section section() const override; + using States = Data::AnyStatistics; + + void setStates(States states); + [[nodiscard]] States states(); + +private: + States _states; + }; class Widget final : public ContentWidget { @@ -40,7 +49,14 @@ public: [[nodiscard]] not_null peer() const; [[nodiscard]] FullMsgId contextId() const; + void setInternalState( + const QRect &geometry, + not_null memento); + private: + void saveState(not_null memento); + void restoreState(not_null memento); + std::shared_ptr doCreateMemento() override; const not_null _inner;