Added ability to save state for recent posts in statistical info.

This commit is contained in:
23rd 2023-10-11 04:53:59 +03:00 committed by John Preston
parent aee6b6e224
commit a3d8db4ac0
8 changed files with 147 additions and 104 deletions

View file

@ -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

View file

@ -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<MsgId, QImage> recentPostPreviews;
};
} // namespace Info::Statistics

View file

@ -470,78 +470,6 @@ void FillOverview(
::Settings::AddSkip(content, st::statisticsLayerOverviewMargins.bottom());
}
void FillRecentPosts(
not_null<Ui::VerticalLayout*> container,
const Descriptor &descriptor,
const Data::ChannelStatistics &stats,
Fn<void(FullMsgId)> showMessageStatistic) {
if (stats.recentMessageInteractions.empty()) {
return;
}
const auto wrap = container->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container,
object_ptr<Ui::VerticalLayout>(container)));
const auto content = wrap->entity();
AddHeader(content, tr::lng_stats_recent_messages_title, { stats, {} });
::Settings::AddSkip(content);
const auto addMessage = [=](
not_null<Ui::VerticalLayout*> messageWrap,
not_null<HistoryItem*> item,
const Data::StatisticsMessageInteractionInfo &info) {
const auto button = messageWrap->add(
object_ptr<Ui::SettingsButton>(
messageWrap,
rpl::never<QString>(),
st::statisticsRecentPostButton));
const auto raw = Ui::CreateChild<MessagePreview>(
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<Ui::VerticalLayout>(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<Api::Statistics>(&_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<PeerData*> 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<Ui::SlideWrap<Ui::VerticalLayout>>(
container,
object_ptr<Ui::VerticalLayout>(container)));
const auto content = wrap->entity();
AddHeader(content, tr::lng_stats_recent_messages_title, { stats, {} });
::Settings::AddSkip(content);
const auto addMessage = [=](
not_null<Ui::VerticalLayout*> messageWrap,
not_null<HistoryItem*> item,
const Data::StatisticsMessageInteractionInfo &info) {
const auto button = messageWrap->add(
object_ptr<Ui::SettingsButton>(
messageWrap,
rpl::never<QString>(),
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<MessagePreview>(
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<Ui::VerticalLayout>(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) {
memento->setStates(base::take(_loadedStats));
for (const auto &message : _messagePreviews) {
message->saveState(_state);
}
memento->setState(base::take(_state));
}
void InnerWidget::restoreState(not_null<Memento*> 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();

View file

@ -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*> _controller;
not_null<PeerData*> _peer;
FullMsgId _contextId;
Data::AnyStatistics _loadedStats;
std::vector<not_null<MessagePreview*>> _messagePreviews;
SavedState _state;
rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests;
rpl::event_stream<ShowRequest> _showRequests;

View file

@ -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<Ui::RpWidget*> parent,
not_null<HistoryItem*> 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<HistoryItem*> 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

View file

@ -22,13 +22,18 @@ class SpoilerAnimation;
namespace Info::Statistics {
struct SavedState;
class MessagePreview final : public Ui::RpWidget {
public:
MessagePreview(
not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item,
int views,
int shares);
int shares,
QImage cachedPreview);
void saveState(SavedState &state) const;
protected:
void paintEvent(QPaintEvent *e) override;

View file

@ -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<ContentWidget> Memento::createWidget(

View file

@ -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;
};