Added ability to save state for recent posts in statistical info.
This commit is contained in:
parent
aee6b6e224
commit
a3d8db4ac0
|
@ -884,6 +884,7 @@ PRIVATE
|
||||||
info/profile/info_profile_widget.h
|
info/profile/info_profile_widget.h
|
||||||
info/settings/info_settings_widget.cpp
|
info/settings/info_settings_widget.cpp
|
||||||
info/settings/info_settings_widget.h
|
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.cpp
|
||||||
info/statistics/info_statistics_inner_widget.h
|
info/statistics/info_statistics_inner_widget.h
|
||||||
info/statistics/info_statistics_list_controllers.cpp
|
info/statistics/info_statistics_list_controllers.cpp
|
||||||
|
|
|
@ -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
|
|
@ -470,78 +470,6 @@ void FillOverview(
|
||||||
::Settings::AddSkip(content, st::statisticsLayerOverviewMargins.bottom());
|
::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
|
} // namespace
|
||||||
|
|
||||||
InnerWidget::InnerWidget(
|
InnerWidget::InnerWidget(
|
||||||
|
@ -581,7 +509,7 @@ void InnerWidget::load() {
|
||||||
descriptor.api->request(
|
descriptor.api->request(
|
||||||
descriptor.peer
|
descriptor.peer
|
||||||
) | rpl::start_with_done([=] {
|
) | rpl::start_with_done([=] {
|
||||||
_loadedStats = Data::AnyStatistics{
|
_state.stats = Data::AnyStatistics{
|
||||||
descriptor.api->channelStats(),
|
descriptor.api->channelStats(),
|
||||||
descriptor.api->supergroupStats(),
|
descriptor.api->supergroupStats(),
|
||||||
};
|
};
|
||||||
|
@ -596,7 +524,7 @@ void InnerWidget::load() {
|
||||||
_contextId);
|
_contextId);
|
||||||
|
|
||||||
api->request([=](const Data::MessageStatistics &data) {
|
api->request([=](const Data::MessageStatistics &data) {
|
||||||
_loadedStats = Data::AnyStatistics{ .message = data };
|
_state.stats = Data::AnyStatistics{ .message = data };
|
||||||
fill();
|
fill();
|
||||||
|
|
||||||
finishLoading();
|
finishLoading();
|
||||||
|
@ -613,16 +541,13 @@ void InnerWidget::fill() {
|
||||||
lifetime().make_state<Api::Statistics>(&_peer->session().api()),
|
lifetime().make_state<Api::Statistics>(&_peer->session().api()),
|
||||||
_controller->uiShow()->toastParent(),
|
_controller->uiShow()->toastParent(),
|
||||||
};
|
};
|
||||||
FillOverview(inner, _loadedStats);
|
FillOverview(inner, _state.stats);
|
||||||
FillStatistic(inner, descriptor, _loadedStats);
|
FillStatistic(inner, descriptor, _state.stats);
|
||||||
const auto &channel = _loadedStats.channel;
|
const auto &channel = _state.stats.channel;
|
||||||
const auto &supergroup = _loadedStats.supergroup;
|
const auto &supergroup = _state.stats.supergroup;
|
||||||
const auto &message = _loadedStats.message;
|
const auto &message = _state.stats.message;
|
||||||
if (channel) {
|
if (channel) {
|
||||||
auto showMessage = [=](FullMsgId fullId) {
|
fillRecentPosts();
|
||||||
_showRequests.fire({ .messageStatistic = fullId });
|
|
||||||
};
|
|
||||||
FillRecentPosts(inner, descriptor, channel, showMessage);
|
|
||||||
} else if (supergroup) {
|
} else if (supergroup) {
|
||||||
const auto showPeerInfo = [=](not_null<PeerData*> peer) {
|
const auto showPeerInfo = [=](not_null<PeerData*> peer) {
|
||||||
_showRequests.fire({ .info = peer->id });
|
_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) {
|
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) {
|
void InnerWidget::restoreState(not_null<Memento*> memento) {
|
||||||
_loadedStats = memento->states();
|
_state = memento->state();
|
||||||
if (_loadedStats.channel
|
if (_state.stats.channel
|
||||||
|| _loadedStats.supergroup
|
|| _state.stats.supergroup
|
||||||
|| _loadedStats.message) {
|
|| _state.stats.message) {
|
||||||
fill();
|
fill();
|
||||||
} else {
|
} else {
|
||||||
load();
|
load();
|
||||||
|
|
|
@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/object_ptr.h"
|
#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/widgets/scroll_area.h"
|
||||||
#include "ui/wrap/vertical_layout.h"
|
#include "ui/wrap/vertical_layout.h"
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ class Controller;
|
||||||
namespace Info::Statistics {
|
namespace Info::Statistics {
|
||||||
|
|
||||||
class Memento;
|
class Memento;
|
||||||
|
class MessagePreview;
|
||||||
|
|
||||||
class InnerWidget final : public Ui::VerticalLayout {
|
class InnerWidget final : public Ui::VerticalLayout {
|
||||||
public:
|
public:
|
||||||
|
@ -48,12 +49,15 @@ public:
|
||||||
private:
|
private:
|
||||||
void load();
|
void load();
|
||||||
void fill();
|
void fill();
|
||||||
|
void fillRecentPosts();
|
||||||
|
|
||||||
not_null<Controller*> _controller;
|
not_null<Controller*> _controller;
|
||||||
not_null<PeerData*> _peer;
|
not_null<PeerData*> _peer;
|
||||||
FullMsgId _contextId;
|
FullMsgId _contextId;
|
||||||
|
|
||||||
Data::AnyStatistics _loadedStats;
|
std::vector<not_null<MessagePreview*>> _messagePreviews;
|
||||||
|
|
||||||
|
SavedState _state;
|
||||||
|
|
||||||
rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests;
|
rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests;
|
||||||
rpl::event_stream<ShowRequest> _showRequests;
|
rpl::event_stream<ShowRequest> _showRequests;
|
||||||
|
|
|
@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "history/history_item_helpers.h"
|
#include "history/history_item_helpers.h"
|
||||||
#include "history/view/history_view_item_preview.h"
|
#include "history/view/history_view_item_preview.h"
|
||||||
|
#include "info/statistics/info_statistics_common.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "ui/effects/ripple_animation.h"
|
#include "ui/effects/ripple_animation.h"
|
||||||
|
@ -69,7 +70,8 @@ MessagePreview::MessagePreview(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
int views,
|
int views,
|
||||||
int shares)
|
int shares,
|
||||||
|
QImage cachedPreview)
|
||||||
: Ui::RpWidget(parent)
|
: Ui::RpWidget(parent)
|
||||||
, _item(item)
|
, _item(item)
|
||||||
, _date(
|
, _date(
|
||||||
|
@ -88,7 +90,8 @@ MessagePreview::MessagePreview(
|
||||||
lt_count_decimal,
|
lt_count_decimal,
|
||||||
shares))
|
shares))
|
||||||
, _viewsWidth(_views.maxWidth())
|
, _viewsWidth(_views.maxWidth())
|
||||||
, _sharesWidth(_shares.maxWidth()) {
|
, _sharesWidth(_shares.maxWidth())
|
||||||
|
, _preview(std::move(cachedPreview)) {
|
||||||
_text.setMarkedText(
|
_text.setMarkedText(
|
||||||
st::defaultPeerListItem.nameStyle,
|
st::defaultPeerListItem.nameStyle,
|
||||||
_item->toPreview({ .generateImages = false }).text,
|
_item->toPreview({ .generateImages = false }).text,
|
||||||
|
@ -97,7 +100,9 @@ MessagePreview::MessagePreview(
|
||||||
.session = &item->history()->session(),
|
.session = &item->history()->session(),
|
||||||
.customEmojiRepaint = [=] { update(); },
|
.customEmojiRepaint = [=] { update(); },
|
||||||
});
|
});
|
||||||
processPreview(item);
|
if (_preview.isNull()) {
|
||||||
|
processPreview(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessagePreview::processPreview(not_null<HistoryItem*> 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
|
} // namespace Info::Statistics
|
||||||
|
|
|
@ -22,13 +22,18 @@ class SpoilerAnimation;
|
||||||
|
|
||||||
namespace Info::Statistics {
|
namespace Info::Statistics {
|
||||||
|
|
||||||
|
struct SavedState;
|
||||||
|
|
||||||
class MessagePreview final : public Ui::RpWidget {
|
class MessagePreview final : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
MessagePreview(
|
MessagePreview(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
int views,
|
int views,
|
||||||
int shares);
|
int shares,
|
||||||
|
QImage cachedPreview);
|
||||||
|
|
||||||
|
void saveState(SavedState &state) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
|
@ -31,12 +31,12 @@ Section Memento::section() const {
|
||||||
return Section(Section::Type::Statistics);
|
return Section(Section::Type::Statistics);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Memento::setStates(Memento::States states) {
|
void Memento::setState(SavedState state) {
|
||||||
_states = std::move(states);
|
_state = std::move(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Memento::States Memento::states() {
|
SavedState Memento::state() {
|
||||||
return base::take(_states);
|
return base::take(_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
object_ptr<ContentWidget> Memento::createWidget(
|
object_ptr<ContentWidget> Memento::createWidget(
|
||||||
|
|
|
@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "info/info_content_widget.h"
|
#include "info/info_content_widget.h"
|
||||||
#include "data/data_statistics.h"
|
#include "info/statistics/info_statistics_common.h"
|
||||||
|
|
||||||
namespace Info::Statistics {
|
namespace Info::Statistics {
|
||||||
|
|
||||||
|
@ -27,13 +27,11 @@ public:
|
||||||
|
|
||||||
Section section() const override;
|
Section section() const override;
|
||||||
|
|
||||||
using States = Data::AnyStatistics;
|
void setState(SavedState states);
|
||||||
|
[[nodiscard]] SavedState state();
|
||||||
void setStates(States states);
|
|
||||||
[[nodiscard]] States states();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
States _states;
|
SavedState _state;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue