From 628c8e10f7f6c49e40b286ec93648a17b71d11c6 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 3 Nov 2017 22:26:14 +0400 Subject: [PATCH] Search and save state in common groups. --- .../info_common_groups_inner_widget.cpp | 79 ++++++++++++++++++- .../info_common_groups_inner_widget.h | 1 + .../info_common_groups_widget.cpp | 15 +++- .../common_groups/info_common_groups_widget.h | 15 +++- .../SourceFiles/info/info_content_widget.cpp | 48 +++++++++-- .../SourceFiles/info/info_content_widget.h | 23 ++++-- Telegram/SourceFiles/info/info_controller.cpp | 21 +++-- Telegram/SourceFiles/info/info_controller.h | 7 ++ Telegram/SourceFiles/info/info_memento.cpp | 18 +++-- Telegram/SourceFiles/info/info_memento.h | 16 +++- Telegram/SourceFiles/info/info_top_bar.cpp | 31 ++++++-- Telegram/SourceFiles/info/info_top_bar.h | 11 ++- .../SourceFiles/info/info_wrap_widget.cpp | 34 +++++++- Telegram/SourceFiles/info/info_wrap_widget.h | 2 + .../info/media/info_media_inner_widget.cpp | 9 ++- .../info/media/info_media_inner_widget.h | 1 + .../info/media/info_media_list_widget.cpp | 6 ++ .../info/media/info_media_widget.cpp | 27 +------ .../info/media/info_media_widget.h | 4 +- .../info/profile/info_profile_members.cpp | 2 +- .../info/profile/info_profile_widget.cpp | 2 +- .../info/profile/info_profile_widget.h | 3 +- 22 files changed, 290 insertions(+), 85 deletions(-) diff --git a/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.cpp b/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.cpp index edd8676ed..4ae8e1338 100644 --- a/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.cpp +++ b/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.cpp @@ -28,13 +28,15 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "mtproto/sender.h" #include "window/window_controller.h" #include "ui/widgets/scroll_area.h" +#include "ui/search_field_controller.h" #include "apiwrap.h" namespace Info { namespace CommonGroups { namespace { -constexpr int kCommonGroupsPerPage = 40; +constexpr auto kCommonGroupsPerPage = 40; +constexpr auto kCommonGroupsSearchAfter = 20; class ListController : public PeerListController @@ -49,7 +51,22 @@ public: void rowClicked(not_null row) override; void loadMoreRows() override; + std::unique_ptr createRestoredRow( + not_null peer) override { + return createRow(peer); + } + + std::unique_ptr saveState() override; + void restoreState(std::unique_ptr state) override; + private: + std::unique_ptr createRow(not_null peer); + + struct SavedState : SavedStateBase { + int32 preloadGroupId = 0; + bool allLoaded = false; + bool wasLoading = false; + }; const not_null _controller; not_null _user; mtpRequestId _preloadRequestId = 0; @@ -64,6 +81,14 @@ ListController::ListController( : PeerListController() , _controller(controller) , _user(user) { + _controller->setSearchEnabledByContent(false); +} + +std::unique_ptr ListController::createRow( + not_null peer) { + auto result = std::make_unique(peer); + result->setCustomStatus(QString()); + return result; } void ListController::prepare() { @@ -90,9 +115,8 @@ void ListController::loadMoreRows() { for_const (auto &chatData, list) { if (auto chat = App::feedChat(chatData)) { if (!chat->migrateTo()) { - auto row = std::make_unique(chat); - row->setCustomStatus(QString()); - delegate()->peerListAppendRow(std::move(row)); + delegate()->peerListAppendRow( + createRow(chat)); } _preloadGroupId = chat->bareId(); _allLoaded = false; @@ -101,9 +125,48 @@ void ListController::loadMoreRows() { delegate()->peerListRefreshRows(); } } + auto fullCount = delegate()->peerListFullRowsCount(); + if (fullCount > kCommonGroupsSearchAfter) { + _controller->setSearchEnabledByContent(true); + } }).send(); } +std::unique_ptr ListController::saveState() { + auto result = PeerListController::saveState(); + auto my = std::make_unique(); + my->preloadGroupId = _preloadGroupId; + my->allLoaded = _allLoaded; + if (auto requestId = base::take(_preloadRequestId)) { + request(requestId).cancel(); + my->wasLoading = true; + } + result->controllerState = std::move(my); + return result; +} + +void ListController::restoreState( + std::unique_ptr state) { + auto typeErasedState = state + ? state->controllerState.get() + : nullptr; + if (auto my = dynamic_cast(typeErasedState)) { + if (auto requestId = base::take(_preloadRequestId)) { + request(requestId).cancel(); + } + _allLoaded = my->allLoaded; + _preloadGroupId = my->preloadGroupId; + if (my->wasLoading) { + loadMoreRows(); + } + PeerListController::restoreState(std::move(state)); + auto fullCount = delegate()->peerListFullRowsCount(); + if (fullCount > kCommonGroupsSearchAfter) { + _controller->setSearchEnabledByContent(true); + } + } +} + void ListController::rowClicked(not_null row) { _controller->window()->showPeerHistory( row->peer(), @@ -117,11 +180,17 @@ InnerWidget::InnerWidget( not_null controller, not_null user) : RpWidget(parent) +, _controller(controller) , _user(user) , _listController(std::make_unique(controller, _user)) , _list(setupList(this, _listController.get())) { setContent(_list.data()); _listController->setDelegate(static_cast(this)); + _controller->searchFieldController()->queryValue() + | rpl::start_with_next([this](QString &&query) { + peerListScrollToTop(); + content()->searchQueryChanged(std::move(query)); + }, lifetime()); } void InnerWidget::visibleTopBottomUpdated( @@ -131,9 +200,11 @@ void InnerWidget::visibleTopBottomUpdated( } void InnerWidget::saveState(not_null memento) { + memento->setListState(_listController->saveState()); } void InnerWidget::restoreState(not_null memento) { + _listController->restoreState(std::move(memento->listState())); } int InnerWidget::desiredHeight() const { diff --git a/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.h b/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.h index 06a3eb91a..dbd3573f1 100644 --- a/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.h +++ b/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.h @@ -80,6 +80,7 @@ private: RpWidget *parent, not_null controller) const; + not_null _controller; not_null _user; std::unique_ptr _listController; object_ptr _list; diff --git a/Telegram/SourceFiles/info/common_groups/info_common_groups_widget.cpp b/Telegram/SourceFiles/info/common_groups/info_common_groups_widget.cpp index d1dfaa32b..cd68e075a 100644 --- a/Telegram/SourceFiles/info/common_groups/info_common_groups_widget.cpp +++ b/Telegram/SourceFiles/info/common_groups/info_common_groups_widget.cpp @@ -22,7 +22,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "info/common_groups/info_common_groups_inner_widget.h" #include "info/info_controller.h" +#include "ui/search_field_controller.h" #include "ui/widgets/scroll_area.h" +#include "styles/style_info.h" namespace Info { namespace CommonGroups { @@ -43,6 +45,16 @@ object_ptr Memento::createWidget( return std::move(result); } +void Memento::setListState(std::unique_ptr state) { + _listState = std::move(state); +} + +std::unique_ptr Memento::listState() { + return std::move(_listState); +} + +Memento::~Memento() = default; + Widget::Widget( QWidget *parent, not_null controller, @@ -77,7 +89,7 @@ void Widget::setInternalState(const QRect &geometry, not_null memento) restoreState(memento); } -std::unique_ptr Widget::createMemento() { +std::unique_ptr Widget::doCreateMemento() { auto result = std::make_unique(user()->bareId()); saveState(result.get()); return std::move(result); @@ -92,7 +104,6 @@ void Widget::restoreState(not_null memento) { _inner->restoreState(memento); auto scrollTop = memento->scrollTop(); scrollTopRestore(memento->scrollTop()); - // TODO is setVisibleTopBottom called? } } // namespace CommonGroups diff --git a/Telegram/SourceFiles/info/common_groups/info_common_groups_widget.h b/Telegram/SourceFiles/info/common_groups/info_common_groups_widget.h index eb9955fc9..93e5e62f1 100644 --- a/Telegram/SourceFiles/info/common_groups/info_common_groups_widget.h +++ b/Telegram/SourceFiles/info/common_groups/info_common_groups_widget.h @@ -23,6 +23,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include #include "info/info_content_widget.h" +struct PeerListState; + +namespace Ui { +class SearchFieldController; +} // namespace Ui + namespace Info { namespace CommonGroups { @@ -45,7 +51,13 @@ public: return peerToUser(peerId()); } + void setListState(std::unique_ptr state); + std::unique_ptr listState(); + + ~Memento(); + private: + std::unique_ptr _listState; }; @@ -60,7 +72,6 @@ public: bool showInternal( not_null memento) override; - std::unique_ptr createMemento() override; void setInternalState( const QRect &geometry, @@ -70,6 +81,8 @@ private: void saveState(not_null memento); void restoreState(not_null memento); + std::unique_ptr doCreateMemento() override; + InnerWidget *_inner = nullptr; }; diff --git a/Telegram/SourceFiles/info/info_content_widget.cpp b/Telegram/SourceFiles/info/info_content_widget.cpp index 401958cac..daf8dfbbb 100644 --- a/Telegram/SourceFiles/info/info_content_widget.cpp +++ b/Telegram/SourceFiles/info/info_content_widget.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include #include "window/window_controller.h" #include "ui/widgets/scroll_area.h" +#include "ui/search_field_controller.h" #include "lang/lang_keys.h" #include "info/profile/info_profile_widget.h" #include "info/media/info_media_widget.h" @@ -43,6 +44,8 @@ ContentWidget::ContentWidget( : RpWidget(parent) , _controller(controller) , _scroll(this, st::infoScroll) { + using namespace rpl::mappers; + setAttribute(Qt::WA_OpaquePaintEvent); _controller->wrapValue() | rpl::start_with_next([this](Wrap value) { @@ -51,6 +54,13 @@ ContentWidget::ContentWidget( : st::profileBg; update(); }, lifetime()); + rpl::combine( + _controller->wrapValue(), + _controller->searchEnabledByContent(), + ($1 == Wrap::Layer) && $2) + | rpl::start_with_next([this](bool shown) { + refreshSearchField(shown); + }, lifetime()); _scrollTopSkip.changes() | rpl::start_with_next([this] { updateControlsGeometry(); @@ -62,6 +72,9 @@ void ContentWidget::resizeEvent(QResizeEvent *e) { } void ContentWidget::updateControlsGeometry() { + if (!_inner) { + return; + } auto newScrollTop = _scroll->scrollTop() + _topDelta; auto scrollGeometry = rect().marginsRemoved( QMargins(0, _scrollTopSkip.current(), 0, 0)); @@ -75,10 +88,18 @@ void ContentWidget::updateControlsGeometry() { _scroll->scrollToY(newScrollTop); } auto scrollTop = _scroll->scrollTop(); - _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); + _inner->setVisibleTopBottom( + scrollTop, + scrollTop + _scroll->height()); } } +std::unique_ptr ContentWidget::createMemento() { + auto result = doCreateMemento(); + _controller->saveSearchState(result.get()); + return result; +} + void ContentWidget::paintEvent(QPaintEvent *e) { Painter p(this); p.fillRect(e->rect(), _bg); @@ -100,8 +121,7 @@ void ContentWidget::setGeometryWithTopMoved( } Ui::RpWidget *ContentWidget::doSetInnerWidget( - object_ptr inner, - int scrollTopSkip) { + object_ptr inner) { using namespace rpl::mappers; _inner = _scroll->setOwnedWidget(std::move(inner)); @@ -119,8 +139,6 @@ Ui::RpWidget *ContentWidget::doSetInnerWidget( inner->setVisibleTopBottom(top, bottom); }, _inner->lifetime()); - setScrollTopSkip(scrollTopSkip); - return _inner; } @@ -176,4 +194,24 @@ rpl::producer ContentWidget::selectedListValue() const { return rpl::single(SelectedItems(Storage::SharedMediaType::Photo)); } +void ContentWidget::refreshSearchField(bool shown) { + auto search = _controller->searchFieldController(); + if (search && shown) { + _searchField = search->createRowView( + this, + st::infoLayerMediaSearch); + auto field = _searchField.get(); + widthValue() + | rpl::start_with_next([field](int newWidth) { + field->resizeToWidth(newWidth); + field->moveToLeft(0, 0); + }, field->lifetime()); + field->show(); + setScrollTopSkip(field->heightNoMargins() - st::lineWidth); + } else { + _searchField = nullptr; + setScrollTopSkip(0); + } +} + } // namespace Info diff --git a/Telegram/SourceFiles/info/info_content_widget.h b/Telegram/SourceFiles/info/info_content_widget.h index 411d136f5..4ac7ec6cb 100644 --- a/Telegram/SourceFiles/info/info_content_widget.h +++ b/Telegram/SourceFiles/info/info_content_widget.h @@ -46,7 +46,7 @@ public: virtual bool showInternal( not_null memento) = 0; - virtual std::unique_ptr createMemento() = 0; + std::unique_ptr createMemento(); virtual rpl::producer
sectionRequest() const; virtual void setIsStackBottom(bool isStackBottom) { @@ -77,11 +77,9 @@ public: protected: template - Widget *setInnerWidget( - object_ptr inner, - int scrollTopSkip = 0) { + Widget *setInnerWidget(object_ptr inner) { return static_cast( - doSetInnerWidget(std::move(inner), scrollTopSkip)); + doSetInnerWidget(std::move(inner))); } not_null controller() const { @@ -97,10 +95,11 @@ protected: void scrollTo(const Ui::ScrollToRequest &request); private: - RpWidget *doSetInnerWidget( - object_ptr inner, - int scrollTopSkip); + RpWidget *doSetInnerWidget(object_ptr inner); void updateControlsGeometry(); + void refreshSearchField(bool shown); + + virtual std::unique_ptr doCreateMemento() = 0; const not_null _controller; @@ -108,6 +107,7 @@ private: rpl::variable _scrollTopSkip = -1; object_ptr _scroll; Ui::RpWidget *_inner = nullptr; + base::unique_qptr _searchField = nullptr; // Saving here topDelta in setGeometryWithTopMoved() to get it passed to resizeEvent(). int _topDelta = 0; @@ -149,12 +149,19 @@ public: QString searchFieldQuery() const { return _searchFieldQuery; } + void setSearchEnabledByContent(bool enabled) { + _searchEnabledByContent = enabled; + } + bool searchEnabledByContent() const { + return _searchEnabledByContent; + } private: const PeerId _peerId = 0; const PeerId _migratedPeerId = 0; int _scrollTop = 0; QString _searchFieldQuery; + bool _searchEnabledByContent = false; }; diff --git a/Telegram/SourceFiles/info/info_controller.cpp b/Telegram/SourceFiles/info/info_controller.cpp index c482e25b2..4c8129255 100644 --- a/Telegram/SourceFiles/info/info_controller.cpp +++ b/Telegram/SourceFiles/info/info_controller.cpp @@ -85,8 +85,8 @@ void Controller::updateSearchControllers( : Section::MediaType::kCount; auto hasMediaSearch = isMedia && SharedMediaAllowSearch(mediaType); -// auto hasCommonGroupsSearch -// = (_section.type() == Section::Type::CommonGroups); + auto hasCommonGroupsSearch + = (_section.type() == Section::Type::CommonGroups); auto searchQuery = memento->searchFieldQuery(); if (isMedia) { _searchController @@ -98,15 +98,18 @@ void Controller::updateSearchControllers( } else { _searchController = nullptr; } - if (hasMediaSearch) { + if (hasMediaSearch || hasCommonGroupsSearch) { _searchFieldController = std::make_unique( searchQuery); - _searchFieldController->queryValue() - | rpl::start_with_next([=](QString &&query) { - _searchController->setQuery( - produceSearchQuery(std::move(query))); - }, _searchFieldController->lifetime()); + if (_searchController) { + _searchFieldController->queryValue() + | rpl::start_with_next([=](QString &&query) { + _searchController->setQuery( + produceSearchQuery(std::move(query))); + }, _searchFieldController->lifetime()); + } + _seachEnabledByContent = memento->searchEnabledByContent(); } else { _searchFieldController = nullptr; } @@ -116,6 +119,8 @@ void Controller::saveSearchState(not_null memento) { if (_searchFieldController) { memento->setSearchFieldQuery( _searchFieldController->query()); + memento->setSearchEnabledByContent( + _seachEnabledByContent.current()); } if (_searchController) { auto mediaMemento = dynamic_cast( diff --git a/Telegram/SourceFiles/info/info_controller.h b/Telegram/SourceFiles/info/info_controller.h index e4bd45dd7..2ae7d070d 100644 --- a/Telegram/SourceFiles/info/info_controller.h +++ b/Telegram/SourceFiles/info/info_controller.h @@ -106,6 +106,12 @@ public: Ui::SearchFieldController *searchFieldController() const { return _searchFieldController.get(); } + void setSearchEnabledByContent(bool enabled) { + _seachEnabledByContent = enabled; + } + rpl::producer searchEnabledByContent() const { + return _seachEnabledByContent.value(); + } rpl::producer mediaSource( SparseIdsMergedSlice::UniversalMsgId aroundId, int limitBefore, @@ -137,6 +143,7 @@ private: std::unique_ptr _searchFieldController; std::unique_ptr _searchController; + rpl::variable _seachEnabledByContent = false; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/info/info_memento.cpp b/Telegram/SourceFiles/info/info_memento.cpp index 7313ca73d..ab45ee921 100644 --- a/Telegram/SourceFiles/info/info_memento.cpp +++ b/Telegram/SourceFiles/info/info_memento.cpp @@ -34,11 +34,19 @@ Memento::Memento(PeerId peerId) } Memento::Memento(PeerId peerId, Section section) -: Memento(Default(peerId, section)) { +: Memento(DefaultStack(peerId, section)) { } -Memento::Memento(std::unique_ptr content) -: _content(std::move(content)) { +Memento::Memento(std::vector> stack) +: _stack(std::move(stack)) { +} + +std::vector> Memento::DefaultStack( + PeerId peerId, + Section section) { + auto result = std::vector>(); + result.push_back(Default(peerId, section)); + return result; } std::unique_ptr Memento::Default( @@ -98,8 +106,8 @@ object_ptr Memento::createLayer( return nullptr; } -void Memento::setInner(std::unique_ptr content) { - _content = std::move(content); +std::vector> Memento::takeStack() { + return std::move(_stack); } Memento::~Memento() = default; diff --git a/Telegram/SourceFiles/info/info_memento.h b/Telegram/SourceFiles/info/info_memento.h index b4fef5be0..34782db8f 100644 --- a/Telegram/SourceFiles/info/info_memento.h +++ b/Telegram/SourceFiles/info/info_memento.h @@ -42,7 +42,7 @@ class Memento final : public Window::SectionMemento { public: Memento(PeerId peerId); Memento(PeerId peerId, Section section); - Memento(std::unique_ptr content); + Memento(std::vector> stack); object_ptr createWidget( QWidget *parent, @@ -54,19 +54,27 @@ public: not_null controller, const QRect &geometry) override; - void setInner(std::unique_ptr content); + int stackSize() const { + return int(_stack.size()); + } + std::vector> takeStack(); + not_null content() { - return _content.get(); + Expects(!_stack.empty()); + return _stack.back().get(); } ~Memento(); private: + static std::vector> DefaultStack( + PeerId peerId, + Section section); static std::unique_ptr Default( PeerId peerId, Section section); - std::unique_ptr _content; + std::vector> _stack; }; diff --git a/Telegram/SourceFiles/info/info_top_bar.cpp b/Telegram/SourceFiles/info/info_top_bar.cpp index fce249409..8301a1b8b 100644 --- a/Telegram/SourceFiles/info/info_top_bar.cpp +++ b/Telegram/SourceFiles/info/info_top_bar.cpp @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #include "info/info_top_bar.h" +#include #include "styles/style_info.h" #include "lang/lang_keys.h" #include "info/info_wrap_widget.h" @@ -64,10 +65,11 @@ void TopBar::enableBackButton(bool enable) { } void TopBar::createSearchView( - not_null controller) { - setSearchField(controller->createField( - this, - _st.searchRow.field)); + not_null controller, + rpl::producer &&shown) { + setSearchField( + controller->createField(this, _st.searchRow.field), + std::move(shown)); } void TopBar::pushButton(base::unique_qptr button) { @@ -81,15 +83,18 @@ void TopBar::pushButton(base::unique_qptr button) { } void TopBar::setSearchField( - base::unique_qptr field) { + base::unique_qptr field, + rpl::producer &&shown) { if (auto value = field.release()) { - createSearchView(value); + createSearchView(value, std::move(shown)); } else { _searchView = nullptr; } } -void TopBar::createSearchView(not_null field) { +void TopBar::createSearchView( + not_null field, + rpl::producer &&shown) { _searchView = base::make_unique_q( this, _st.searchRow.height); @@ -162,12 +167,22 @@ void TopBar::createSearchView(not_null field) { | rpl::start_with_done([=] { field->setParent(nullptr); removeButton(search); - setSearchField(nullptr); + setSearchField(nullptr, rpl::never()); }, _searchView->lifetime()); toggleSearchMode( !field->getLastText().isEmpty(), anim::type::instant); + + std::move(shown) + | rpl::start_with_next([=](bool visible) { + if (!field->getLastText().isEmpty()) { + return; + } + toggleSearchMode(false, anim::type::instant); + wrap->setVisible(visible); + search->toggle(visible, anim::type::instant); + }, wrap->lifetime()); } void TopBar::removeButton(not_null button) { diff --git a/Telegram/SourceFiles/info/info_top_bar.h b/Telegram/SourceFiles/info/info_top_bar.h index 0a287e2e7..3ed3fb724 100644 --- a/Telegram/SourceFiles/info/info_top_bar.h +++ b/Telegram/SourceFiles/info/info_top_bar.h @@ -60,7 +60,8 @@ public: } void createSearchView( - not_null controller); + not_null controller, + rpl::producer &&shown); protected: int resizeGetHeight(int newWidth) override; @@ -71,8 +72,12 @@ private: void pushButton(base::unique_qptr button); void removeButton(not_null button); - void setSearchField(base::unique_qptr field); - void createSearchView(not_null field); + void setSearchField( + base::unique_qptr field, + rpl::producer &&shown); + void createSearchView( + not_null field, + rpl::producer &&shown); const style::InfoTopBar &_st; object_ptr _back = { nullptr }; diff --git a/Telegram/SourceFiles/info/info_wrap_widget.cpp b/Telegram/SourceFiles/info/info_wrap_widget.cpp index f272d0eaa..27f30b0bd 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.cpp +++ b/Telegram/SourceFiles/info/info_wrap_widget.cpp @@ -78,7 +78,24 @@ WrapWidget::WrapWidget( refreshTopBarOverride(std::move(items)); }); }, lifetime()); - showNewContent(memento->content()); + restoreHistoryStack(memento->takeStack()); +} + +void WrapWidget::restoreHistoryStack( + std::vector> stack) { + Expects(!stack.empty()); + Expects(_historyStack.empty()); + auto content = std::move(stack.back()); + stack.pop_back(); + if (!stack.empty()) { + _historyStack.reserve(stack.size()); + for (auto &stackItem : stack) { + auto item = StackItem(); + item.section = std::move(stackItem); + _historyStack.push_back(std::move(item)); + } + } + showNewContent(content.get()); } std::unique_ptr WrapWidget::createController( @@ -232,7 +249,9 @@ void WrapWidget::createTopBar() { } else if (requireTopBarSearch()) { auto search = _controller->searchFieldController(); Assert(search != nullptr); - _topBar->createSearchView(search); + _topBar->createSearchView( + search, + _controller->searchEnabledByContent()); } _topBar->move(0, 0); @@ -469,6 +488,9 @@ bool WrapWidget::showInternal( not_null memento, const Window::SectionShow ¶ms) { if (auto infoMemento = dynamic_cast(memento.get())) { + if (infoMemento->stackSize() > 1) { + return false; + } auto content = infoMemento->content(); if (_controller->validateMementoPeer(content)) { if (_content->showInternal(content)) { @@ -484,7 +506,13 @@ bool WrapWidget::showInternal( } std::unique_ptr WrapWidget::createMemento() { - return std::make_unique(_content->createMemento()); + auto stack = std::vector>(); + stack.reserve(_historyStack.size() + 1); + for (auto &stackItem : _historyStack) { + stack.push_back(std::move(stackItem.section)); + } + stack.push_back(_content->createMemento()); + return std::make_unique(std::move(stack)); } rpl::producer WrapWidget::desiredHeightValue() const { diff --git a/Telegram/SourceFiles/info/info_wrap_widget.h b/Telegram/SourceFiles/info/info_wrap_widget.h index ec02de710..fb61dfba6 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.h +++ b/Telegram/SourceFiles/info/info_wrap_widget.h @@ -142,6 +142,8 @@ private: }; struct StackItem; + void restoreHistoryStack( + std::vector> stack); void showBackFromStack(); void showNewContent(not_null memento); void showNewContent( diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp index 1222336d3..5ee9aa5c2 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp @@ -58,6 +58,12 @@ void InnerWidget::setupOtherTypes() { _otherTypes.destroy(); refreshHeight(); } + }, lifetime()); + rpl::combine( + _controller->wrapValue(), + _controller->searchEnabledByContent()) + | rpl::start_with_next([this](Wrap wrap, bool enabled) { + _searchEnabled = enabled; refreshSearchField(); }, lifetime()); } @@ -204,7 +210,7 @@ void InnerWidget::switchToTab(Memento &&memento) { void InnerWidget::refreshSearchField() { auto search = _controller->searchFieldController(); - if (search && _otherTabs) { + if (search && _otherTabs && _searchEnabled) { _searchField = search->createRowView( this, st::infoMediaSearch); @@ -216,7 +222,6 @@ void InnerWidget::refreshSearchField() { } object_ptr InnerWidget::setupList() { - refreshSearchField(); auto result = object_ptr( this, _controller); diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.h b/Telegram/SourceFiles/info/media/info_media_inner_widget.h index f47ac389f..8ceec3fd9 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.h @@ -86,6 +86,7 @@ private: object_ptr _otherTabsShadow = { nullptr }; base::unique_qptr _searchField = nullptr; object_ptr _list = { nullptr }; + bool _searchEnabled = false; bool _inResize = false; diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 05d42d24f..eb683aa59 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -49,6 +49,7 @@ constexpr auto kPreloadedScreensCount = 4; constexpr auto kPreloadIfLessThanScreens = 2; constexpr auto kPreloadedScreensCountFull = kPreloadedScreensCount + 1 + kPreloadedScreensCount; +constexpr auto kMediaCountForSearch = 10; UniversalMsgId GetUniversalId(FullMsgId itemId) { return (itemId.channel != 0) @@ -552,6 +553,7 @@ ListWidget::ListWidget( } void ListWidget::start() { + _controller->setSearchEnabledByContent(false); ObservableViewer(*Window::Theme::Background()) | rpl::start_with_next([this](const auto &update) { if (update.paletteChanged()) { @@ -889,6 +891,10 @@ void ListWidget::refreshRows() { _sections.push_back(std::move(section)); } + if (_layouts.size() > kMediaCountForSearch) { + _controller->setSearchEnabledByContent(true); + } + clearStaleLayouts(); resizeToWidth(width()); diff --git a/Telegram/SourceFiles/info/media/info_media_widget.cpp b/Telegram/SourceFiles/info/media/info_media_widget.cpp index 981b9aa26..a0c685157 100644 --- a/Telegram/SourceFiles/info/media/info_media_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_widget.cpp @@ -91,10 +91,6 @@ Widget::Widget( | rpl::start_with_next([this](int skip) { scrollTo({ skip, -1 }); }, _inner->lifetime()); - controller->wrapValue() - | rpl::start_with_next([this] { - refreshSearchField(); - }, lifetime()); } rpl::producer Widget::selectedListValue() const { @@ -123,14 +119,13 @@ void Widget::setInternalState(const QRect &geometry, not_null memento) restoreState(memento); } -std::unique_ptr Widget::createMemento() { +std::unique_ptr Widget::doCreateMemento() { auto result = std::make_unique(controller()); saveState(result.get()); return std::move(result); } void Widget::saveState(not_null memento) { - controller()->saveSearchState(memento); _inner->saveState(memento); } @@ -138,25 +133,5 @@ void Widget::restoreState(not_null memento) { _inner->restoreState(memento); } -void Widget::refreshSearchField() { - auto search = controller()->searchFieldController(); - if (search && controller()->wrap() == Wrap::Layer) { - _searchField = search->createRowView( - this, - st::infoLayerMediaSearch); - auto field = _searchField.get(); - widthValue() - | rpl::start_with_next([field](int newWidth) { - field->resizeToWidth(newWidth); - field->moveToLeft(0, 0); - }, field->lifetime()); - field->show(); - setScrollTopSkip(field->heightNoMargins() - st::lineWidth); - } else { - _searchField = nullptr; - setScrollTopSkip(0); - } -} - } // namespace Media } // namespace Info diff --git a/Telegram/SourceFiles/info/media/info_media_widget.h b/Telegram/SourceFiles/info/media/info_media_widget.h index 5bc928516..4041a2349 100644 --- a/Telegram/SourceFiles/info/media/info_media_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_widget.h @@ -106,7 +106,6 @@ public: bool showInternal( not_null memento) override; - std::unique_ptr createMemento() override; void setInternalState( const QRect &geometry, @@ -119,10 +118,9 @@ private: void saveState(not_null memento); void restoreState(not_null memento); - void refreshSearchField(); + std::unique_ptr doCreateMemento() override; InnerWidget *_inner = nullptr; - base::unique_qptr _searchField = nullptr; }; diff --git a/Telegram/SourceFiles/info/profile/info_profile_members.cpp b/Telegram/SourceFiles/info/profile/info_profile_members.cpp index 19fa9fe5e..d6414eec9 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_members.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_members.cpp @@ -43,7 +43,7 @@ namespace Info { namespace Profile { namespace { -constexpr auto kEnableSearchMembersAfterCount = 50; +constexpr auto kEnableSearchMembersAfterCount = 20; } // namespace diff --git a/Telegram/SourceFiles/info/profile/info_profile_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_widget.cpp index bb09458da..853118482 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_widget.cpp @@ -92,7 +92,7 @@ void Widget::setInternalState(const QRect &geometry, not_null memento) restoreState(memento); } -std::unique_ptr Widget::createMemento() { +std::unique_ptr Widget::doCreateMemento() { auto result = std::make_unique(controller()); saveState(result.get()); return std::move(result); diff --git a/Telegram/SourceFiles/info/profile/info_profile_widget.h b/Telegram/SourceFiles/info/profile/info_profile_widget.h index 0a129826c..2b7e88384 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_widget.h +++ b/Telegram/SourceFiles/info/profile/info_profile_widget.h @@ -79,7 +79,6 @@ public: bool showInternal( not_null memento) override; - std::unique_ptr createMemento() override; void setInternalState( const QRect &geometry, @@ -91,6 +90,8 @@ private: void saveState(not_null memento); void restoreState(not_null memento); + std::unique_ptr doCreateMemento() override; + InnerWidget *_inner = nullptr; };