mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Search and save state in common groups.
This commit is contained in:
parent
a6361d6221
commit
628c8e10f7
22 changed files with 290 additions and 85 deletions
|
@ -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<PeerListRow*> row) override;
|
||||
void loadMoreRows() override;
|
||||
|
||||
std::unique_ptr<PeerListRow> createRestoredRow(
|
||||
not_null<PeerData*> peer) override {
|
||||
return createRow(peer);
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerListState> saveState() override;
|
||||
void restoreState(std::unique_ptr<PeerListState> state) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<PeerListRow> createRow(not_null<PeerData*> peer);
|
||||
|
||||
struct SavedState : SavedStateBase {
|
||||
int32 preloadGroupId = 0;
|
||||
bool allLoaded = false;
|
||||
bool wasLoading = false;
|
||||
};
|
||||
const not_null<Controller*> _controller;
|
||||
not_null<UserData*> _user;
|
||||
mtpRequestId _preloadRequestId = 0;
|
||||
|
@ -64,6 +81,14 @@ ListController::ListController(
|
|||
: PeerListController()
|
||||
, _controller(controller)
|
||||
, _user(user) {
|
||||
_controller->setSearchEnabledByContent(false);
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerListRow> ListController::createRow(
|
||||
not_null<PeerData*> peer) {
|
||||
auto result = std::make_unique<PeerListRow>(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<PeerListRow>(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<PeerListState> ListController::saveState() {
|
||||
auto result = PeerListController::saveState();
|
||||
auto my = std::make_unique<SavedState>();
|
||||
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<PeerListState> state) {
|
||||
auto typeErasedState = state
|
||||
? state->controllerState.get()
|
||||
: nullptr;
|
||||
if (auto my = dynamic_cast<SavedState*>(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<PeerListRow*> row) {
|
||||
_controller->window()->showPeerHistory(
|
||||
row->peer(),
|
||||
|
@ -117,11 +180,17 @@ InnerWidget::InnerWidget(
|
|||
not_null<Controller*> controller,
|
||||
not_null<UserData*> user)
|
||||
: RpWidget(parent)
|
||||
, _controller(controller)
|
||||
, _user(user)
|
||||
, _listController(std::make_unique<ListController>(controller, _user))
|
||||
, _list(setupList(this, _listController.get())) {
|
||||
setContent(_list.data());
|
||||
_listController->setDelegate(static_cast<PeerListDelegate*>(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) {
|
||||
memento->setListState(_listController->saveState());
|
||||
}
|
||||
|
||||
void InnerWidget::restoreState(not_null<Memento*> memento) {
|
||||
_listController->restoreState(std::move(memento->listState()));
|
||||
}
|
||||
|
||||
int InnerWidget::desiredHeight() const {
|
||||
|
|
|
@ -80,6 +80,7 @@ private:
|
|||
RpWidget *parent,
|
||||
not_null<PeerListController*> controller) const;
|
||||
|
||||
not_null<Controller*> _controller;
|
||||
not_null<UserData*> _user;
|
||||
std::unique_ptr<PeerListController> _listController;
|
||||
object_ptr<ListWidget> _list;
|
||||
|
|
|
@ -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<ContentWidget> Memento::createWidget(
|
|||
return std::move(result);
|
||||
}
|
||||
|
||||
void Memento::setListState(std::unique_ptr<PeerListState> state) {
|
||||
_listState = std::move(state);
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerListState> Memento::listState() {
|
||||
return std::move(_listState);
|
||||
}
|
||||
|
||||
Memento::~Memento() = default;
|
||||
|
||||
Widget::Widget(
|
||||
QWidget *parent,
|
||||
not_null<Controller*> controller,
|
||||
|
@ -77,7 +89,7 @@ void Widget::setInternalState(const QRect &geometry, not_null<Memento*> memento)
|
|||
restoreState(memento);
|
||||
}
|
||||
|
||||
std::unique_ptr<ContentMemento> Widget::createMemento() {
|
||||
std::unique_ptr<ContentMemento> Widget::doCreateMemento() {
|
||||
auto result = std::make_unique<Memento>(user()->bareId());
|
||||
saveState(result.get());
|
||||
return std::move(result);
|
||||
|
@ -92,7 +104,6 @@ void Widget::restoreState(not_null<Memento*> memento) {
|
|||
_inner->restoreState(memento);
|
||||
auto scrollTop = memento->scrollTop();
|
||||
scrollTopRestore(memento->scrollTop());
|
||||
// TODO is setVisibleTopBottom called?
|
||||
}
|
||||
|
||||
} // namespace CommonGroups
|
||||
|
|
|
@ -23,6 +23,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include <rpl/producer.h>
|
||||
#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<PeerListState> state);
|
||||
std::unique_ptr<PeerListState> listState();
|
||||
|
||||
~Memento();
|
||||
|
||||
private:
|
||||
std::unique_ptr<PeerListState> _listState;
|
||||
|
||||
};
|
||||
|
||||
|
@ -60,7 +72,6 @@ public:
|
|||
|
||||
bool showInternal(
|
||||
not_null<ContentMemento*> memento) override;
|
||||
std::unique_ptr<ContentMemento> createMemento() override;
|
||||
|
||||
void setInternalState(
|
||||
const QRect &geometry,
|
||||
|
@ -70,6 +81,8 @@ private:
|
|||
void saveState(not_null<Memento*> memento);
|
||||
void restoreState(not_null<Memento*> memento);
|
||||
|
||||
std::unique_ptr<ContentMemento> doCreateMemento() override;
|
||||
|
||||
InnerWidget *_inner = nullptr;
|
||||
|
||||
};
|
||||
|
|
|
@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include <rpl/range.h>
|
||||
#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<ContentMemento> 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<RpWidget> inner,
|
||||
int scrollTopSkip) {
|
||||
object_ptr<RpWidget> 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<SelectedItems> 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
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
|
||||
virtual bool showInternal(
|
||||
not_null<ContentMemento*> memento) = 0;
|
||||
virtual std::unique_ptr<ContentMemento> createMemento() = 0;
|
||||
std::unique_ptr<ContentMemento> createMemento();
|
||||
|
||||
virtual rpl::producer<Section> sectionRequest() const;
|
||||
virtual void setIsStackBottom(bool isStackBottom) {
|
||||
|
@ -77,11 +77,9 @@ public:
|
|||
|
||||
protected:
|
||||
template <typename Widget>
|
||||
Widget *setInnerWidget(
|
||||
object_ptr<Widget> inner,
|
||||
int scrollTopSkip = 0) {
|
||||
Widget *setInnerWidget(object_ptr<Widget> inner) {
|
||||
return static_cast<Widget*>(
|
||||
doSetInnerWidget(std::move(inner), scrollTopSkip));
|
||||
doSetInnerWidget(std::move(inner)));
|
||||
}
|
||||
|
||||
not_null<Controller*> controller() const {
|
||||
|
@ -97,10 +95,11 @@ protected:
|
|||
void scrollTo(const Ui::ScrollToRequest &request);
|
||||
|
||||
private:
|
||||
RpWidget *doSetInnerWidget(
|
||||
object_ptr<RpWidget> inner,
|
||||
int scrollTopSkip);
|
||||
RpWidget *doSetInnerWidget(object_ptr<RpWidget> inner);
|
||||
void updateControlsGeometry();
|
||||
void refreshSearchField(bool shown);
|
||||
|
||||
virtual std::unique_ptr<ContentMemento> doCreateMemento() = 0;
|
||||
|
||||
const not_null<Controller*> _controller;
|
||||
|
||||
|
@ -108,6 +107,7 @@ private:
|
|||
rpl::variable<int> _scrollTopSkip = -1;
|
||||
object_ptr<Ui::ScrollArea> _scroll;
|
||||
Ui::RpWidget *_inner = nullptr;
|
||||
base::unique_qptr<Ui::RpWidget> _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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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<Ui::SearchFieldController>(
|
||||
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<ContentMemento*> memento) {
|
|||
if (_searchFieldController) {
|
||||
memento->setSearchFieldQuery(
|
||||
_searchFieldController->query());
|
||||
memento->setSearchEnabledByContent(
|
||||
_seachEnabledByContent.current());
|
||||
}
|
||||
if (_searchController) {
|
||||
auto mediaMemento = dynamic_cast<Media::Memento*>(
|
||||
|
|
|
@ -106,6 +106,12 @@ public:
|
|||
Ui::SearchFieldController *searchFieldController() const {
|
||||
return _searchFieldController.get();
|
||||
}
|
||||
void setSearchEnabledByContent(bool enabled) {
|
||||
_seachEnabledByContent = enabled;
|
||||
}
|
||||
rpl::producer<bool> searchEnabledByContent() const {
|
||||
return _seachEnabledByContent.value();
|
||||
}
|
||||
rpl::producer<SparseIdsMergedSlice> mediaSource(
|
||||
SparseIdsMergedSlice::UniversalMsgId aroundId,
|
||||
int limitBefore,
|
||||
|
@ -137,6 +143,7 @@ private:
|
|||
|
||||
std::unique_ptr<Ui::SearchFieldController> _searchFieldController;
|
||||
std::unique_ptr<Api::DelayedSearchController> _searchController;
|
||||
rpl::variable<bool> _seachEnabledByContent = false;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
|
|
|
@ -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<ContentMemento> content)
|
||||
: _content(std::move(content)) {
|
||||
Memento::Memento(std::vector<std::unique_ptr<ContentMemento>> stack)
|
||||
: _stack(std::move(stack)) {
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<ContentMemento>> Memento::DefaultStack(
|
||||
PeerId peerId,
|
||||
Section section) {
|
||||
auto result = std::vector<std::unique_ptr<ContentMemento>>();
|
||||
result.push_back(Default(peerId, section));
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<ContentMemento> Memento::Default(
|
||||
|
@ -98,8 +106,8 @@ object_ptr<Window::LayerWidget> Memento::createLayer(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void Memento::setInner(std::unique_ptr<ContentMemento> content) {
|
||||
_content = std::move(content);
|
||||
std::vector<std::unique_ptr<ContentMemento>> Memento::takeStack() {
|
||||
return std::move(_stack);
|
||||
}
|
||||
|
||||
Memento::~Memento() = default;
|
||||
|
|
|
@ -42,7 +42,7 @@ class Memento final : public Window::SectionMemento {
|
|||
public:
|
||||
Memento(PeerId peerId);
|
||||
Memento(PeerId peerId, Section section);
|
||||
Memento(std::unique_ptr<ContentMemento> content);
|
||||
Memento(std::vector<std::unique_ptr<ContentMemento>> stack);
|
||||
|
||||
object_ptr<Window::SectionWidget> createWidget(
|
||||
QWidget *parent,
|
||||
|
@ -54,19 +54,27 @@ public:
|
|||
not_null<Window::Controller*> controller,
|
||||
const QRect &geometry) override;
|
||||
|
||||
void setInner(std::unique_ptr<ContentMemento> content);
|
||||
int stackSize() const {
|
||||
return int(_stack.size());
|
||||
}
|
||||
std::vector<std::unique_ptr<ContentMemento>> takeStack();
|
||||
|
||||
not_null<ContentMemento*> content() {
|
||||
return _content.get();
|
||||
Expects(!_stack.empty());
|
||||
return _stack.back().get();
|
||||
}
|
||||
|
||||
~Memento();
|
||||
|
||||
private:
|
||||
static std::vector<std::unique_ptr<ContentMemento>> DefaultStack(
|
||||
PeerId peerId,
|
||||
Section section);
|
||||
static std::unique_ptr<ContentMemento> Default(
|
||||
PeerId peerId,
|
||||
Section section);
|
||||
|
||||
std::unique_ptr<ContentMemento> _content;
|
||||
std::vector<std::unique_ptr<ContentMemento>> _stack;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
*/
|
||||
#include "info/info_top_bar.h"
|
||||
|
||||
#include <rpl/never.h>
|
||||
#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<Ui::SearchFieldController*> controller) {
|
||||
setSearchField(controller->createField(
|
||||
this,
|
||||
_st.searchRow.field));
|
||||
not_null<Ui::SearchFieldController*> controller,
|
||||
rpl::producer<bool> &&shown) {
|
||||
setSearchField(
|
||||
controller->createField(this, _st.searchRow.field),
|
||||
std::move(shown));
|
||||
}
|
||||
|
||||
void TopBar::pushButton(base::unique_qptr<Ui::RpWidget> button) {
|
||||
|
@ -81,15 +83,18 @@ void TopBar::pushButton(base::unique_qptr<Ui::RpWidget> button) {
|
|||
}
|
||||
|
||||
void TopBar::setSearchField(
|
||||
base::unique_qptr<Ui::InputField> field) {
|
||||
base::unique_qptr<Ui::InputField> field,
|
||||
rpl::producer<bool> &&shown) {
|
||||
if (auto value = field.release()) {
|
||||
createSearchView(value);
|
||||
createSearchView(value, std::move(shown));
|
||||
} else {
|
||||
_searchView = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void TopBar::createSearchView(not_null<Ui::InputField*> field) {
|
||||
void TopBar::createSearchView(
|
||||
not_null<Ui::InputField*> field,
|
||||
rpl::producer<bool> &&shown) {
|
||||
_searchView = base::make_unique_q<Ui::FixedHeightWidget>(
|
||||
this,
|
||||
_st.searchRow.height);
|
||||
|
@ -162,12 +167,22 @@ void TopBar::createSearchView(not_null<Ui::InputField*> field) {
|
|||
| rpl::start_with_done([=] {
|
||||
field->setParent(nullptr);
|
||||
removeButton(search);
|
||||
setSearchField(nullptr);
|
||||
setSearchField(nullptr, rpl::never<bool>());
|
||||
}, _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<Ui::RpWidget*> button) {
|
||||
|
|
|
@ -60,7 +60,8 @@ public:
|
|||
}
|
||||
|
||||
void createSearchView(
|
||||
not_null<Ui::SearchFieldController*> controller);
|
||||
not_null<Ui::SearchFieldController*> controller,
|
||||
rpl::producer<bool> &&shown);
|
||||
|
||||
protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
@ -71,8 +72,12 @@ private:
|
|||
void pushButton(base::unique_qptr<Ui::RpWidget> button);
|
||||
void removeButton(not_null<Ui::RpWidget*> button);
|
||||
|
||||
void setSearchField(base::unique_qptr<Ui::InputField> field);
|
||||
void createSearchView(not_null<Ui::InputField*> field);
|
||||
void setSearchField(
|
||||
base::unique_qptr<Ui::InputField> field,
|
||||
rpl::producer<bool> &&shown);
|
||||
void createSearchView(
|
||||
not_null<Ui::InputField*> field,
|
||||
rpl::producer<bool> &&shown);
|
||||
|
||||
const style::InfoTopBar &_st;
|
||||
object_ptr<Ui::IconButton> _back = { nullptr };
|
||||
|
|
|
@ -78,7 +78,24 @@ WrapWidget::WrapWidget(
|
|||
refreshTopBarOverride(std::move(items));
|
||||
});
|
||||
}, lifetime());
|
||||
showNewContent(memento->content());
|
||||
restoreHistoryStack(memento->takeStack());
|
||||
}
|
||||
|
||||
void WrapWidget::restoreHistoryStack(
|
||||
std::vector<std::unique_ptr<ContentMemento>> 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<Controller> 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<Window::SectionMemento*> memento,
|
||||
const Window::SectionShow ¶ms) {
|
||||
if (auto infoMemento = dynamic_cast<Memento*>(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<Window::SectionMemento> WrapWidget::createMemento() {
|
||||
return std::make_unique<Memento>(_content->createMemento());
|
||||
auto stack = std::vector<std::unique_ptr<ContentMemento>>();
|
||||
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<Memento>(std::move(stack));
|
||||
}
|
||||
|
||||
rpl::producer<int> WrapWidget::desiredHeightValue() const {
|
||||
|
|
|
@ -142,6 +142,8 @@ private:
|
|||
};
|
||||
struct StackItem;
|
||||
|
||||
void restoreHistoryStack(
|
||||
std::vector<std::unique_ptr<ContentMemento>> stack);
|
||||
void showBackFromStack();
|
||||
void showNewContent(not_null<ContentMemento*> memento);
|
||||
void showNewContent(
|
||||
|
|
|
@ -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<ListWidget> InnerWidget::setupList() {
|
||||
refreshSearchField();
|
||||
auto result = object_ptr<ListWidget>(
|
||||
this,
|
||||
_controller);
|
||||
|
|
|
@ -86,6 +86,7 @@ private:
|
|||
object_ptr<Ui::PlainShadow> _otherTabsShadow = { nullptr };
|
||||
base::unique_qptr<Ui::RpWidget> _searchField = nullptr;
|
||||
object_ptr<ListWidget> _list = { nullptr };
|
||||
bool _searchEnabled = false;
|
||||
|
||||
bool _inResize = false;
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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<SelectedItems> Widget::selectedListValue() const {
|
||||
|
@ -123,14 +119,13 @@ void Widget::setInternalState(const QRect &geometry, not_null<Memento*> memento)
|
|||
restoreState(memento);
|
||||
}
|
||||
|
||||
std::unique_ptr<ContentMemento> Widget::createMemento() {
|
||||
std::unique_ptr<ContentMemento> Widget::doCreateMemento() {
|
||||
auto result = std::make_unique<Memento>(controller());
|
||||
saveState(result.get());
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
void Widget::saveState(not_null<Memento*> memento) {
|
||||
controller()->saveSearchState(memento);
|
||||
_inner->saveState(memento);
|
||||
}
|
||||
|
||||
|
@ -138,25 +133,5 @@ void Widget::restoreState(not_null<Memento*> 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
|
||||
|
|
|
@ -106,7 +106,6 @@ public:
|
|||
|
||||
bool showInternal(
|
||||
not_null<ContentMemento*> memento) override;
|
||||
std::unique_ptr<ContentMemento> createMemento() override;
|
||||
|
||||
void setInternalState(
|
||||
const QRect &geometry,
|
||||
|
@ -119,10 +118,9 @@ private:
|
|||
void saveState(not_null<Memento*> memento);
|
||||
void restoreState(not_null<Memento*> memento);
|
||||
|
||||
void refreshSearchField();
|
||||
std::unique_ptr<ContentMemento> doCreateMemento() override;
|
||||
|
||||
InnerWidget *_inner = nullptr;
|
||||
base::unique_qptr<Ui::RpWidget> _searchField = nullptr;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Info {
|
|||
namespace Profile {
|
||||
namespace {
|
||||
|
||||
constexpr auto kEnableSearchMembersAfterCount = 50;
|
||||
constexpr auto kEnableSearchMembersAfterCount = 20;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ void Widget::setInternalState(const QRect &geometry, not_null<Memento*> memento)
|
|||
restoreState(memento);
|
||||
}
|
||||
|
||||
std::unique_ptr<ContentMemento> Widget::createMemento() {
|
||||
std::unique_ptr<ContentMemento> Widget::doCreateMemento() {
|
||||
auto result = std::make_unique<Memento>(controller());
|
||||
saveState(result.get());
|
||||
return std::move(result);
|
||||
|
|
|
@ -79,7 +79,6 @@ public:
|
|||
|
||||
bool showInternal(
|
||||
not_null<ContentMemento*> memento) override;
|
||||
std::unique_ptr<ContentMemento> createMemento() override;
|
||||
|
||||
void setInternalState(
|
||||
const QRect &geometry,
|
||||
|
@ -91,6 +90,8 @@ private:
|
|||
void saveState(not_null<Memento*> memento);
|
||||
void restoreState(not_null<Memento*> memento);
|
||||
|
||||
std::unique_ptr<ContentMemento> doCreateMemento() override;
|
||||
|
||||
InnerWidget *_inner = nullptr;
|
||||
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue