From f61c22b0650fe9a4a457e4aea1f8c4f97fb25c65 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Mon, 16 Oct 2023 22:26:36 +0300 Subject: [PATCH] Added initial boosts list to boost info. --- .../info/boosts/info_boosts_inner_widget.cpp | 30 +++ .../info_statistics_list_controllers.cpp | 177 +++++++++++++++++- .../info_statistics_list_controllers.h | 8 + .../SourceFiles/statistics/statistics.style | 11 ++ 4 files changed, 222 insertions(+), 4 deletions(-) diff --git a/Telegram/SourceFiles/info/boosts/info_boosts_inner_widget.cpp b/Telegram/SourceFiles/info/boosts/info_boosts_inner_widget.cpp index ee55bac73..08890809e 100644 --- a/Telegram/SourceFiles/info/boosts/info_boosts_inner_widget.cpp +++ b/Telegram/SourceFiles/info/boosts/info_boosts_inner_widget.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_statistics.h" #include "boxes/peers/edit_peer_invite_link.h" #include "info/info_controller.h" +#include "info/statistics/info_statistics_list_controllers.h" #include "lang/lang_keys.h" #include "settings/settings_common.h" #include "statistics/widgets/chart_header_widget.h" @@ -211,6 +212,35 @@ InnerWidget::InnerWidget( FillOverview(inner, status); + ::Settings::AddSkip(inner); + ::Settings::AddDivider(inner); + ::Settings::AddSkip(inner); + + if (status.firstSlice.total > 0) { + ::Settings::AddSkip(inner); + using PeerPtr = not_null; + const auto header = inner->add( + object_ptr(inner), + st::statisticsLayerMargins); + header->resizeToWidth(header->width()); + header->setTitle(tr::lng_boosts_list_title( + tr::now, + lt_count, + status.firstSlice.total)); + header->setSubTitle({}); + Statistics::AddBoostsList( + status.firstSlice, + inner, + [=](PeerPtr p) { controller->showPeerInfo(p); }, + peer, + tr::lng_boosts_title()); + ::Settings::AddSkip(inner); + ::Settings::AddDividerText( + inner, + tr::lng_boosts_list_subtext()); + ::Settings::AddSkip(inner); + } + ::Settings::AddSkip(inner); AddHeader(inner, tr::lng_boosts_link_title); FillShareLink(inner, _show, status.link, peer); diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp index d6d0fe968..af07515ac 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_statistics.h" #include "boxes/peer_list_controllers.h" +#include "data/data_boosts.h" #include "data/data_channel.h" #include "data/data_session.h" #include "data/data_user.h" @@ -16,14 +17,40 @@ 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/effects/toggle_arrow.h" +#include "ui/painter.h" +#include "ui/rect.h" #include "ui/widgets/buttons.h" #include "ui/wrap/slide_wrap.h" #include "ui/wrap/vertical_layout.h" #include "styles/style_settings.h" +#include "styles/style_statistics.h" +#include "styles/style_window.h" namespace Info::Statistics { namespace { +void AddArrow(not_null parent) { + const auto arrow = Ui::CreateChild(parent.get()); + arrow->paintRequest( + ) | rpl::start_with_next([=](const QRect &r) { + auto p = QPainter(arrow); + + const auto path = Ui::ToggleUpDownArrowPath( + st::statisticsShowMoreButtonArrowSize, + st::statisticsShowMoreButtonArrowSize, + st::statisticsShowMoreButtonArrowSize, + st::mainMenuToggleFourStrokes, + 0.); + + auto hq = PainterHighQualityEnabler(p); + p.fillPath(path, st::lightButtonFg); + }, arrow->lifetime()); + arrow->resize(Size(st::statisticsShowMoreButtonArrowSize * 2)); + arrow->move(st::statisticsShowMoreButtonArrowPosition); + arrow->show(); +} + void AddSubsectionTitle( not_null container, rpl::producer title) { @@ -71,6 +98,12 @@ struct MembersDescriptor final { Data::SupergroupStatistics data; }; +struct BoostsDescriptor final { + Data::BoostsListSlice firstSlice; + Fn)> showPeerInfo; + not_null peer; +}; + class PeerListRowWithMsgId : public PeerListRow { public: using PeerListRow::PeerListRow; @@ -198,7 +231,7 @@ public: void loadMoreRows() override; private: - bool appendRow(not_null peer, MsgId msgId); + void appendRow(not_null peer, MsgId msgId); void applySlice(const Data::PublicForwardsSlice &slice); const not_null _session; @@ -257,11 +290,11 @@ void PublicForwardsController::rowClicked(not_null row) { }); } -bool PublicForwardsController::appendRow( +void PublicForwardsController::appendRow( not_null peer, MsgId msgId) { if (delegate()->peerListFindRow(peer->id.value)) { - return false; + return; } auto row = std::make_unique(peer); @@ -285,7 +318,94 @@ bool PublicForwardsController::appendRow( row->setCustomStatus(resultText); delegate()->peerListAppendRow(std::move(row)); - return true; + return; +} + +class BoostsController final : public PeerListController { +public: + explicit BoostsController(BoostsDescriptor d); + + Main::Session &session() const override; + void prepare() override; + void rowClicked(not_null row) override; + void loadMoreRows() override; + + [[nodiscard]] bool skipRequest() const; + void setLimit(int limit); + +private: + void applySlice(const Data::BoostsListSlice &slice); + + const not_null _session; + Fn)> _showPeerInfo; + + Api::Boosts _api; + Data::BoostsListSlice _firstSlice; + Data::BoostsListSlice::OffsetToken _apiToken; + + int _limit = 0; + + bool _allLoaded = false; + bool _requesting = false; + +}; + +BoostsController::BoostsController(BoostsDescriptor d) +: _session(&d.peer->session()) +, _showPeerInfo(std::move(d.showPeerInfo)) +, _api(d.peer) +, _firstSlice(std::move(d.firstSlice)) { +} + +Main::Session &BoostsController::session() const { + return *_session; +} + +bool BoostsController::skipRequest() const { + return _requesting || _allLoaded; +} + +void BoostsController::setLimit(int limit) { + _limit = limit; + _requesting = true; + _api.requestBoosts(_apiToken, [=](const Data::BoostsListSlice &slice) { + _requesting = false; + applySlice(slice); + }); +} + +void BoostsController::prepare() { + applySlice(base::take(_firstSlice)); + delegate()->peerListRefreshRows(); +} + +void BoostsController::loadMoreRows() { +} + +void BoostsController::applySlice(const Data::BoostsListSlice &slice) { + _allLoaded = slice.allLoaded; + _apiToken = slice.token; + + const auto formatter = u"MMM d, yyyy"_q; + for (const auto &item : slice.list) { + const auto user = session().data().user(item.userId); + if (delegate()->peerListFindRow(user->id.value)) { + continue; + } + auto row = std::make_unique(user); + row->setCustomStatus(tr::lng_boosts_list_status( + tr::now, + lt_date, + QLocale().toString(item.expirationDate, formatter))); + delegate()->peerListAppendRow(std::move(row)); + } + delegate()->peerListRefreshRows(); +} + +void BoostsController::rowClicked(not_null row) { + crl::on_main([=, peer = row->peer()] { + _showPeerInfo(peer); + }); } } // namespace @@ -388,4 +508,53 @@ void AddMembersList( showMore(); } +void AddBoostsList( + const Data::BoostsListSlice &firstSlice, + not_null container, + Fn)> showPeerInfo, + not_null peer, + rpl::producer title) { + const auto max = firstSlice.total; + struct State final { + State(BoostsDescriptor d) : controller(std::move(d)) { + } + PeerListContentDelegateSimple delegate; + BoostsController controller; + int limit = Api::Boosts::kFirstSlice; + }; + auto d = BoostsDescriptor{ firstSlice, std::move(showPeerInfo), peer }; + const auto state = container->lifetime().make_state(std::move(d)); + + state->delegate.setContent(container->add( + object_ptr(container, &state->controller))); + state->controller.setDelegate(&state->delegate); + + const auto wrap = container->add( + object_ptr>( + container, + object_ptr( + container, + tr::lng_boosts_show_more(), + st::statisticsShowMoreButton)), + { 0, -st::settingsButton.padding.top(), 0, 0 }); + const auto button = wrap->entity(); + AddArrow(button); + + const auto showMore = [=] { + if (state->controller.skipRequest()) { + return; + } + state->limit = std::min(int(max), state->limit + Api::Boosts::kLimit); + state->controller.setLimit(state->limit); + if (state->limit == max) { + wrap->toggle(false, anim::type::instant); + } + container->resizeToWidth(container->width()); + }; + button->setClickedCallback(showMore); + if (state->limit == max) { + wrap->toggle(false, anim::type::instant); + } +} + } // namespace Info::Statistics diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.h b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.h index 8520acc4d..dc619362d 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.h +++ b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.h @@ -14,6 +14,7 @@ class VerticalLayout; } // namespace Ui namespace Data { +struct BoostsListSlice; struct PublicForwardsSlice; struct SupergroupStatistics; } // namespace Data @@ -34,4 +35,11 @@ void AddMembersList( not_null peer, rpl::producer title); +void AddBoostsList( + const Data::BoostsListSlice &firstSlice, + not_null container, + Fn)> showPeerInfo, + not_null peer, + rpl::producer title); + } // namespace Info::Statistics diff --git a/Telegram/SourceFiles/statistics/statistics.style b/Telegram/SourceFiles/statistics/statistics.style index 0c2de07af..46078fbca 100644 --- a/Telegram/SourceFiles/statistics/statistics.style +++ b/Telegram/SourceFiles/statistics/statistics.style @@ -104,6 +104,17 @@ statisticsRecentPostButton: SettingsButton(defaultSettingsButton) { height: 56px; padding: margins(7px, 0px, 24px, 0px); } + +statisticsShowMoreButton: SettingsButton(defaultSettingsButton) { + textFg: lightButtonFg; + textFgOver: lightButtonFgOver; + + padding: margins(73px, 10px, 22px, 8px); +} + +statisticsShowMoreButtonArrowPosition: point(29px, 13px); +statisticsShowMoreButtonArrowSize: 7px; + boostsButton: SettingsButton(defaultSettingsButton) { textFg: lightButtonFg; textFgOver: lightButtonFgOver;