From 98c6a3ff79eaa198837674397653e7d84dfa0b1e Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 6 Dec 2023 21:27:33 +0300 Subject: [PATCH] Added support of stories in list of public forwards in statistics info. --- Telegram/SourceFiles/api/api_statistics.cpp | 23 ++-- .../info_statistics_inner_widget.cpp | 7 +- .../statistics/info_statistics_inner_widget.h | 1 + .../info_statistics_list_controllers.cpp | 115 +++++++++++++----- .../info_statistics_list_controllers.h | 2 +- .../statistics/info_statistics_widget.cpp | 12 +- 6 files changed, 115 insertions(+), 45 deletions(-) diff --git a/Telegram/SourceFiles/api/api_statistics.cpp b/Telegram/SourceFiles/api/api_statistics.cpp index 6655c618e..e889c3cdb 100644 --- a/Telegram/SourceFiles/api/api_statistics.cpp +++ b/Telegram/SourceFiles/api/api_statistics.cpp @@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "data/data_channel.h" #include "data/data_session.h" +#include "data/data_stories.h" +#include "data/data_story.h" #include "history/history.h" #include "main/main_session.h" #include "statistics/statistics_data_deserialize.h" @@ -475,9 +477,10 @@ void PublicForwards::requestStory( _requestId = 0; const auto &data = tlForwards.data(); + auto &owner = channel->owner(); - channel->owner().processUsers(data.vusers()); - channel->owner().processChats(data.vchats()); + owner.processUsers(data.vusers()); + owner.processChats(data.vchats()); const auto nextToken = Data::PublicForwardsSlice::OffsetToken({ .storyOffset = data.vnext_offset().value_or_empty(), @@ -494,23 +497,23 @@ void PublicForwards::requestStory( const auto msgId = IdFromMessage(message); const auto peerId = PeerFromMessage(message); const auto lastDate = DateFromMessage(message); - if (const auto peer = channel->owner().peerLoaded(peerId)) { + if (const auto peer = owner.peerLoaded(peerId)) { if (!lastDate) { return; } - channel->owner().addNewMessage( + owner.addNewMessage( message, MessageFlags(), NewMessageType::Existing); recentList.push_back({ .messageId = { peerId, msgId } }); } }, [&](const MTPDpublicForwardStory &data) { - data.vstory().match([&](const MTPDstoryItem &d) { - recentList.push_back({ - .storyId = { peerFromMTP(data.vpeer()), d.vid().v } - }); - }, [](const auto &) { - }); + const auto story = owner.stories().applyFromWebpage( + peerFromMTP(data.vpeer()), + data.vstory()); + if (story) { + recentList.push_back({ .storyId = story->fullId() }); + } }); } diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp index ca77f7ad5..20814f3ea 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp @@ -728,7 +728,12 @@ void InnerWidget::fill() { AddPublicForwards( _state.publicForwardsFirstSlice, inner, - [=](FullMsgId id) { _showRequests.fire({ .history = id }); }, + [=](RecentPostId id) { + _showRequests.fire({ + .history = id.messageId, + .story = id.storyId, + }); + }, descriptor.peer, RecentPostId{ .messageId = _contextId, .storyId = _storyId }); } diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.h b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.h index ed4e93a9f..ada52f65c 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.h +++ b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.h @@ -33,6 +33,7 @@ public: FullMsgId history; FullMsgId messageStatistic; FullStoryId storyStatistic; + FullStoryId story; }; InnerWidget( diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp index cdaffc183..acead54d5 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp @@ -9,22 +9,23 @@ 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_stories.h" #include "data/data_user.h" #include "history/history_item.h" #include "info/boosts/giveaway/boost_badge.h" #include "lang/lang_keys.h" #include "main/main_session.h" +#include "ui/effects/outline_segments.h" // Ui::UnreadStoryOutlineGradient. #include "ui/effects/toggle_arrow.h" -#include "ui/empty_userpic.h" #include "ui/painter.h" #include "ui/rect.h" #include "ui/vertical_list.h" #include "ui/widgets/buttons.h" #include "ui/wrap/slide_wrap.h" #include "ui/wrap/vertical_layout.h" +#include "styles/style_dialogs.h" // dialogsStoriesFull. #include "styles/style_settings.h" #include "styles/style_statistics.h" #include "styles/style_window.h" @@ -93,7 +94,7 @@ void AddSubtitle( struct PublicForwardsDescriptor final { Data::PublicForwardsSlice firstSlice; - Fn<void(FullMsgId)> showPeerHistory; + Fn<void(Data::RecentPostId)> requestShow; not_null<PeerData*> peer; Data::RecentPostId contextId; }; @@ -110,24 +111,62 @@ struct BoostsDescriptor final { not_null<PeerData*> peer; }; -class PeerListRowWithMsgId : public PeerListRow { +class PeerListRowWithFullId : public PeerListRow { public: - using PeerListRow::PeerListRow; + PeerListRowWithFullId( + not_null<PeerData*> peer, + Data::RecentPostId contextId); - void setMsgId(MsgId msgId); - [[nodiscard]] MsgId msgId() const; + [[nodiscard]] PaintRoundImageCallback generatePaintUserpicCallback( + bool) override; + + [[nodiscard]] Data::RecentPostId contextId() const; private: - MsgId _msgId; + const Data::RecentPostId _contextId; }; -void PeerListRowWithMsgId::setMsgId(MsgId msgId) { - _msgId = msgId; +PeerListRowWithFullId::PeerListRowWithFullId( + not_null<PeerData*> peer, + Data::RecentPostId contextId) +: PeerListRow(peer) +, _contextId(contextId) { } -MsgId PeerListRowWithMsgId::msgId() const { - return _msgId; +PaintRoundImageCallback PeerListRowWithFullId::generatePaintUserpicCallback( + bool forceRound) { + if (!_contextId.storyId) { + return PeerListRow::generatePaintUserpicCallback(forceRound); + } + const auto peer = PeerListRow::peer(); + auto userpic = PeerListRow::ensureUserpicView(); + + const auto line = st::dialogsStoriesFull.lineTwice; + const auto penWidth = line / 2.; + const auto offset = 1.5 * penWidth * 2; + return [=](Painter &p, int x, int y, int outerWidth, int size) mutable { + const auto rect = QRect(QPoint(x, y), Size(size)); + peer->paintUserpicLeft( + p, + userpic, + x + offset, + y + offset, + outerWidth, + size - offset * 2); + auto hq = PainterHighQualityEnabler(p); + auto gradient = Ui::UnreadStoryOutlineGradient(); + gradient.setStart(rect.topRight()); + gradient.setFinalStop(rect.bottomLeft()); + + p.setPen(QPen(gradient, penWidth)); + p.setBrush(Qt::NoBrush); + p.drawEllipse(rect - Margins(penWidth)); + }; +} + +Data::RecentPostId PeerListRowWithFullId::contextId() const { + return _contextId; } class MembersController final : public PeerListController { @@ -237,11 +276,11 @@ public: void loadMoreRows() override; private: - void appendRow(not_null<PeerData*> peer, MsgId msgId); + void appendRow(not_null<PeerData*> peer, Data::RecentPostId contextId); void applySlice(const Data::PublicForwardsSlice &slice); const not_null<Main::Session*> _session; - Fn<void(FullMsgId)> _showPeerHistory; + Fn<void(Data::RecentPostId)> _requestShow; Api::PublicForwards _api; Data::PublicForwardsSlice _firstSlice; @@ -253,7 +292,7 @@ private: PublicForwardsController::PublicForwardsController(PublicForwardsDescriptor d) : _session(&d.peer->session()) -, _showPeerHistory(std::move(d.showPeerHistory)) +, _requestShow(std::move(d.requestShow)) , _api(d.peer->asChannel(), d.contextId) , _firstSlice(std::move(d.firstSlice)) { } @@ -282,10 +321,13 @@ void PublicForwardsController::applySlice( _apiToken = slice.token; for (const auto &item : slice.list) { - // TODO support stories. - if (const auto fullId = item.messageId) { - if (const auto peer = session().data().peerLoaded(fullId.peer)) { - appendRow(peer, fullId.msg); + if (const auto &full = item.messageId) { + if (const auto peer = session().data().peerLoaded(full.peer)) { + appendRow(peer, item); + } + } else if (const auto &full = item.storyId) { + if (const auto story = session().data().stories().lookup(full)) { + appendRow((*story)->peer(), item); } } } @@ -293,25 +335,32 @@ void PublicForwardsController::applySlice( } void PublicForwardsController::rowClicked(not_null<PeerListRow*> row) { - const auto rowWithMsgId = static_cast<PeerListRowWithMsgId*>(row.get()); - crl::on_main([=, msgId = rowWithMsgId->msgId(), peer = row->peer()] { - _showPeerHistory({ peer->id, msgId }); - }); + const auto rowWithId = static_cast<PeerListRowWithFullId*>(row.get()); + crl::on_main([=, id = rowWithId->contextId()] { _requestShow(id); }); } void PublicForwardsController::appendRow( not_null<PeerData*> peer, - MsgId msgId) { + Data::RecentPostId contextId) { if (delegate()->peerListFindRow(peer->id.value)) { return; } - auto row = std::make_unique<PeerListRowWithMsgId>(peer); - row->setMsgId(msgId); + auto row = std::make_unique<PeerListRowWithFullId>(peer, contextId); - const auto members = peer->asChannel()->membersCount(); - const auto message = peer->owner().message({ peer->id, msgId }); - const auto views = message ? message->viewsCount() : 0; + const auto members = peer->isChannel() + ? peer->asChannel()->membersCount() + : 0; + const auto views = [&] { + if (contextId.messageId) { + const auto message = peer->owner().message(contextId.messageId); + return message ? message->viewsCount() : 0; + } else if (const auto &id = contextId.storyId) { + const auto story = peer->owner().stories().lookup(id); + return story ? (*story)->views() : 0; + } + return 0; + }(); const auto membersText = !members ? QString() @@ -321,7 +370,9 @@ void PublicForwardsController::appendRow( const auto viewsText = views ? tr::lng_stats_recent_messages_views({}, lt_count_decimal, views) : QString(); - const auto resultText = (membersText.isEmpty() || viewsText.isEmpty()) + const auto resultText = (membersText.isEmpty() && viewsText.isEmpty()) + ? tr::lng_stories_no_views(tr::now) + : (membersText.isEmpty() || viewsText.isEmpty()) ? membersText + viewsText : QString("%1, %2").arg(membersText, viewsText); row->setCustomStatus(resultText); @@ -618,7 +669,7 @@ rpl::producer<int> BoostsController::totalBoostsValue() const { void AddPublicForwards( const Data::PublicForwardsSlice &firstSlice, not_null<Ui::VerticalLayout*> container, - Fn<void(FullMsgId)> showPeerHistory, + Fn<void(Data::RecentPostId)> requestShow, not_null<PeerData*> peer, Data::RecentPostId contextId) { if (!peer->isChannel()) { @@ -633,7 +684,7 @@ void AddPublicForwards( }; auto d = PublicForwardsDescriptor{ firstSlice, - std::move(showPeerHistory), + std::move(requestShow), peer, contextId, }; diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.h b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.h index 0696062c7..2a2dfe93a 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.h +++ b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.h @@ -26,7 +26,7 @@ namespace Info::Statistics { void AddPublicForwards( const Data::PublicForwardsSlice &firstSlice, not_null<Ui::VerticalLayout*> container, - Fn<void(FullMsgId)> showPeerHistory, + Fn<void(Data::RecentPostId)> requestShow, not_null<PeerData*> peer, Data::RecentPostId contextId); diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp index 3544b2ae0..6c978b260 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp @@ -7,10 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "info/statistics/info_statistics_widget.h" -#include "info/statistics/info_statistics_inner_widget.h" +#include "data/data_session.h" +#include "data/data_stories.h" #include "info/info_controller.h" #include "info/info_memento.h" +#include "info/statistics/info_statistics_inner_widget.h" #include "lang/lang_keys.h" +#include "main/main_session.h" namespace Info::Statistics { @@ -78,6 +81,13 @@ Widget::Widget( controller->statisticsPeer(), request.messageStatistic, request.storyStatistic)); + } else if (const auto &s = request.story) { + if (const auto peer = controller->session().data().peer(s.peer)) { + controller->parentController()->openPeerStory( + peer, + s.story, + { Data::StoriesContextSingle() }); + } } }, _inner->lifetime()); _inner->scrollToRequests(