Added saving of profile tab state in section memento.

Related commits: 76e26ebbb1, e01a603a80.
This commit is contained in:
23rd
2026-09-14 07:27:09 +03:00
parent b84d21d07b
commit d64208dacb
7 changed files with 82 additions and 13 deletions

View File

@@ -507,7 +507,7 @@ void InnerWidget::saveState(not_null<Memento*> memento) {
memento->setMembersState(_members->saveState());
}
if (_tabsHost) {
memento->setActiveTab(_tabsHost->activeId());
memento->setTabsState(_tabsHost->saveState());
}
}
@@ -519,9 +519,7 @@ void InnerWidget::restoreState(not_null<Memento*> memento) {
_sharedMediaWrap->finishAnimating();
}
if (_tabsHost) {
if (const auto active = memento->activeTab(); !active.isEmpty()) {
_tabsHost->restoreActiveTab(active);
}
_tabsHost->restoreState(memento->tabsState());
}
}

View File

@@ -94,6 +94,14 @@ std::unique_ptr<MembersState> Memento::membersState() {
return std::move(_membersState);
}
void Memento::setTabsState(std::unique_ptr<TabsState> state) {
_tabsState = std::move(state);
}
std::unique_ptr<TabsState> Memento::tabsState() {
return std::move(_tabsState);
}
Memento::~Memento() = default;
Widget::Widget(

View File

@@ -20,6 +20,7 @@ namespace Info::Profile {
class InnerWidget;
class TabsHost;
struct MembersState;
struct TabsState;
struct GroupReactionOrigin {
not_null<PeerData*> group;
@@ -55,12 +56,8 @@ public:
void setMembersState(std::unique_ptr<MembersState> state);
[[nodiscard]] std::unique_ptr<MembersState> membersState();
void setActiveTab(const QString &id) {
_activeTab = id;
}
[[nodiscard]] QString activeTab() const {
return _activeTab;
}
void setTabsState(std::unique_ptr<TabsState> state);
[[nodiscard]] std::unique_ptr<TabsState> tabsState();
~Memento();
@@ -73,8 +70,8 @@ private:
Origin origin);
std::unique_ptr<MembersState> _membersState;
std::unique_ptr<TabsState> _tabsState;
Origin _origin;
QString _activeTab;
};

View File

@@ -20,6 +20,10 @@ namespace {
constexpr auto kEnableSearchMembersAfterCount = 20;
struct MembersTabState final : MediaTabState {
std::unique_ptr<MembersState> list;
};
class MembersTabAdapter final : public MediaTabContent {
public:
explicit MembersTabAdapter(MediaTabContext context)
@@ -109,6 +113,18 @@ public:
_members->setVisibleTopBottom(top, bottom);
}
std::unique_ptr<MediaTabState> saveState() override {
auto result = std::make_unique<MembersTabState>();
result->list = _members->saveState();
return result;
}
void restoreState(std::unique_ptr<MediaTabState> state) override {
if (const auto my = dynamic_cast<MembersTabState*>(state.get())) {
_members->restoreState(std::move(my->list));
}
}
private:
const not_null<PeerData*> _peer;
object_ptr<Ui::RpWidget> _host;

View File

@@ -40,6 +40,10 @@ struct MediaTabContext {
Fn<void(int count)> onlineCountChanged;
};
struct MediaTabState {
virtual ~MediaTabState() = default;
};
class MediaTabContent {
public:
virtual ~MediaTabContent() = default;
@@ -62,9 +66,10 @@ public:
virtual void paintOverflow(QPainter &p) {
}
virtual void saveScrollState(QByteArray &out) {
[[nodiscard]] virtual std::unique_ptr<MediaTabState> saveState() {
return nullptr;
}
virtual void restoreScrollState(const QByteArray &in) {
virtual void restoreState(std::unique_ptr<MediaTabState> state) {
}
};

View File

@@ -487,6 +487,35 @@ void TabsHost::ensureActiveVisible() {
}
}
std::unique_ptr<TabsState> TabsHost::saveState() {
auto result = std::make_unique<TabsState>();
result->activeId = _activeId;
result->scrollTops = _tabScrollTops;
if (!_activeId.isEmpty() && _visibleTop >= 0) {
result->scrollTops[_activeId] = _visibleTop;
}
for (auto &[id, content] : _contents) {
if (auto state = content->saveState()) {
result->contents.emplace(id, std::move(state));
}
}
for (auto &[id, state] : base::take(_pendingStates)) {
result->contents.emplace(id, std::move(state));
}
return result;
}
void TabsHost::restoreState(std::unique_ptr<TabsState> state) {
if (!state) {
return;
}
_tabScrollTops = std::move(state->scrollTops);
_pendingStates = std::move(state->contents);
if (!state->activeId.isEmpty()) {
restoreActiveTab(state->activeId);
}
}
void TabsHost::restoreActiveTab(const QString &id) {
const auto it = ranges::find(_tabs, id, &MediaTabDescriptor::id);
if (it == end(_tabs)) {
@@ -580,6 +609,12 @@ void TabsHost::activateTab(const QString &id, bool animated) {
});
};
cached = it->factory(std::move(context));
const auto pending = _pendingStates.find(id);
if (pending != end(_pendingStates)) {
auto state = std::move(pending->second);
_pendingStates.erase(pending);
cached->restoreState(std::move(state));
}
}
const auto previousId = _activeId;
const auto previousIndex = previousId.isEmpty()

View File

@@ -28,6 +28,12 @@ extern const char kOptionProfileMediaTabs[];
class TabsStrip;
struct TabsState {
QString activeId;
base::flat_map<QString, int> scrollTops;
base::flat_map<QString, std::unique_ptr<MediaTabState>> contents;
};
class TabsHost final : public Ui::RpWidget {
public:
struct Descriptor {
@@ -60,6 +66,9 @@ public:
void activateTab(const QString &id, bool animated = true);
void restoreActiveTab(const QString &id);
[[nodiscard]] std::unique_ptr<TabsState> saveState();
void restoreState(std::unique_ptr<TabsState> state);
[[nodiscard]] QRect bodyGeometry() const;
[[nodiscard]] Fn<void()> prepareSwitch(bool toNextTab);
@@ -121,6 +130,7 @@ private:
QRect _slideRect;
base::flat_map<QString, std::unique_ptr<MediaTabContent>> _contents;
base::flat_map<QString, std::unique_ptr<MediaTabState>> _pendingStates;
base::flat_map<QString, int> _tabScrollTops;
rpl::event_stream<Ui::ScrollToRequest> _scrollToRequests;
QString _activeId;