diff --git a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp index 426aea365f..7a74a94eec 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp @@ -507,7 +507,7 @@ void InnerWidget::saveState(not_null 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) { _sharedMediaWrap->finishAnimating(); } if (_tabsHost) { - if (const auto active = memento->activeTab(); !active.isEmpty()) { - _tabsHost->restoreActiveTab(active); - } + _tabsHost->restoreState(memento->tabsState()); } } diff --git a/Telegram/SourceFiles/info/profile/info_profile_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_widget.cpp index d8a74309a5..a69ed5c379 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_widget.cpp @@ -94,6 +94,14 @@ std::unique_ptr Memento::membersState() { return std::move(_membersState); } +void Memento::setTabsState(std::unique_ptr state) { + _tabsState = std::move(state); +} + +std::unique_ptr Memento::tabsState() { + return std::move(_tabsState); +} + Memento::~Memento() = default; Widget::Widget( diff --git a/Telegram/SourceFiles/info/profile/info_profile_widget.h b/Telegram/SourceFiles/info/profile/info_profile_widget.h index d70c063a87..4db90ce7b2 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_widget.h +++ b/Telegram/SourceFiles/info/profile/info_profile_widget.h @@ -20,6 +20,7 @@ namespace Info::Profile { class InnerWidget; class TabsHost; struct MembersState; +struct TabsState; struct GroupReactionOrigin { not_null group; @@ -55,12 +56,8 @@ public: void setMembersState(std::unique_ptr state); [[nodiscard]] std::unique_ptr membersState(); - void setActiveTab(const QString &id) { - _activeTab = id; - } - [[nodiscard]] QString activeTab() const { - return _activeTab; - } + void setTabsState(std::unique_ptr state); + [[nodiscard]] std::unique_ptr tabsState(); ~Memento(); @@ -73,8 +70,8 @@ private: Origin origin); std::unique_ptr _membersState; + std::unique_ptr _tabsState; Origin _origin; - QString _activeTab; }; diff --git a/Telegram/SourceFiles/info/profile/tabs/adapters/info_profile_tab_members.cpp b/Telegram/SourceFiles/info/profile/tabs/adapters/info_profile_tab_members.cpp index 525ef5b801..3ff4b6d825 100644 --- a/Telegram/SourceFiles/info/profile/tabs/adapters/info_profile_tab_members.cpp +++ b/Telegram/SourceFiles/info/profile/tabs/adapters/info_profile_tab_members.cpp @@ -20,6 +20,10 @@ namespace { constexpr auto kEnableSearchMembersAfterCount = 20; +struct MembersTabState final : MediaTabState { + std::unique_ptr list; +}; + class MembersTabAdapter final : public MediaTabContent { public: explicit MembersTabAdapter(MediaTabContext context) @@ -109,6 +113,18 @@ public: _members->setVisibleTopBottom(top, bottom); } + std::unique_ptr saveState() override { + auto result = std::make_unique(); + result->list = _members->saveState(); + return result; + } + + void restoreState(std::unique_ptr state) override { + if (const auto my = dynamic_cast(state.get())) { + _members->restoreState(std::move(my->list)); + } + } + private: const not_null _peer; object_ptr _host; diff --git a/Telegram/SourceFiles/info/profile/tabs/info_profile_tab_content.h b/Telegram/SourceFiles/info/profile/tabs/info_profile_tab_content.h index 827bef567d..a4dae56937 100644 --- a/Telegram/SourceFiles/info/profile/tabs/info_profile_tab_content.h +++ b/Telegram/SourceFiles/info/profile/tabs/info_profile_tab_content.h @@ -40,6 +40,10 @@ struct MediaTabContext { Fn 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 saveState() { + return nullptr; } - virtual void restoreScrollState(const QByteArray &in) { + virtual void restoreState(std::unique_ptr state) { } }; diff --git a/Telegram/SourceFiles/info/profile/tabs/info_profile_tabs_host.cpp b/Telegram/SourceFiles/info/profile/tabs/info_profile_tabs_host.cpp index 8333c62c91..86ab301ee9 100644 --- a/Telegram/SourceFiles/info/profile/tabs/info_profile_tabs_host.cpp +++ b/Telegram/SourceFiles/info/profile/tabs/info_profile_tabs_host.cpp @@ -487,6 +487,35 @@ void TabsHost::ensureActiveVisible() { } } +std::unique_ptr TabsHost::saveState() { + auto result = std::make_unique(); + 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 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() diff --git a/Telegram/SourceFiles/info/profile/tabs/info_profile_tabs_host.h b/Telegram/SourceFiles/info/profile/tabs/info_profile_tabs_host.h index 4be72c3d7d..78d22e54ed 100644 --- a/Telegram/SourceFiles/info/profile/tabs/info_profile_tabs_host.h +++ b/Telegram/SourceFiles/info/profile/tabs/info_profile_tabs_host.h @@ -28,6 +28,12 @@ extern const char kOptionProfileMediaTabs[]; class TabsStrip; +struct TabsState { + QString activeId; + base::flat_map scrollTops; + base::flat_map> 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 saveState(); + void restoreState(std::unique_ptr state); + [[nodiscard]] QRect bodyGeometry() const; [[nodiscard]] Fn prepareSwitch(bool toNextTab); @@ -121,6 +130,7 @@ private: QRect _slideRect; base::flat_map> _contents; + base::flat_map> _pendingStates; base::flat_map _tabScrollTops; rpl::event_stream _scrollToRequests; QString _activeId;