diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 93140d89f..4a73bf094 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -884,6 +884,7 @@ PRIVATE info/profile/info_profile_widget.h info/settings/info_settings_widget.cpp info/settings/info_settings_widget.h + info/statistics/info_statistics_common.h info/statistics/info_statistics_inner_widget.cpp info/statistics/info_statistics_inner_widget.h info/statistics/info_statistics_list_controllers.cpp diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_common.h b/Telegram/SourceFiles/info/statistics/info_statistics_common.h new file mode 100644 index 000000000..9ffa41680 --- /dev/null +++ b/Telegram/SourceFiles/info/statistics/info_statistics_common.h @@ -0,0 +1,19 @@ +/* +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 "data/data_statistics.h" + +namespace Info::Statistics { + +struct SavedState final { + Data::AnyStatistics stats; + base::flat_map recentPostPreviews; +}; + +} // namespace Info::Statistics diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp index d29ec1e21..b103f4714 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp @@ -470,78 +470,6 @@ void FillOverview( ::Settings::AddSkip(content, st::statisticsLayerOverviewMargins.bottom()); } -void FillRecentPosts( - not_null container, - const Descriptor &descriptor, - const Data::ChannelStatistics &stats, - Fn showMessageStatistic) { - if (stats.recentMessageInteractions.empty()) { - return; - } - - const auto wrap = container->add( - object_ptr>( - container, - object_ptr(container))); - const auto content = wrap->entity(); - AddHeader(content, tr::lng_stats_recent_messages_title, { stats, {} }); - ::Settings::AddSkip(content); - - const auto addMessage = [=]( - not_null messageWrap, - not_null item, - const Data::StatisticsMessageInteractionInfo &info) { - const auto button = messageWrap->add( - object_ptr( - messageWrap, - rpl::never(), - st::statisticsRecentPostButton)); - const auto raw = Ui::CreateChild( - button, - item, - info.viewsCount, - info.forwardsCount); - raw->show(); - button->sizeValue( - ) | rpl::start_with_next([=](const QSize &s) { - if (!s.isNull()) { - raw->setGeometry(Rect(s) - - st::statisticsRecentPostButton.padding); - } - }, raw->lifetime()); - button->setClickedCallback([=, fullId = item->fullId()] { - showMessageStatistic(fullId); - }); - ::Settings::AddSkip(messageWrap); - if (!wrap->toggled()) { - wrap->toggle(true, anim::type::normal); - } - }; - - auto foundLoaded = false; - const auto &peer = descriptor.peer; - for (const auto &recent : stats.recentMessageInteractions) { - const auto messageWrap = content->add( - object_ptr(content)); - const auto msgId = recent.messageId; - if (const auto item = peer->owner().message(peer, msgId)) { - addMessage(messageWrap, item, recent); - foundLoaded = true; - continue; - } - const auto callback = crl::guard(content, [=] { - if (const auto item = peer->owner().message(peer, msgId)) { - addMessage(messageWrap, item, recent); - content->resizeToWidth(content->width()); - } - }); - peer->session().api().requestMessageData(peer, msgId, callback); - } - if (!foundLoaded) { - wrap->toggle(false, anim::type::instant); - } -} - } // namespace InnerWidget::InnerWidget( @@ -581,7 +509,7 @@ void InnerWidget::load() { descriptor.api->request( descriptor.peer ) | rpl::start_with_done([=] { - _loadedStats = Data::AnyStatistics{ + _state.stats = Data::AnyStatistics{ descriptor.api->channelStats(), descriptor.api->supergroupStats(), }; @@ -596,7 +524,7 @@ void InnerWidget::load() { _contextId); api->request([=](const Data::MessageStatistics &data) { - _loadedStats = Data::AnyStatistics{ .message = data }; + _state.stats = Data::AnyStatistics{ .message = data }; fill(); finishLoading(); @@ -613,16 +541,13 @@ void InnerWidget::fill() { 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; + FillOverview(inner, _state.stats); + FillStatistic(inner, descriptor, _state.stats); + const auto &channel = _state.stats.channel; + const auto &supergroup = _state.stats.supergroup; + const auto &message = _state.stats.message; if (channel) { - auto showMessage = [=](FullMsgId fullId) { - _showRequests.fire({ .messageStatistic = fullId }); - }; - FillRecentPosts(inner, descriptor, channel, showMessage); + fillRecentPosts(); } else if (supergroup) { const auto showPeerInfo = [=](not_null peer) { _showRequests.fire({ .info = peer->id }); @@ -677,15 +602,95 @@ void InnerWidget::fill() { } } +void InnerWidget::fillRecentPosts() { + const auto &stats = _state.stats.channel; + if (!stats || stats.recentMessageInteractions.empty()) { + return; + } + _messagePreviews.reserve(stats.recentMessageInteractions.size()); + const auto container = this; + + const auto wrap = container->add( + object_ptr>( + container, + object_ptr(container))); + const auto content = wrap->entity(); + AddHeader(content, tr::lng_stats_recent_messages_title, { stats, {} }); + ::Settings::AddSkip(content); + + const auto addMessage = [=]( + not_null messageWrap, + not_null item, + const Data::StatisticsMessageInteractionInfo &info) { + const auto button = messageWrap->add( + object_ptr( + messageWrap, + rpl::never(), + st::statisticsRecentPostButton)); + auto it = _state.recentPostPreviews.find(item->fullId().msg); + auto cachedPreview = (it != end(_state.recentPostPreviews)) + ? base::take(it->second) + : QImage(); + const auto raw = Ui::CreateChild( + button, + item, + info.viewsCount, + info.forwardsCount, + std::move(cachedPreview)); + + _messagePreviews.push_back(raw); + raw->show(); + button->sizeValue( + ) | rpl::start_with_next([=](const QSize &s) { + if (!s.isNull()) { + raw->setGeometry(Rect(s) + - st::statisticsRecentPostButton.padding); + } + }, raw->lifetime()); + button->setClickedCallback([=, fullId = item->fullId()] { + _showRequests.fire({ .messageStatistic = fullId }); + }); + ::Settings::AddSkip(messageWrap); + if (!wrap->toggled()) { + wrap->toggle(true, anim::type::normal); + } + }; + + auto foundLoaded = false; + for (const auto &recent : stats.recentMessageInteractions) { + const auto messageWrap = content->add( + object_ptr(content)); + const auto msgId = recent.messageId; + if (const auto item = _peer->owner().message(_peer, msgId)) { + addMessage(messageWrap, item, recent); + foundLoaded = true; + continue; + } + const auto callback = crl::guard(content, [=] { + if (const auto item = _peer->owner().message(_peer, msgId)) { + addMessage(messageWrap, item, recent); + content->resizeToWidth(content->width()); + } + }); + _peer->session().api().requestMessageData(_peer, msgId, callback); + } + if (!foundLoaded) { + wrap->toggle(false, anim::type::instant); + } +} + void InnerWidget::saveState(not_null memento) { - memento->setStates(base::take(_loadedStats)); + for (const auto &message : _messagePreviews) { + message->saveState(_state); + } + memento->setState(base::take(_state)); } void InnerWidget::restoreState(not_null memento) { - _loadedStats = memento->states(); - if (_loadedStats.channel - || _loadedStats.supergroup - || _loadedStats.message) { + _state = memento->state(); + if (_state.stats.channel + || _state.stats.supergroup + || _state.stats.message) { fill(); } else { load(); diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.h b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.h index f384d70eb..cd3aa9348 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.h +++ b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.h @@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "base/object_ptr.h" -#include "data/data_statistics.h" +#include "info/statistics/info_statistics_common.h" #include "ui/widgets/scroll_area.h" #include "ui/wrap/vertical_layout.h" @@ -19,6 +19,7 @@ class Controller; namespace Info::Statistics { class Memento; +class MessagePreview; class InnerWidget final : public Ui::VerticalLayout { public: @@ -48,12 +49,15 @@ public: private: void load(); void fill(); + void fillRecentPosts(); not_null _controller; not_null _peer; FullMsgId _contextId; - Data::AnyStatistics _loadedStats; + std::vector> _messagePreviews; + + SavedState _state; rpl::event_stream _scrollToRequests; rpl::event_stream _showRequests; diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_recent_message.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_recent_message.cpp index 9ffdb7fbc..e4825c712 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_recent_message.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_recent_message.cpp @@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "history/history_item_helpers.h" #include "history/view/history_view_item_preview.h" +#include "info/statistics/info_statistics_common.h" #include "lang/lang_keys.h" #include "main/main_session.h" #include "ui/effects/ripple_animation.h" @@ -69,7 +70,8 @@ MessagePreview::MessagePreview( not_null parent, not_null item, int views, - int shares) + int shares, + QImage cachedPreview) : Ui::RpWidget(parent) , _item(item) , _date( @@ -88,7 +90,8 @@ MessagePreview::MessagePreview( lt_count_decimal, shares)) , _viewsWidth(_views.maxWidth()) -, _sharesWidth(_shares.maxWidth()) { +, _sharesWidth(_shares.maxWidth()) +, _preview(std::move(cachedPreview)) { _text.setMarkedText( st::defaultPeerListItem.nameStyle, _item->toPreview({ .generateImages = false }).text, @@ -97,7 +100,9 @@ MessagePreview::MessagePreview( .session = &item->history()->session(), .customEmojiRepaint = [=] { update(); }, }); - processPreview(item); + if (_preview.isNull()) { + processPreview(item); + } } void MessagePreview::processPreview(not_null item) { @@ -226,4 +231,10 @@ void MessagePreview::paintEvent(QPaintEvent *e) { }); } +void MessagePreview::saveState(SavedState &state) const { + if (!_lifetimeDownload) { + state.recentPostPreviews[_item->fullId().msg] = _preview; + } +} + } // namespace Info::Statistics diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_recent_message.h b/Telegram/SourceFiles/info/statistics/info_statistics_recent_message.h index 5f858086e..147b5bcb2 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_recent_message.h +++ b/Telegram/SourceFiles/info/statistics/info_statistics_recent_message.h @@ -22,13 +22,18 @@ class SpoilerAnimation; namespace Info::Statistics { +struct SavedState; + class MessagePreview final : public Ui::RpWidget { public: MessagePreview( not_null parent, not_null item, int views, - int shares); + int shares, + QImage cachedPreview); + + void saveState(SavedState &state) const; protected: void paintEvent(QPaintEvent *e) override; diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp index 6d9004e24..1edae544a 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_widget.cpp @@ -31,12 +31,12 @@ Section Memento::section() const { return Section(Section::Type::Statistics); } -void Memento::setStates(Memento::States states) { - _states = std::move(states); +void Memento::setState(SavedState state) { + _state = std::move(state); } -Memento::States Memento::states() { - return base::take(_states); +SavedState Memento::state() { + return base::take(_state); } object_ptr Memento::createWidget( diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_widget.h b/Telegram/SourceFiles/info/statistics/info_statistics_widget.h index 06827f461..172db8f3e 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_widget.h +++ b/Telegram/SourceFiles/info/statistics/info_statistics_widget.h @@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "info/info_content_widget.h" -#include "data/data_statistics.h" +#include "info/statistics/info_statistics_common.h" namespace Info::Statistics { @@ -27,13 +27,11 @@ public: Section section() const override; - using States = Data::AnyStatistics; - - void setStates(States states); - [[nodiscard]] States states(); + void setState(SavedState states); + [[nodiscard]] SavedState state(); private: - States _states; + SavedState _state; };