Use Info::Controller for the whole info section.

This commit is contained in:
John Preston 2017-10-31 22:25:22 +04:00
parent c9152b0b3a
commit 86ad15612a
37 changed files with 686 additions and 509 deletions

View File

@ -40,7 +40,7 @@ public:
unique_qptr &operator=(unique_qptr &&other) { unique_qptr &operator=(unique_qptr &&other) {
if (_object != other._object) { if (_object != other._object) {
destroy(); destroy();
_object = std::move(other._object); _object = base::take(other._object);
} }
return *this; return *this;
} }
@ -58,18 +58,17 @@ public:
unique_qptr &operator=(unique_qptr<U> &&other) { unique_qptr &operator=(unique_qptr<U> &&other) {
if (_object != other._object) { if (_object != other._object) {
destroy(); destroy();
_object = std::move(other._object); _object = base::take(other._object);
} }
return *this; return *this;
} }
unique_qptr &operator=(std::nullptr_t) { unique_qptr &operator=(std::nullptr_t) {
destroy(); destroy();
_object = nullptr;
return *this; return *this;
} }
void reset(T *value) { void reset(T *value = nullptr) {
if (_object != value) { if (_object != value) {
destroy(); destroy();
_object = value; _object = value;

View File

@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "info/info_common_groups_inner_widget.h" #include "info/info_common_groups_inner_widget.h"
#include "info/info_common_groups_widget.h" #include "info/info_common_groups_widget.h"
#include "info/info_controller.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "styles/style_info.h" #include "styles/style_info.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
@ -35,13 +36,13 @@ namespace {
constexpr int kCommonGroupsPerPage = 40; constexpr int kCommonGroupsPerPage = 40;
class Controller class ListController
: public PeerListController : public PeerListController
, private base::Subscriber , private base::Subscriber
, private MTP::Sender { , private MTP::Sender {
public: public:
Controller( ListController(
not_null<Window::Controller*> window, not_null<Controller*> controller,
not_null<UserData*> user); not_null<UserData*> user);
void prepare() override; void prepare() override;
@ -49,7 +50,7 @@ public:
void loadMoreRows() override; void loadMoreRows() override;
private: private:
not_null<Window::Controller*> _window; const not_null<Controller*> _controller;
not_null<UserData*> _user; not_null<UserData*> _user;
mtpRequestId _preloadRequestId = 0; mtpRequestId _preloadRequestId = 0;
bool _allLoaded = false; bool _allLoaded = false;
@ -57,21 +58,21 @@ private:
}; };
Controller::Controller( ListController::ListController(
not_null<Window::Controller*> window, not_null<Controller*> controller,
not_null<UserData*> user) not_null<UserData*> user)
: PeerListController() : PeerListController()
, _window(window) , _controller(controller)
, _user(user) { , _user(user) {
} }
void Controller::prepare() { void ListController::prepare() {
setSearchNoResultsText(lang(lng_blocked_list_not_found)); setSearchNoResultsText(lang(lng_blocked_list_not_found));
delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled); delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled);
delegate()->peerListSetTitle(langFactory(lng_profile_common_groups_section)); delegate()->peerListSetTitle(langFactory(lng_profile_common_groups_section));
} }
void Controller::loadMoreRows() { void ListController::loadMoreRows() {
if (_preloadRequestId || _allLoaded) { if (_preloadRequestId || _allLoaded) {
return; return;
} }
@ -103,8 +104,8 @@ void Controller::loadMoreRows() {
}).send(); }).send();
} }
void Controller::rowClicked(not_null<PeerListRow*> row) { void ListController::rowClicked(not_null<PeerListRow*> row) {
_window->showPeerHistory( _controller->window()->showPeerHistory(
row->peer(), row->peer(),
Window::SectionShow::Way::Forward); Window::SectionShow::Way::Forward);
} }
@ -113,11 +114,11 @@ void Controller::rowClicked(not_null<PeerListRow*> row) {
InnerWidget::InnerWidget( InnerWidget::InnerWidget(
QWidget *parent, QWidget *parent,
not_null<Window::Controller*> controller, not_null<Controller*> controller,
not_null<UserData*> user) not_null<UserData*> user)
: RpWidget(parent) : RpWidget(parent)
, _user(user) , _user(user)
, _listController(std::make_unique<Controller>(controller, _user)) , _listController(std::make_unique<ListController>(controller, _user))
, _list(setupList(this, _listController.get())) { , _list(setupList(this, _listController.get())) {
setContent(_list.data()); setContent(_list.data());
_listController->setDelegate(static_cast<PeerListDelegate*>(this)); _listController->setDelegate(static_cast<PeerListDelegate*>(this));

View File

@ -25,6 +25,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "boxes/peer_list_box.h" #include "boxes/peer_list_box.h"
namespace Info { namespace Info {
class Controller;
namespace CommonGroups { namespace CommonGroups {
class Memento; class Memento;
@ -35,7 +38,7 @@ class InnerWidget final
public: public:
InnerWidget( InnerWidget(
QWidget *parent, QWidget *parent,
not_null<Window::Controller*> controller, not_null<Controller*> controller,
not_null<UserData*> user); not_null<UserData*> user);
not_null<UserData*> user() const { not_null<UserData*> user() const {

View File

@ -21,19 +21,22 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "info/info_common_groups_widget.h" #include "info/info_common_groups_widget.h"
#include "info/info_common_groups_inner_widget.h" #include "info/info_common_groups_inner_widget.h"
#include "info/info_controller.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
namespace Info { namespace Info {
namespace CommonGroups { namespace CommonGroups {
Section Memento::section() const {
return Section(Section::Type::CommonGroups);
}
object_ptr<ContentWidget> Memento::createWidget( object_ptr<ContentWidget> Memento::createWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller,
not_null<Window::Controller*> controller,
const QRect &geometry) { const QRect &geometry) {
auto result = object_ptr<Widget>( auto result = object_ptr<Widget>(
parent, parent,
std::move(wrap),
controller, controller,
App::user(userId())); App::user(userId()));
result->setInternalState(geometry, this); result->setInternalState(geometry, this);
@ -42,10 +45,9 @@ object_ptr<ContentWidget> Memento::createWidget(
Widget::Widget( Widget::Widget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller,
not_null<Window::Controller*> controller,
not_null<UserData*> user) not_null<UserData*> user)
: ContentWidget(parent, wrap, controller, user) { : ContentWidget(parent, controller) {
_inner = setInnerWidget(object_ptr<InnerWidget>( _inner = setInnerWidget(object_ptr<InnerWidget>(
this, this,
controller, controller,
@ -56,11 +58,10 @@ not_null<UserData*> Widget::user() const {
return _inner->user(); return _inner->user();
} }
Section Widget::section() const {
return Section(Section::Type::CommonGroups);
}
bool Widget::showInternal(not_null<ContentMemento*> memento) { bool Widget::showInternal(not_null<ContentMemento*> memento) {
if (!controller()->validateMementoPeer(memento)) {
return false;
}
if (auto groupsMemento = dynamic_cast<Memento*>(memento.get())) { if (auto groupsMemento = dynamic_cast<Memento*>(memento.get())) {
if (groupsMemento->userId() == user()->bareId()) { if (groupsMemento->userId() == user()->bareId()) {
restoreState(groupsMemento); restoreState(groupsMemento);

View File

@ -30,18 +30,16 @@ class InnerWidget;
class Memento final : public ContentMemento { class Memento final : public ContentMemento {
public: public:
Memento(UserId userId) : ContentMemento(peerFromUser(userId)) { Memento(UserId userId)
: ContentMemento(peerFromUser(userId), 0) {
} }
object_ptr<ContentWidget> createWidget( object_ptr<ContentWidget> createWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller,
not_null<Window::Controller*> controller,
const QRect &geometry) override; const QRect &geometry) override;
Section section() const override { Section section() const override;
return Section(Section::Type::CommonGroups);
}
UserId userId() const { UserId userId() const {
return peerToUser(peerId()); return peerToUser(peerId());
@ -55,12 +53,10 @@ class Widget final : public ContentWidget {
public: public:
Widget( Widget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller,
not_null<Window::Controller*> controller,
not_null<UserData*> user); not_null<UserData*> user);
not_null<UserData*> user() const; not_null<UserData*> user() const;
Section section() const override;
bool showInternal( bool showInternal(
not_null<ContentMemento*> memento) override; not_null<ContentMemento*> memento) override;

View File

@ -31,6 +31,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "info/info_common_groups_widget.h" #include "info/info_common_groups_widget.h"
#include "info/info_layer_widget.h" #include "info/info_layer_widget.h"
#include "info/info_section_widget.h" #include "info/info_section_widget.h"
#include "info/info_controller.h"
#include "styles/style_info.h" #include "styles/style_info.h"
#include "styles/style_profile.h" #include "styles/style_profile.h"
@ -38,22 +39,18 @@ namespace Info {
ContentWidget::ContentWidget( ContentWidget::ContentWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller)
not_null<Window::Controller*> controller,
not_null<PeerData*> peer)
: RpWidget(parent) : RpWidget(parent)
, _controller(controller) , _controller(controller)
, _peer(peer)
, _scroll(this, st::infoScroll) { , _scroll(this, st::infoScroll) {
setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_OpaquePaintEvent);
std::move(wrap) | rpl::start_with_next( _controller->wrapValue()
[this](Wrap value) { | rpl::start_with_next([this](Wrap value) {
_bg = (value == Wrap::Layer) _bg = (value == Wrap::Layer)
? st::boxBg ? st::boxBg
: st::profileBg; : st::profileBg;
update(); update();
}, }, lifetime());
lifetime());
} }
void ContentWidget::resizeEvent(QResizeEvent *e) { void ContentWidget::resizeEvent(QResizeEvent *e) {

View File

@ -33,21 +33,16 @@ class ScrollArea;
struct ScrollToRequest; struct ScrollToRequest;
} // namespace Ui } // namespace Ui
namespace Window {
class Controller;
} // namespace Window
namespace Info { namespace Info {
class ContentMemento; class ContentMemento;
class Controller;
class ContentWidget : public Ui::RpWidget { class ContentWidget : public Ui::RpWidget {
public: public:
ContentWidget( ContentWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller);
not_null<Window::Controller*> controller,
not_null<PeerData*> peer);
virtual bool showInternal( virtual bool showInternal(
not_null<ContentMemento*> memento) = 0; not_null<ContentMemento*> memento) = 0;
@ -57,11 +52,6 @@ public:
virtual void setIsStackBottom(bool isStackBottom) { virtual void setIsStackBottom(bool isStackBottom) {
} }
virtual Section section() const = 0;
not_null<PeerData*> peer() const {
return _peer;
}
rpl::producer<int> desiredHeightValue() const override; rpl::producer<int> desiredHeightValue() const override;
rpl::producer<bool> desiredShadowVisibility() const; rpl::producer<bool> desiredShadowVisibility() const;
bool hasTopBarShadow() const; bool hasTopBarShadow() const;
@ -94,7 +84,7 @@ protected:
doSetInnerWidget(std::move(inner), scrollTopSkip)); doSetInnerWidget(std::move(inner), scrollTopSkip));
} }
not_null<Window::Controller*> controller() const { not_null<Controller*> controller() const {
return _controller; return _controller;
} }
@ -112,8 +102,7 @@ private:
int scrollTopSkip); int scrollTopSkip);
void updateControlsGeometry(); void updateControlsGeometry();
const not_null<Window::Controller*> _controller; const not_null<Controller*> _controller;
const not_null<PeerData*> _peer;
style::color _bg; style::color _bg;
int _scrollTopSkip = 0; int _scrollTopSkip = 0;
@ -127,18 +116,23 @@ private:
class ContentMemento { class ContentMemento {
public: public:
ContentMemento(PeerId peerId) : _peerId(peerId) { ContentMemento(PeerId peerId, PeerId migratedPeerId)
: _peerId(peerId)
, _migratedPeerId(migratedPeerId) {
} }
virtual object_ptr<ContentWidget> createWidget( virtual object_ptr<ContentWidget> createWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller,
not_null<Window::Controller*> controller,
const QRect &geometry) = 0; const QRect &geometry) = 0;
virtual PeerId peerId() const { PeerId peerId() const {
return _peerId; return _peerId;
} }
PeerId migratedPeerId() const {
return _migratedPeerId;
}
virtual Section section() const = 0; virtual Section section() const = 0;
virtual ~ContentMemento() = default; virtual ~ContentMemento() = default;
@ -151,7 +145,8 @@ public:
} }
private: private:
PeerId _peerId = 0; const PeerId _peerId = 0;
const PeerId _migratedPeerId = 0;
int _scrollTop = 0; int _scrollTop = 0;
}; };

View File

@ -0,0 +1,139 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#include "info/info_controller.h"
#include "ui/search_field_controller.h"
#include "history/history_shared_media.h"
#include "info/info_content_widget.h"
#include "info/info_memento.h"
namespace Info {
namespace {
not_null<PeerData*> CorrectPeer(PeerId peerId) {
Expects(peerId != 0);
auto result = App::peer(peerId);
if (auto to = result->migrateTo()) {
return to;
}
return result;
}
} // namespace
Controller::Controller(
not_null<WrapWidget*> widget,
not_null<Window::Controller*> window,
not_null<ContentMemento*> memento)
: _widget(widget)
, _peer(App::peer(memento->peerId()))
, _migrated(memento->migratedPeerId()
? App::peer(memento->migratedPeerId())
: nullptr)
, _window(window)
, _section(memento->section()) {
updateSearchControllers();
}
Wrap Controller::wrap() const {
return _widget->wrap();
}
rpl::producer<Wrap> Controller::wrapValue() const {
return _widget->wrapValue();
}
bool Controller::validateMementoPeer(
not_null<ContentMemento*> memento) const {
return memento->peerId() == peerId()
&& memento->migratedPeerId() == migratedPeerId();
}
void Controller::setSection(const Section &section) {
_section = section;
updateSearchControllers();
}
void Controller::updateSearchControllers() {
auto isMedia = (_section.type() == Section::Type::Media);
auto mediaType = isMedia
? _section.mediaType()
: Section::MediaType::kCount;
auto hasMediaSearch = isMedia
&& SharedMediaAllowSearch(mediaType);
// auto hasCommonGroupsSearch
// = (_section.type() == Section::Type::CommonGroups);
if (isMedia) {
_searchController
= std::make_unique<Api::DelayedSearchController>();
_searchController->setQueryFast(produceSearchQuery());
} else {
_searchController = nullptr;
}
if (hasMediaSearch) {
_searchFieldController
= std::make_unique<Ui::SearchFieldController>();
_searchFieldController->queryValue()
| rpl::start_with_next([=](QString &&query) {
_searchController->setQuery(
produceSearchQuery(std::move(query)));
}, _searchFieldController->lifetime());
} else {
_searchFieldController = nullptr;
}
}
auto Controller::produceSearchQuery(
QString &&query) const -> SearchQuery {
auto result = SearchQuery();
result.type = _section.mediaType();
result.peerId = _peer->id;
result.query = std::move(query);
result.migratedPeerId = _migrated ? _migrated->id : PeerId(0);
return result;
}
rpl::producer<SparseIdsMergedSlice> Controller::mediaSource(
SparseIdsMergedSlice::UniversalMsgId aroundId,
int limitBefore,
int limitAfter) const {
auto query = _searchController->currentQuery();
if (!query.query.isEmpty()) {
return _searchController->idsSlice(
aroundId,
limitBefore,
limitAfter);
}
return SharedMediaMergedViewer(
SharedMediaMergedKey(
SparseIdsMergedSlice::Key(
query.peerId,
query.migratedPeerId,
aroundId),
query.type),
limitBefore,
limitAfter);
}
Controller::~Controller() = default;
} // namespace Info

View File

@ -0,0 +1,143 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once
#include <rpl/variable.h>
#include "history/history_search_controller.h"
namespace Ui {
class SearchFieldController;
} // namespace Ui
namespace Window {
class Controller;
} // namespace Window
namespace Info {
enum class Wrap;
class WrapWidget;
class Memento;
class ContentMemento;
class Section final {
public:
enum class Type {
Profile,
Media,
CommonGroups,
};
using MediaType = Storage::SharedMediaType;
Section(Type type) : _type(type) {
Expects(type != Type::Media);
}
Section(MediaType mediaType)
: _type(Type::Media)
, _mediaType(mediaType) {
}
Type type() const {
return _type;
}
MediaType mediaType() const {
Expects(_type == Type::Media);
return _mediaType;
}
private:
Type _type;
Storage::SharedMediaType _mediaType;
};
class Controller {
public:
Controller(
not_null<WrapWidget*> widget,
not_null<Window::Controller*> window,
not_null<ContentMemento*> memento);
not_null<PeerData*> peer() const {
return _peer;
}
PeerData *migrated() const {
return _migrated;
}
PeerId peerId() const {
return _peer->id;
}
PeerId migratedPeerId() const {
return _migrated ? _migrated->id : PeerId(0);
}
const Section &section() const {
return _section;
}
bool validateMementoPeer(
not_null<ContentMemento*> memento) const;
Wrap wrap() const;
rpl::producer<Wrap> wrapValue() const;
void setSection(const Section &section);
not_null<Window::Controller*> window() const {
return _window;
}
Ui::SearchFieldController *searchFieldController() const {
return _searchFieldController.get();
}
rpl::producer<SparseIdsMergedSlice> mediaSource(
SparseIdsMergedSlice::UniversalMsgId aroundId,
int limitBefore,
int limitAfter) const;
rpl::producer<> mediaSourceChanged() const {
return _searchController->sourceChanged();
}
rpl::lifetime &lifetime() {
return _lifetime;
}
~Controller();
private:
using SearchQuery = Api::DelayedSearchController::Query;
void updateSearchControllers();
SearchQuery produceSearchQuery(
QString &&query = QString()) const;
not_null<WrapWidget*> _widget;
not_null<PeerData*> _peer;
PeerData *_migrated = nullptr;
not_null<Window::Controller*> _window;
rpl::variable<Wrap> _wrap;
Section _section;
std::unique_ptr<Ui::SearchFieldController> _searchFieldController;
std::unique_ptr<Api::DelayedSearchController> _searchController;
rpl::lifetime _lifetime;
};
} // namespace Info

View File

@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "info/info_common_groups_widget.h" #include "info/info_common_groups_widget.h"
#include "info/info_section_widget.h" #include "info/info_section_widget.h"
#include "info/info_layer_widget.h" #include "info/info_layer_widget.h"
#include "info/info_controller.h"
namespace Info { namespace Info {
@ -40,23 +41,28 @@ Memento::Memento(std::unique_ptr<ContentMemento> content)
: _content(std::move(content)) { : _content(std::move(content)) {
} }
PeerId Memento::peerId() const {
return _content->peerId();
}
Section Memento::section() const {
return _content->section();
}
std::unique_ptr<ContentMemento> Memento::Default( std::unique_ptr<ContentMemento> Memento::Default(
PeerId peerId, PeerId peerId,
Section section) { Section section) {
Expects(peerId != 0);
auto peer = App::peer(peerId);
if (auto to = peer->migrateTo()) {
peer = to;
}
auto migrated = peer->migrateFrom();
peerId = peer->id;
auto migratedPeerId = migrated ? migrated->id : PeerId(0);
switch (section.type()) { switch (section.type()) {
case Section::Type::Profile: case Section::Type::Profile:
return std::make_unique<Profile::Memento>(peerId); return std::make_unique<Profile::Memento>(
peerId,
migratedPeerId);
case Section::Type::Media: case Section::Type::Media:
return std::make_unique<Media::Memento>( return std::make_unique<Media::Memento>(
peerId, peerId,
migratedPeerId,
section.mediaType()); section.mediaType());
case Section::Type::CommonGroups: case Section::Type::CommonGroups:
Assert(peerIsUser(peerId)); Assert(peerIsUser(peerId));

View File

@ -59,9 +59,6 @@ public:
return _content.get(); return _content.get();
} }
PeerId peerId() const;
Section section() const;
~Memento(); ~Memento();
private: private:

View File

@ -24,25 +24,26 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "info/info_wrap_widget.h" #include "info/info_wrap_widget.h"
#include "info/info_layer_widget.h" #include "info/info_layer_widget.h"
#include "info/info_memento.h" #include "info/info_memento.h"
#include "info/info_controller.h"
namespace Info { namespace Info {
SectionWidget::SectionWidget( SectionWidget::SectionWidget(
QWidget *parent, QWidget *parent,
not_null<Window::Controller*> controller, not_null<Window::Controller*> window,
Wrap wrap, Wrap wrap,
not_null<Memento*> memento) not_null<Memento*> memento)
: Window::SectionWidget(parent, controller) : Window::SectionWidget(parent, window)
, _content(this, controller, wrap, memento) { , _content(this, window, wrap, memento) {
init(); init();
} }
SectionWidget::SectionWidget( SectionWidget::SectionWidget(
QWidget *parent, QWidget *parent,
not_null<Window::Controller*> controller, not_null<Window::Controller*> window,
Wrap wrap, Wrap wrap,
not_null<MoveMemento*> memento) not_null<MoveMemento*> memento)
: Window::SectionWidget(parent, controller) : Window::SectionWidget(parent, window)
, _content(memento->takeContent(this, wrap)) { , _content(memento->takeContent(this, wrap)) {
init(); init();
} }
@ -55,6 +56,11 @@ void SectionWidget::init() {
}, _content->lifetime()); }, _content->lifetime());
} }
not_null<Controller*> SectionWidget::controller() const {
Expects(_content != nullptr);
return _content->controller();
}
PeerData *SectionWidget::peerForDialogs() const { PeerData *SectionWidget::peerForDialogs() const {
return _content->peerForDialogs(); return _content->peerForDialogs();
} }
@ -83,19 +89,19 @@ bool SectionWidget::showInternal(
} }
std::unique_ptr<Window::SectionMemento> SectionWidget::createMemento() { std::unique_ptr<Window::SectionMemento> SectionWidget::createMemento() {
auto result = std::make_unique<Memento>(_content->peer()->id); return _content->createMemento();
_content->saveState(result.get());
return std::move(result);
} }
object_ptr<Window::LayerWidget> SectionWidget::moveContentToLayer( object_ptr<Window::LayerWidget> SectionWidget::moveContentToLayer(
QRect bodyGeometry) { QRect bodyGeometry) {
if (_content->wrap() != Wrap::Narrow if (controller()->wrap() != Wrap::Narrow
|| width() < LayerWidget::MinimalSupportedWidth()) { || width() < LayerWidget::MinimalSupportedWidth()) {
return nullptr; return nullptr;
} }
return MoveMemento( return MoveMemento(
std::move(_content)).createLayer(controller(), bodyGeometry); std::move(_content)).createLayer(
controller()->window(),
bodyGeometry);
} }
bool SectionWidget::wheelEventFromFloatPlayer(QEvent *e) { bool SectionWidget::wheelEventFromFloatPlayer(QEvent *e) {

View File

@ -31,6 +31,7 @@ namespace Info {
class Memento; class Memento;
class MoveMemento; class MoveMemento;
class Controller;
class WrapWidget; class WrapWidget;
enum class Wrap; enum class Wrap;
@ -38,12 +39,12 @@ class SectionWidget final : public Window::SectionWidget {
public: public:
SectionWidget( SectionWidget(
QWidget *parent, QWidget *parent,
not_null<Window::Controller*> controller, not_null<Window::Controller*> window,
Wrap wrap, Wrap wrap,
not_null<Memento*> memento); not_null<Memento*> memento);
SectionWidget( SectionWidget(
QWidget *parent, QWidget *parent,
not_null<Window::Controller*> controller, not_null<Window::Controller*> window,
Wrap wrap, Wrap wrap,
not_null<MoveMemento*> memento); not_null<MoveMemento*> memento);
@ -72,6 +73,8 @@ protected:
private: private:
void init(); void init();
not_null<Controller*> controller() const;
object_ptr<WrapWidget> _content; object_ptr<WrapWidget> _content;
}; };

View File

@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "styles/style_info.h" #include "styles/style_info.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "info/info_wrap_widget.h" #include "info/info_wrap_widget.h"
#include "info/info_controller.h"
#include "storage/storage_shared_media.h" #include "storage/storage_shared_media.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
@ -102,19 +103,19 @@ void TopBar::paintEvent(QPaintEvent *e) {
rpl::producer<QString> TitleValue( rpl::producer<QString> TitleValue(
const Section &section, const Section &section,
PeerId peerId) { not_null<PeerData*> peer) {
return Lang::Viewer([&] { return Lang::Viewer([&] {
switch (section.type()) { switch (section.type()) {
case Section::Type::Profile: case Section::Type::Profile:
if (peerIsUser(peerId)) { if (auto user = peer->asUser()) {
return App::user(peerId)->botInfo return user->botInfo
? lng_info_bot_title ? lng_info_bot_title
: lng_info_user_title; : lng_info_user_title;
} else if (peerIsChannel(peerId)) { } else if (auto channel = peer->asChannel()) {
return App::channel(peerId)->isMegagroup() return channel->isMegagroup()
? lng_info_group_title ? lng_info_group_title
: lng_info_channel_title; : lng_info_channel_title;
} else if (peerIsChat(peerId)) { } else if (peer->isChat()) {
return lng_info_group_title; return lng_info_group_title;
} }
Unexpected("Bad peer type in Info::TitleValue()"); Unexpected("Bad peer type in Info::TitleValue()");

View File

@ -37,7 +37,7 @@ class Section;
rpl::producer<QString> TitleValue( rpl::producer<QString> TitleValue(
const Section &section, const Section &section,
PeerId peerId); not_null<PeerData*> peer);
class TopBar : public Ui::RpWidget { class TopBar : public Ui::RpWidget {
public: public:

View File

@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "info/profile/info_profile_widget.h" #include "info/profile/info_profile_widget.h"
#include "info/media/info_media_widget.h" #include "info/media/info_media_widget.h"
#include "info/info_content_widget.h" #include "info/info_content_widget.h"
#include "info/info_controller.h"
#include "info/info_memento.h" #include "info/info_memento.h"
#include "info/info_top_bar.h" #include "info/info_top_bar.h"
#include "info/info_top_bar_override.h" #include "info/info_top_bar_override.h"
@ -57,13 +58,19 @@ struct WrapWidget::StackItem {
WrapWidget::WrapWidget( WrapWidget::WrapWidget(
QWidget *parent, QWidget *parent,
not_null<Window::Controller*> controller, not_null<Window::Controller*> window,
Wrap wrap, Wrap wrap,
not_null<Memento*> memento) not_null<Memento*> memento)
: SectionWidget(parent, controller) : SectionWidget(parent, window)
, _wrap(wrap) , _wrap(wrap)
, _controller(createController(window, memento->content()))
, _topShadow(this) { , _topShadow(this) {
_topShadow->toggleOn(topShadowToggledValue()); _topShadow->toggleOn(topShadowToggledValue());
_wrap.changes()
| rpl::start_with_next([this] {
setupTop();
finishShowContent();
}, lifetime());
selectedListValue() selectedListValue()
| rpl::start_with_next([this](SelectedItems &&items) { | rpl::start_with_next([this](SelectedItems &&items) {
InvokeQueued(this, [this, items = std::move(items)]() mutable { InvokeQueued(this, [this, items = std::move(items)]() mutable {
@ -73,20 +80,18 @@ WrapWidget::WrapWidget(
showNewContent(memento->content()); showNewContent(memento->content());
} }
std::unique_ptr<Controller> WrapWidget::createController(
not_null<Window::Controller*> window,
not_null<ContentMemento*> memento) {
auto result = std::make_unique<Controller>(
this,
window,
memento);
return result;
}
not_null<PeerData*> WrapWidget::peer() const { not_null<PeerData*> WrapWidget::peer() const {
return _content->peer(); return _controller->peer();
}
Wrap WrapWidget::wrap() const {
return _wrap.current();
}
void WrapWidget::setWrap(Wrap wrap) {
if (_wrap.current() != wrap) {
_wrap = wrap;
setupTop(_content->section(), _content->peer()->id);
finishShowContent();
}
} }
void WrapWidget::createTabs() { void WrapWidget::createTabs() {
@ -138,9 +143,15 @@ void WrapWidget::showTab(Tab tab) {
? SlideDirection::FromRight ? SlideDirection::FromRight
: SlideDirection::FromLeft; : SlideDirection::FromLeft;
auto newAnotherMemento = _content->createMemento(); auto newAnotherMemento = _content->createMemento();
auto newContent = _anotherTabMemento if (!_anotherTabMemento) {
? createContent(_anotherTabMemento.get()) _anotherTabMemento = createTabMemento(tab);
: createContent(tab); }
auto newController = createController(
_controller->window(),
_anotherTabMemento.get());
auto newContent = createContent(
_anotherTabMemento.get(),
newController.get());
auto animationParams = SectionSlideParams(); auto animationParams = SectionSlideParams();
// animationParams.withFade = (wrap() == Wrap::Layer); // animationParams.withFade = (wrap() == Wrap::Layer);
animationParams.withTabs = true; animationParams.withTabs = true;
@ -149,6 +160,7 @@ void WrapWidget::showTab(Tab tab) {
animationParams.oldContentCache = grabForShowAnimation( animationParams.oldContentCache = grabForShowAnimation(
animationParams); animationParams);
_controller = std::move(newController);
showContent(std::move(newContent)); showContent(std::move(newContent));
showAnimated(direction, animationParams); showAnimated(direction, animationParams);
@ -157,7 +169,8 @@ void WrapWidget::showTab(Tab tab) {
_tab = tab; _tab = tab;
} }
void WrapWidget::setupTabbedTop(const Section &section) { void WrapWidget::setupTabbedTop() {
auto section = _controller->section();
switch (section.type()) { switch (section.type()) {
case Section::Type::Profile: case Section::Type::Profile:
setupTabs(Tab::Profile); setupTabs(Tab::Profile);
@ -180,30 +193,26 @@ void WrapWidget::setupTabbedTop(const Section &section) {
} }
} }
void WrapWidget::setupTop( void WrapWidget::setupTop() {
const Section &section,
PeerId peerId) {
if (wrap() == Wrap::Side && _historyStack.empty()) { if (wrap() == Wrap::Side && _historyStack.empty()) {
setupTabbedTop(section); setupTabbedTop();
} else { } else {
setupTabs(Tab::None); setupTabs(Tab::None);
} }
if (_topTabs) { if (_topTabs) {
_topBar.destroy(); _topBar.destroy();
} else { } else {
createTopBar(section, peerId); createTopBar();
} }
refreshTopBarOverride(); refreshTopBarOverride();
} }
void WrapWidget::createTopBar( void WrapWidget::createTopBar() {
const Section &section,
PeerId peerId) {
_topBar.create(this, TopBarStyle(wrap())); _topBar.create(this, TopBarStyle(wrap()));
_topBar->setTitle(TitleValue( _topBar->setTitle(TitleValue(
section, _controller->section(),
peerId)); _controller->peer()));
if (wrap() != Wrap::Layer || !_historyStack.empty()) { if (wrap() != Wrap::Layer || !_historyStack.empty()) {
_topBar->enableBackButton(true); _topBar->enableBackButton(true);
_topBar->backRequest() _topBar->backRequest()
@ -216,7 +225,7 @@ void WrapWidget::createTopBar(
_topBar, _topBar,
st::infoLayerTopBarClose)); st::infoLayerTopBarClose));
close->addClickHandler([this] { close->addClickHandler([this] {
controller()->hideSpecialLayer(); _controller->window()->hideSpecialLayer();
}); });
} }
@ -290,7 +299,7 @@ void WrapWidget::showBackFromStack() {
params); params);
_anotherTabMemento = std::move(last.anotherTab); _anotherTabMemento = std::move(last.anotherTab);
} else { } else {
controller()->showBackFromStack(params); _controller->window()->showBackFromStack(params);
} }
} }
@ -324,7 +333,7 @@ void WrapWidget::finishShowContent() {
rpl::producer<bool> WrapWidget::topShadowToggledValue() const { rpl::producer<bool> WrapWidget::topShadowToggledValue() const {
using namespace rpl::mappers; using namespace rpl::mappers;
return rpl::combine( return rpl::combine(
_wrap.value(), _controller->wrapValue(),
_desiredShadowVisibilities.events() | rpl::flatten_latest(), _desiredShadowVisibilities.events() | rpl::flatten_latest(),
($1 == Wrap::Side) || $2); ($1 == Wrap::Side) || $2);
} }
@ -341,39 +350,26 @@ rpl::producer<SelectedItems> WrapWidget::selectedListValue() const {
return _selectedLists.events() | rpl::flatten_latest(); return _selectedLists.events() | rpl::flatten_latest();
} }
object_ptr<ContentWidget> WrapWidget::createContent(Tab tab) { std::unique_ptr<ContentMemento> WrapWidget::createTabMemento(
Tab tab) {
switch (tab) { switch (tab) {
case Tab::Profile: return createProfileWidget(); case Tab::Profile: return std::make_unique<Profile::Memento>(
case Tab::Media: return createMediaWidget(); _controller->peerId(),
_controller->migratedPeerId());
case Tab::Media: return std::make_unique<Media::Memento>(
_controller->peerId(),
_controller->migratedPeerId(),
Media::Memento::Type::Photo);
} }
Unexpected("Tab value in Info::WrapWidget::createInner()"); Unexpected("Tab value in Info::WrapWidget::createInner()");
} }
object_ptr<Profile::Widget> WrapWidget::createProfileWidget() {
auto result = object_ptr<Profile::Widget>(
this,
_wrap.value(),
controller(),
_content->peer());
return result;
}
object_ptr<Media::Widget> WrapWidget::createMediaWidget() {
auto result = object_ptr<Media::Widget>(
this,
_wrap.value(),
controller(),
_content->peer(),
Media::Widget::Type::Photo);
return result;
}
object_ptr<ContentWidget> WrapWidget::createContent( object_ptr<ContentWidget> WrapWidget::createContent(
not_null<ContentMemento*> memento) { not_null<ContentMemento*> memento,
not_null<Controller*> controller) {
return memento->createWidget( return memento->createWidget(
this, this,
_wrap.value(), controller,
controller(),
contentGeometry()); contentGeometry());
} }
@ -423,20 +419,21 @@ bool WrapWidget::showInternal(
const Window::SectionShow &params) { const Window::SectionShow &params) {
if (auto infoMemento = dynamic_cast<Memento*>(memento.get())) { if (auto infoMemento = dynamic_cast<Memento*>(memento.get())) {
auto content = infoMemento->content(); auto content = infoMemento->content();
if (!_content->showInternal(content)) { if (_controller->validateMementoPeer(content)) {
showNewContent( if (_content->showInternal(content)) {
content, return true;
params); }
} }
showNewContent(
content,
params);
return true; return true;
} }
return false; return false;
} }
std::unique_ptr<Window::SectionMemento> WrapWidget::createMemento() { std::unique_ptr<Window::SectionMemento> WrapWidget::createMemento() {
auto result = std::make_unique<Memento>(_content->peer()->id); return std::make_unique<Memento>(_content->createMemento());
saveState(result.get());
return std::move(result);
} }
rpl::producer<int> WrapWidget::desiredHeightValue() const { rpl::producer<int> WrapWidget::desiredHeightValue() const {
@ -446,10 +443,6 @@ rpl::producer<int> WrapWidget::desiredHeightValue() const {
| rpl::flatten_latest(); | rpl::flatten_latest();
} }
void WrapWidget::saveState(not_null<Memento*> memento) {
memento->setInner(_content->createMemento());
}
QRect WrapWidget::contentGeometry() const { QRect WrapWidget::contentGeometry() const {
return rect().marginsRemoved({ 0, topWidget()->height(), 0, 0 }); return rect().marginsRemoved({ 0, topWidget()->height(), 0, 0 });
} }
@ -462,9 +455,12 @@ void WrapWidget::showNewContent(
auto needAnimation = (_content != nullptr) auto needAnimation = (_content != nullptr)
&& (params.animated != anim::type::instant); && (params.animated != anim::type::instant);
auto animationParams = SectionSlideParams(); auto animationParams = SectionSlideParams();
auto newController = createController(
_controller->window(),
memento);
auto newContent = object_ptr<ContentWidget>(nullptr); auto newContent = object_ptr<ContentWidget>(nullptr);
if (needAnimation) { if (needAnimation) {
newContent = createContent(memento); newContent = createContent(memento, newController.get());
animationParams.withTopBarShadow = hasTopBarShadow() animationParams.withTopBarShadow = hasTopBarShadow()
&& newContent->hasTopBarShadow(); && newContent->hasTopBarShadow();
animationParams.oldContentCache = grabForShowAnimation( animationParams.oldContentCache = grabForShowAnimation(
@ -481,8 +477,10 @@ void WrapWidget::showNewContent(
} else if (params.way == Window::SectionShow::Way::ClearStack) { } else if (params.way == Window::SectionShow::Way::ClearStack) {
_historyStack.clear(); _historyStack.clear();
} }
_controller = std::move(newController);
if (newContent) { if (newContent) {
setupTop(newContent->section(), newContent->peer()->id); setupTop();
showContent(std::move(newContent)); showContent(std::move(newContent));
} else { } else {
showNewContent(memento); showNewContent(memento);
@ -498,8 +496,8 @@ void WrapWidget::showNewContent(
void WrapWidget::showNewContent(not_null<ContentMemento*> memento) { void WrapWidget::showNewContent(not_null<ContentMemento*> memento) {
// Validates contentGeometry(). // Validates contentGeometry().
setupTop(memento->section(), memento->peerId()); setupTop();
showContent(createContent(memento)); showContent(createContent(memento, _controller.get()));
} }
void WrapWidget::setupTabs(Tab tab) { void WrapWidget::setupTabs(Tab tab) {

View File

@ -43,6 +43,7 @@ namespace Media {
class Widget; class Widget;
} // namespace Media } // namespace Media
class Controller;
class Section; class Section;
class Memento; class Memento;
class MoveMemento; class MoveMemento;
@ -57,37 +58,6 @@ enum class Wrap {
Side, Side,
}; };
class Section final {
public:
enum class Type {
Profile,
Media,
CommonGroups,
};
using MediaType = Storage::SharedMediaType;
Section(Type type) : _type(type) {
Expects(type != Type::Media);
}
Section(MediaType mediaType)
: _type(Type::Media)
, _mediaType(mediaType) {
}
Type type() const {
return _type;
}
MediaType mediaType() const {
Expects(_type == Type::Media);
return _mediaType;
}
private:
Type _type;
Storage::SharedMediaType _mediaType;
};
struct SelectedItem { struct SelectedItem {
explicit SelectedItem(FullMsgId msgId) : msgId(msgId) { explicit SelectedItem(FullMsgId msgId) : msgId(msgId) {
} }
@ -111,7 +81,7 @@ class WrapWidget final : public Window::SectionWidget {
public: public:
WrapWidget( WrapWidget(
QWidget *parent, QWidget *parent,
not_null<Window::Controller*> controller, not_null<Window::Controller*> window,
Wrap wrap, Wrap wrap,
not_null<Memento*> memento); not_null<Memento*> memento);
@ -119,9 +89,19 @@ public:
PeerData *peerForDialogs() const override { PeerData *peerForDialogs() const override {
return peer(); return peer();
} }
Wrap wrap() const {
return _wrap.current();
}
rpl::producer<Wrap> wrapValue() const {
return _wrap.value();
}
void setWrap(Wrap wrap) {
_wrap = wrap;
}
Wrap wrap() const; not_null<Controller*> controller() {
void setWrap(Wrap wrap); return _controller.get();
}
bool hasTopBarShadow() const override; bool hasTopBarShadow() const override;
QPixmap grabForShowAnimation( QPixmap grabForShowAnimation(
@ -138,7 +118,6 @@ public:
rpl::producer<int> desiredHeightValue() const override; rpl::producer<int> desiredHeightValue() const override;
void updateInternalState(not_null<Memento*> memento); void updateInternalState(not_null<Memento*> memento);
void saveState(not_null<Memento*> memento);
// Float player interface. // Float player interface.
bool wheelEventFromFloatPlayer(QEvent *e) override; bool wheelEventFromFloatPlayer(QEvent *e) override;
@ -167,13 +146,11 @@ private:
void showNewContent( void showNewContent(
not_null<ContentMemento*> memento, not_null<ContentMemento*> memento,
const Window::SectionShow &params); const Window::SectionShow &params);
void setupTop(const Section &section, PeerId peerId); void setupTop();
void setupTabbedTop(const Section &section); void setupTabbedTop();
void setupTabs(Tab tab); void setupTabs(Tab tab);
void createTabs(); void createTabs();
void createTopBar( void createTopBar();
const Section &section,
PeerId peerId);
not_null<RpWidget*> topWidget() const; not_null<RpWidget*> topWidget() const;
@ -185,10 +162,12 @@ private:
void showTab(Tab tab); void showTab(Tab tab);
void showContent(object_ptr<ContentWidget> content); void showContent(object_ptr<ContentWidget> content);
object_ptr<ContentWidget> createContent(Tab tab); std::unique_ptr<ContentMemento> createTabMemento(Tab tab);
object_ptr<Profile::Widget> createProfileWidget();
object_ptr<Media::Widget> createMediaWidget();
object_ptr<ContentWidget> createContent( object_ptr<ContentWidget> createContent(
not_null<ContentMemento*> memento,
not_null<Controller*> controller);
std::unique_ptr<Controller> createController(
not_null<Window::Controller*> window,
not_null<ContentMemento*> memento); not_null<ContentMemento*> memento);
rpl::producer<SelectedItems> selectedListValue() const; rpl::producer<SelectedItems> selectedListValue() const;
@ -198,6 +177,7 @@ private:
void destroyTopBarOverride(); void destroyTopBarOverride();
rpl::variable<Wrap> _wrap; rpl::variable<Wrap> _wrap;
std::unique_ptr<Controller> _controller;
object_ptr<ContentWidget> _content = { nullptr }; object_ptr<ContentWidget> _content = { nullptr };
object_ptr<Ui::PlainShadow> _topTabsBackground = { nullptr }; object_ptr<Ui::PlainShadow> _topTabsBackground = { nullptr };
object_ptr<Ui::SettingsSlider> _topTabs = { nullptr }; object_ptr<Ui::SettingsSlider> _topTabs = { nullptr };

View File

@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "storage/storage_shared_media.h" #include "storage/storage_shared_media.h"
#include "info/info_memento.h" #include "info/info_memento.h"
#include "info/info_controller.h"
#include "info/profile/info_profile_button.h" #include "info/profile/info_profile_button.h"
#include "info/profile/info_profile_values.h" #include "info/profile/info_profile_values.h"
#include "ui/wrap/slide_wrap.h" #include "ui/wrap/slide_wrap.h"
@ -90,11 +91,12 @@ inline auto AddButton(
Ui::VerticalLayout *parent, Ui::VerticalLayout *parent,
not_null<Window::Controller*> controller, not_null<Window::Controller*> controller,
not_null<PeerData*> peer, not_null<PeerData*> peer,
PeerData *migrated,
Type type, Type type,
Ui::MultiSlideTracker &tracker) { Ui::MultiSlideTracker &tracker) {
auto result = AddCountedButton( auto result = AddCountedButton(
parent, parent,
Profile::SharedMediaCountValue(peer, type), Profile::SharedMediaCountValue(peer, migrated, type),
MediaText(type), MediaText(type),
tracker)->entity(); tracker)->entity();
result->addClickHandler([controller, peer, type] { result->addClickHandler([controller, peer, type] {
@ -118,9 +120,7 @@ inline auto AddCommonGroupsButton(
tracker)->entity(); tracker)->entity();
result->addClickHandler([controller, user] { result->addClickHandler([controller, user] {
controller->showSection( controller->showSection(
Info::Memento( Info::Memento(user->id, Section::Type::CommonGroups));
user->id,
Section::Type::CommonGroups));
}); });
return std::move(result); return std::move(result);
}; };

View File

@ -26,6 +26,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "info/media/info_media_buttons.h" #include "info/media/info_media_buttons.h"
#include "info/profile/info_profile_button.h" #include "info/profile/info_profile_button.h"
#include "info/profile/info_profile_icon.h" #include "info/profile/info_profile_icon.h"
#include "info/info_controller.h"
#include "ui/widgets/discrete_sliders.h" #include "ui/widgets/discrete_sliders.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/wrap/vertical_layout.h" #include "ui/wrap/vertical_layout.h"
@ -61,17 +62,15 @@ Type TabIndexToType(int index) {
InnerWidget::InnerWidget( InnerWidget::InnerWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> &&wrap, not_null<Controller*> controller)
not_null<Window::Controller*> controller, : RpWidget(parent)
not_null<PeerData*> peer, , _controller(controller) {
Type type) _list = setupList();
: RpWidget(parent) { setupOtherTypes();
_list = setupList(controller, peer, type);
setupOtherTypes(std::move(wrap));
} }
void InnerWidget::setupOtherTypes(rpl::producer<Wrap> &&wrap) { void InnerWidget::setupOtherTypes() {
std::move(wrap) _controller->wrapValue()
| rpl::start_with_next([this](Wrap value) { | rpl::start_with_next([this](Wrap value) {
if (value == Wrap::Side if (value == Wrap::Side
&& TypeToTabIndex(type())) { && TypeToTabIndex(type())) {
@ -81,6 +80,7 @@ void InnerWidget::setupOtherTypes(rpl::producer<Wrap> &&wrap) {
_otherTypes.destroy(); _otherTypes.destroy();
refreshHeight(); refreshHeight();
} }
refreshSearchField();
}, lifetime()); }, lifetime());
} }
@ -117,8 +117,9 @@ void InnerWidget::createTypeButtons() {
const style::icon &icon) { const style::icon &icon) {
auto result = AddButton( auto result = AddButton(
content, content,
controller(), _controller->window(),
peer(), _controller->peer(),
_controller->migrated(),
type, type,
tracker); tracker);
object_ptr<Profile::FloatingIcon>( object_ptr<Profile::FloatingIcon>(
@ -131,7 +132,7 @@ void InnerWidget::createTypeButtons() {
const style::icon &icon) { const style::icon &icon) {
auto result = AddCommonGroupsButton( auto result = AddCommonGroupsButton(
content, content,
controller(), _controller->window(),
user, user,
tracker); tracker);
object_ptr<Profile::FloatingIcon>( object_ptr<Profile::FloatingIcon>(
@ -142,7 +143,7 @@ void InnerWidget::createTypeButtons() {
addMediaButton(Type::MusicFile, st::infoIconMediaAudio); addMediaButton(Type::MusicFile, st::infoIconMediaAudio);
addMediaButton(Type::Link, st::infoIconMediaLink); addMediaButton(Type::Link, st::infoIconMediaLink);
if (auto user = peer()->asUser()) { if (auto user = _controller->peer()->asUser()) {
addCommonGroupsButton(user, st::infoIconMediaGroup); addCommonGroupsButton(user, st::infoIconMediaGroup);
} }
addMediaButton(Type::VoiceFile, st::infoIconMediaVoice); addMediaButton(Type::VoiceFile, st::infoIconMediaVoice);
@ -170,20 +171,19 @@ void InnerWidget::createTabs() {
_otherTabs->sectionActivated() _otherTabs->sectionActivated()
| rpl::map([](int index) { return TabIndexToType(index); }) | rpl::map([](int index) { return TabIndexToType(index); })
| rpl::start_with_next( | rpl::start_with_next(
[this](Type type) { [this](Type newType) {
if (_list->type() != type) { if (type() != newType) {
switchToTab(Memento(peer()->id, type)); switchToTab(Memento(
_controller->peerId(),
_controller->migratedPeerId(),
newType));
} }
}, },
_otherTabs->lifetime()); _otherTabs->lifetime());
} }
not_null<PeerData*> InnerWidget::peer() const {
return _list->peer();
}
Type InnerWidget::type() const { Type InnerWidget::type() const {
return _list->type(); return _controller->section().mediaType();
} }
void InnerWidget::visibleTopBottomUpdated( void InnerWidget::visibleTopBottomUpdated(
@ -193,7 +193,7 @@ void InnerWidget::visibleTopBottomUpdated(
} }
bool InnerWidget::showInternal(not_null<Memento*> memento) { bool InnerWidget::showInternal(not_null<Memento*> memento) {
if (memento->peerId() != peer()->id) { if (!_controller->validateMementoPeer(memento)) {
return false; return false;
} }
auto mementoType = memento->section().mediaType(); auto mementoType = memento->section().mediaType();
@ -210,8 +210,9 @@ bool InnerWidget::showInternal(not_null<Memento*> memento) {
} }
void InnerWidget::switchToTab(Memento &&memento) { void InnerWidget::switchToTab(Memento &&memento) {
auto type = memento.section().mediaType(); // Save state of the tab before setSection() call.
_list = setupList(controller(), peer(), type); _controller->setSection(memento.section());
_list = setupList();
restoreState(&memento); restoreState(&memento);
_list->show(); _list->show();
_list->resizeToWidth(width()); _list->resizeToWidth(width());
@ -219,48 +220,28 @@ void InnerWidget::switchToTab(Memento &&memento) {
if (_otherTypes) { if (_otherTypes) {
_otherTabsShadow->raise(); _otherTabsShadow->raise();
_otherTypes->raise(); _otherTypes->raise();
_otherTabs->setActiveSection(*TypeToTabIndex(type)); _otherTabs->setActiveSection(*TypeToTabIndex(type()));
} }
} }
not_null<Window::Controller*> InnerWidget::controller() const { void InnerWidget::refreshSearchField() {
return _list->controller(); auto search = _controller->searchFieldController();
} if (search && _otherTabs) {
_searchField = search->createView(
object_ptr<ListWidget> InnerWidget::setupList(
not_null<Window::Controller*> controller,
not_null<PeerData*> peer,
Type type) {
if (SharedMediaAllowSearch(type)) {
_searchFieldController
= std::make_unique<Ui::SearchFieldController>();
_searchFieldController->queryValue()
| rpl::start_with_next([=](QString &&query) {
_searchController.setQuery(produceSearchQuery(
peer,
type,
std::move(query)));
}, _searchFieldController->lifetime());
_searchField = _searchFieldController->createView(
this, this,
st::infoMediaSearch); st::infoMediaSearch);
_searchField->resizeToWidth(width()); _searchField->resizeToWidth(width());
_searchField->show(); _searchField->show();
} else { } else {
_searchField = nullptr; _searchField = nullptr;
_searchFieldController = nullptr;
} }
_searchController.setQueryFast(produceSearchQuery(peer, type)); }
object_ptr<ListWidget> InnerWidget::setupList() {
refreshSearchField();
auto result = object_ptr<ListWidget>( auto result = object_ptr<ListWidget>(
this, this,
controller, _controller);
peer,
type,
produceListSource());
_searchController.sourceChanged()
| rpl::start_with_next([widget = result.data()]{
widget->restart();
}, result->lifetime());
result->heightValue() result->heightValue()
| rpl::start_with_next( | rpl::start_with_next(
[this] { refreshHeight(); }, [this] { refreshHeight(); },
@ -296,47 +277,6 @@ void InnerWidget::cancelSelection() {
InnerWidget::~InnerWidget() = default; InnerWidget::~InnerWidget() = default;
ListWidget::Source InnerWidget::produceListSource() {
return [this](
SparseIdsMergedSlice::UniversalMsgId aroundId,
int limitBefore,
int limitAfter) {
auto query = _searchController.currentQuery();
if (query.query.isEmpty()) {
return SharedMediaMergedViewer(
SharedMediaMergedKey(
SparseIdsMergedSlice::Key(
query.peerId,
query.migratedPeerId,
aroundId),
query.type),
limitBefore,
limitAfter);
}
return _searchController.idsSlice(
aroundId,
limitBefore,
limitAfter);
};
}
auto InnerWidget::produceSearchQuery(
not_null<PeerData*> peer,
Type type,
QString &&query) const -> SearchQuery {
auto result = SearchQuery();
result.type = type;
result.peerId = peer->id;
result.query = std::move(query);
result.migratedPeerId = [&] {
if (auto migrateFrom = peer->migrateFrom()) {
return migrateFrom->id;
}
return PeerId(0);
}();
return result;
}
int InnerWidget::resizeGetHeight(int newWidth) { int InnerWidget::resizeGetHeight(int newWidth) {
_inResize = true; _inResize = true;
auto guard = gsl::finally([this] { _inResize = false; }); auto guard = gsl::finally([this] { _inResize = false; });

View File

@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#pragma once #pragma once
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
#include "base/unique_qptr.h"
#include "info/media/info_media_widget.h" #include "info/media/info_media_widget.h"
#include "info/media/info_media_list_widget.h" #include "info/media/info_media_list_widget.h"
#include "history/history_search_controller.h" #include "history/history_search_controller.h"
@ -32,6 +33,9 @@ class SearchFieldController;
} // namespace Ui } // namespace Ui
namespace Info { namespace Info {
class Controller;
namespace Media { namespace Media {
class Memento; class Memento;
@ -42,13 +46,7 @@ public:
using Type = Widget::Type; using Type = Widget::Type;
InnerWidget( InnerWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> &&wrap, not_null<Controller*> controller);
not_null<Window::Controller*> controller,
not_null<PeerData*> peer,
Type type);
not_null<PeerData*> peer() const;
Type type() const;
bool showInternal(not_null<Memento*> memento); bool showInternal(not_null<Memento*> memento);
@ -72,38 +70,29 @@ protected:
private: private:
int recountHeight(); int recountHeight();
void refreshHeight(); void refreshHeight();
void setupOtherTypes(rpl::producer<Wrap> &&wrap); void setupOtherTypes();
void createOtherTypes(); void createOtherTypes();
void createTypeButtons(); void createTypeButtons();
void createTabs(); void createTabs();
void switchToTab(Memento &&memento); void switchToTab(Memento &&memento);
using SearchQuery = Api::DelayedSearchController::Query; Type type() const;
ListWidget::Source produceListSource();
SearchQuery produceSearchQuery(
not_null<PeerData*> peer,
Type type,
QString &&query = QString()) const;
not_null<Window::Controller*> controller() const; void refreshSearchField();
object_ptr<ListWidget> setupList();
object_ptr<ListWidget> setupList( const not_null<Controller*> _controller;
not_null<Window::Controller*> controller,
not_null<PeerData*> peer,
Type type);
bool _inResize = false;
Ui::SettingsSlider *_otherTabs = nullptr; Ui::SettingsSlider *_otherTabs = nullptr;
object_ptr<Ui::VerticalLayout> _otherTypes = { nullptr }; object_ptr<Ui::VerticalLayout> _otherTypes = { nullptr };
object_ptr<Ui::PlainShadow> _otherTabsShadow = { nullptr }; object_ptr<Ui::PlainShadow> _otherTabsShadow = { nullptr };
std::unique_ptr<Ui::SearchFieldController> _searchFieldController; base::unique_qptr<Ui::RpWidget> _searchField = nullptr;
Ui::RpWidget *_searchField = nullptr;
object_ptr<ListWidget> _list = { nullptr }; object_ptr<ListWidget> _list = { nullptr };
bool _inResize = false;
rpl::event_stream<int> _scrollToRequests; rpl::event_stream<int> _scrollToRequests;
rpl::event_stream<rpl::producer<SelectedItems>> _selectedLists; rpl::event_stream<rpl::producer<SelectedItems>> _selectedLists;
Api::DelayedSearchController _searchController;
}; };

View File

@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/ */
#include "info/media/info_media_list_widget.h" #include "info/media/info_media_list_widget.h"
#include "info/info_controller.h"
#include "overview/overview_layout.h" #include "overview/overview_layout.h"
#include "history/history_media_types.h" #include "history/history_media_types.h"
#include "history/history_item.h" #include "history/history_item.h"
@ -538,15 +539,12 @@ void ListWidget::Section::refreshHeight() {
ListWidget::ListWidget( ListWidget::ListWidget(
QWidget *parent, QWidget *parent,
not_null<Window::Controller*> controller, not_null<Controller*> controller)
not_null<PeerData*> peer,
Type type,
Source source)
: RpWidget(parent) : RpWidget(parent)
, _controller(controller) , _controller(controller)
, _peer(peer) , _peer(_controller->peer())
, _type(type) , _migrated(_controller->migrated())
, _source(std::move(source)) , _type(_controller->section().mediaType())
, _slice(sliceKey(_universalAroundId)) { , _slice(sliceKey(_universalAroundId)) {
setAttribute(Qt::WA_MouseTracking); setAttribute(Qt::WA_MouseTracking);
start(); start();
@ -574,6 +572,10 @@ void ListWidget::start() {
| rpl::start_with_next([this](auto item) { | rpl::start_with_next([this](auto item) {
repaintItem(item); repaintItem(item);
}, lifetime()); }, lifetime());
_controller->mediaSourceChanged()
| rpl::start_with_next([this]{
restart();
}, lifetime());
} }
void ListWidget::restart() { void ListWidget::restart() {
@ -733,13 +735,13 @@ void ListWidget::repaintItem(QRect itemGeometry) {
bool ListWidget::isMyItem(not_null<const HistoryItem*> item) const { bool ListWidget::isMyItem(not_null<const HistoryItem*> item) const {
auto peer = item->history()->peer; auto peer = item->history()->peer;
return (_peer == peer || _peer == peer->migrateTo()); return (_peer == peer) || (_migrated == peer);
} }
bool ListWidget::isPossiblyMyId(FullMsgId fullId) const { bool ListWidget::isPossiblyMyId(FullMsgId fullId) const {
return (fullId.channel != 0) return (fullId.channel != 0)
? (_peer->isChannel() && _peer->bareId() == fullId.channel) ? (_peer->isChannel() && _peer->bareId() == fullId.channel)
: (!_peer->isChannel() || _peer->migrateFrom()); : (!_peer->isChannel() || _migrated);
} }
bool ListWidget::isItemLayout( bool ListWidget::isItemLayout(
@ -757,8 +759,8 @@ void ListWidget::invalidatePaletteCache() {
SparseIdsMergedSlice::Key ListWidget::sliceKey( SparseIdsMergedSlice::Key ListWidget::sliceKey(
UniversalMsgId universalId) const { UniversalMsgId universalId) const {
using Key = SparseIdsMergedSlice::Key; using Key = SparseIdsMergedSlice::Key;
if (auto migrateFrom = _peer->migrateFrom()) { if (_migrated) {
return Key(_peer->id, migrateFrom->id, universalId); return Key(_peer->id, _migrated->id, universalId);
} }
if (universalId < 0) { if (universalId < 0) {
// Convert back to plain id for non-migrated histories. // Convert back to plain id for non-migrated histories.
@ -769,7 +771,10 @@ SparseIdsMergedSlice::Key ListWidget::sliceKey(
void ListWidget::refreshViewer() { void ListWidget::refreshViewer() {
_viewerLifetime.destroy(); _viewerLifetime.destroy();
_source(_universalAroundId, _idsLimit, _idsLimit) _controller->mediaSource(
sliceKey(_universalAroundId).universalId,
_idsLimit,
_idsLimit)
| rpl::start_with_next([this]( | rpl::start_with_next([this](
SparseIdsMergedSlice &&slice) { SparseIdsMergedSlice &&slice) {
_slice = std::move(slice); _slice = std::move(slice);
@ -1752,8 +1757,8 @@ void ListWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butto
auto pressLayout = _overLayout; auto pressLayout = _overLayout;
_mouseAction = MouseAction::None; _mouseAction = MouseAction::None;
_pressWasInactive = _controller->window()->wasInactivePress(); _pressWasInactive = _controller->window()->window()->wasInactivePress();
if (_pressWasInactive) _controller->window()->setInactivePress(false); if (_pressWasInactive) _controller->window()->window()->setInactivePress(false);
if (ClickHandler::getPressed() && !hasSelected()) { if (ClickHandler::getPressed() && !hasSelected()) {
_mouseAction = MouseAction::PrepareDrag; _mouseAction = MouseAction::PrepareDrag;

View File

@ -39,6 +39,9 @@ class Controller;
} // namespace Window } // namespace Window
namespace Info { namespace Info {
class Controller;
namespace Media { namespace Media {
using BaseLayout = Overview::Layout::ItemBase; using BaseLayout = Overview::Layout::ItemBase;
@ -47,27 +50,9 @@ using UniversalMsgId = int32;
class ListWidget : public Ui::RpWidget { class ListWidget : public Ui::RpWidget {
public: public:
using Type = Widget::Type; using Type = Widget::Type;
using Source = base::lambda<
rpl::producer<SparseIdsMergedSlice>(
SparseIdsMergedSlice::UniversalMsgId aroundId,
int limitBefore,
int limitAfter)>;
ListWidget( ListWidget(
QWidget *parent, QWidget *parent,
not_null<Window::Controller*> controller, not_null<Controller*> controller);
not_null<PeerData*> peer,
Type type,
Source source);
not_null<Window::Controller*> controller() const {
return _controller;
}
not_null<PeerData*> peer() const {
return _peer;
}
Type type() const {
return _type;
}
void restart(); void restart();
@ -103,6 +88,7 @@ protected:
void leaveEventHook(QEvent *e) override; void leaveEventHook(QEvent *e) override;
private: private:
using Type = Widget::Type;
enum class MouseAction { enum class MouseAction {
None, None,
PrepareDrag, PrepareDrag,
@ -280,10 +266,10 @@ private:
void validateTrippleClickStartTime(); void validateTrippleClickStartTime();
void checkMoveToOtherViewer(); void checkMoveToOtherViewer();
not_null<Window::Controller*> _controller; const not_null<Controller*> _controller;
not_null<PeerData*> _peer; const not_null<PeerData*> _peer;
PeerData * const _migrated = nullptr;
Type _type = Type::Photo; Type _type = Type::Photo;
Source _source;
static constexpr auto kMinimalIdsLimit = 16; static constexpr auto kMinimalIdsLimit = 16;
static constexpr auto kDefaultAroundId = (ServerMaxMsgId - 1); static constexpr auto kDefaultAroundId = (ServerMaxMsgId - 1);

View File

@ -21,39 +21,41 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "info/media/info_media_widget.h" #include "info/media/info_media_widget.h"
#include "info/media/info_media_inner_widget.h" #include "info/media/info_media_inner_widget.h"
#include "info/info_controller.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
namespace Info { namespace Info {
namespace Media { namespace Media {
Memento::Memento(not_null<Controller*> controller)
: Memento(
controller->peerId(),
controller->migratedPeerId(),
controller->section().mediaType()) {
}
Section Memento::section() const {
return Section(_type);
}
object_ptr<ContentWidget> Memento::createWidget( object_ptr<ContentWidget> Memento::createWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller,
not_null<Window::Controller*> controller,
const QRect &geometry) { const QRect &geometry) {
auto result = object_ptr<Widget>( auto result = object_ptr<Widget>(
parent, parent,
std::move(wrap), controller);
controller,
App::peer(peerId()),
_type);
result->setInternalState(geometry, this); result->setInternalState(geometry, this);
return std::move(result); return std::move(result);
} }
Widget::Widget( Widget::Widget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller)
not_null<Window::Controller*> controller, : ContentWidget(parent, controller) {
not_null<PeerData*> peer,
Type type)
: ContentWidget(parent, rpl::duplicate(wrap), controller, peer) {
_inner = setInnerWidget(object_ptr<InnerWidget>( _inner = setInnerWidget(object_ptr<InnerWidget>(
this, this,
std::move(wrap), controller));
controller,
peer,
type));
_inner->scrollToRequests() _inner->scrollToRequests()
| rpl::start_with_next([this](int skip) { | rpl::start_with_next([this](int skip) {
scrollTo({ skip, -1 }); scrollTo({ skip, -1 });
@ -68,15 +70,10 @@ void Widget::cancelSelection() {
_inner->cancelSelection(); _inner->cancelSelection();
} }
Section Widget::section() const {
return Section(type());
}
Widget::Type Widget::type() const {
return _inner->type();
}
bool Widget::showInternal(not_null<ContentMemento*> memento) { bool Widget::showInternal(not_null<ContentMemento*> memento) {
if (!controller()->validateMementoPeer(memento)) {
return false;
}
if (auto mediaMemento = dynamic_cast<Memento*>(memento.get())) { if (auto mediaMemento = dynamic_cast<Memento*>(memento.get())) {
if (_inner->showInternal(mediaMemento)) { if (_inner->showInternal(mediaMemento)) {
return true; return true;
@ -92,7 +89,7 @@ void Widget::setInternalState(const QRect &geometry, not_null<Memento*> memento)
} }
std::unique_ptr<ContentMemento> Widget::createMemento() { std::unique_ptr<ContentMemento> Widget::createMemento() {
auto result = std::make_unique<Memento>(peer()->id, type()); auto result = std::make_unique<Memento>(controller());
saveState(result.get()); saveState(result.get());
return std::move(result); return std::move(result);
} }

View File

@ -33,20 +33,19 @@ class Memento final : public ContentMemento {
public: public:
using Type = Storage::SharedMediaType; using Type = Storage::SharedMediaType;
Memento(PeerId peerId, Type type) Memento(not_null<Controller*> controller);
: ContentMemento(peerId)
Memento(PeerId peerId, PeerId migratedPeerId, Type type)
: ContentMemento(peerId, migratedPeerId)
, _type(type) { , _type(type) {
} }
object_ptr<ContentWidget> createWidget( object_ptr<ContentWidget> createWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller,
not_null<Window::Controller*> controller,
const QRect &geometry) override; const QRect &geometry) override;
Section section() const override { Section section() const override;
return Section(_type);
}
Type type() const { Type type() const {
return _type; return _type;
@ -92,13 +91,7 @@ public:
Widget( Widget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller);
not_null<Window::Controller*> controller,
not_null<PeerData*> peer,
Type type);
Type type() const;
Section section() const override;
bool showInternal( bool showInternal(
not_null<ContentMemento*> memento) override; not_null<ContentMemento*> memento) override;
@ -114,7 +107,7 @@ public:
private: private:
void saveState(not_null<Memento*> memento); void saveState(not_null<Memento*> memento);
void restoreState(not_null<Memento*> memento); void restoreState(not_null<Memento*> memento);
InnerWidget *_inner = nullptr; InnerWidget *_inner = nullptr;
}; };

View File

@ -24,6 +24,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include <rpl/combine_previous.h> #include <rpl/combine_previous.h>
#include <rpl/flatten_latest.h> #include <rpl/flatten_latest.h>
#include "info/info_memento.h" #include "info/info_memento.h"
#include "info/info_controller.h"
#include "info/info_top_bar_override.h"
#include "info/profile/info_profile_button.h" #include "info/profile/info_profile_button.h"
#include "info/profile/info_profile_widget.h" #include "info/profile/info_profile_widget.h"
#include "info/profile/info_profile_text.h" #include "info/profile/info_profile_text.h"
@ -32,7 +34,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "info/profile/info_profile_icon.h" #include "info/profile/info_profile_icon.h"
#include "info/profile/info_profile_members.h" #include "info/profile/info_profile_members.h"
#include "info/media/info_media_buttons.h" #include "info/media/info_media_buttons.h"
#include "info/info_top_bar_override.h"
#include "boxes/abstract_box.h" #include "boxes/abstract_box.h"
#include "boxes/add_contact_box.h" #include "boxes/add_contact_box.h"
#include "boxes/confirm_box.h" #include "boxes/confirm_box.h"
@ -59,13 +60,12 @@ namespace Profile {
InnerWidget::InnerWidget( InnerWidget::InnerWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> &&wrapValue, not_null<Controller*> controller)
not_null<Window::Controller*> controller,
not_null<PeerData*> peer)
: RpWidget(parent) : RpWidget(parent)
, _controller(controller) , _controller(controller)
, _peer(peer) , _peer(_controller->peer())
, _content(setupContent(this, std::move(wrapValue))) { , _migrated(_controller->migrated())
, _content(setupContent(this)) {
_content->heightValue() _content->heightValue()
| rpl::start_with_next([this](int height) { | rpl::start_with_next([this](int height) {
resizeToWidth(width()); resizeToWidth(width());
@ -84,8 +84,7 @@ rpl::producer<bool> InnerWidget::canHideDetails() const {
} }
object_ptr<Ui::RpWidget> InnerWidget::setupContent( object_ptr<Ui::RpWidget> InnerWidget::setupContent(
RpWidget *parent, RpWidget *parent) {
rpl::producer<Wrap> &&wrapValue) {
auto result = object_ptr<Ui::VerticalLayout>(parent); auto result = object_ptr<Ui::VerticalLayout>(parent);
_cover = result->add(object_ptr<Cover>( _cover = result->add(object_ptr<Cover>(
result, result,
@ -101,7 +100,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
} else { } else {
result->add(std::move(details)); result->add(std::move(details));
} }
result->add(setupSharedMedia(result, rpl::duplicate(wrapValue))); result->add(setupSharedMedia(result));
result->add(object_ptr<BoxContentDivider>(result)); result->add(object_ptr<BoxContentDivider>(result));
if (auto user = _peer->asUser()) { if (auto user = _peer->asUser()) {
result->add(setupUserActions(result, user)); result->add(setupUserActions(result, user));
@ -114,7 +113,6 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
_members = result->add(object_ptr<Members>( _members = result->add(object_ptr<Members>(
result, result,
_controller, _controller,
std::move(wrapValue),
_peer) _peer)
); );
_members->scrollToRequests() _members->scrollToRequests()
@ -241,10 +239,10 @@ void InnerWidget::setupUserButtons(
addButton( addButton(
Lang::Viewer(lng_profile_send_message) | ToUpperValue() Lang::Viewer(lng_profile_send_message) | ToUpperValue()
)->toggleOn( )->toggleOn(
_controller->historyPeer.value() _controller->window()->historyPeer.value()
| rpl::map($1 != user) | rpl::map($1 != user)
)->entity()->addClickHandler([this, user] { )->entity()->addClickHandler([this, user] {
_controller->showPeerHistory( _controller->window()->showPeerHistory(
user, user,
Window::SectionShow::Way::Forward); Window::SectionShow::Way::Forward);
}); });
@ -266,8 +264,7 @@ void InnerWidget::setupUserButtons(
} }
object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia( object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
RpWidget *parent, RpWidget *parent) {
rpl::producer<Wrap> &&wrapValue) {
using namespace rpl::mappers; using namespace rpl::mappers;
using MediaType = Media::Type; using MediaType = Media::Type;
@ -278,8 +275,9 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
const style::icon &icon) { const style::icon &icon) {
auto result = Media::AddButton( auto result = Media::AddButton(
content, content,
_controller, _controller->window(),
peer(), _peer,
_migrated,
type, type,
tracker); tracker);
object_ptr<Profile::FloatingIcon>( object_ptr<Profile::FloatingIcon>(
@ -292,7 +290,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
const style::icon &icon) { const style::icon &icon) {
auto result = Media::AddCommonGroupsButton( auto result = Media::AddCommonGroupsButton(
content, content,
_controller, _controller->window(),
user, user,
tracker); tracker);
object_ptr<Profile::FloatingIcon>( object_ptr<Profile::FloatingIcon>(
@ -306,7 +304,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
addMediaButton(MediaType::File, st::infoIconMediaFile); addMediaButton(MediaType::File, st::infoIconMediaFile);
addMediaButton(MediaType::MusicFile, st::infoIconMediaAudio); addMediaButton(MediaType::MusicFile, st::infoIconMediaAudio);
addMediaButton(MediaType::Link, st::infoIconMediaLink); addMediaButton(MediaType::Link, st::infoIconMediaLink);
if (auto user = peer()->asUser()) { if (auto user = _peer->asUser()) {
addCommonGroupsButton(user, st::infoIconMediaGroup); addCommonGroupsButton(user, st::infoIconMediaGroup);
} }
addMediaButton(MediaType::VoiceFile, st::infoIconMediaVoice); addMediaButton(MediaType::VoiceFile, st::infoIconMediaVoice);
@ -320,7 +318,7 @@ object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(
using ToggledData = std::tuple<bool, Wrap, bool>; using ToggledData = std::tuple<bool, Wrap, bool>;
rpl::combine( rpl::combine(
tracker.atLeastOneShownValue(), tracker.atLeastOneShownValue(),
std::move(wrapValue), _controller->wrapValue(),
_isStackBottom.events()) _isStackBottom.events())
| rpl::combine_previous(ToggledData()) | rpl::combine_previous(ToggledData())
| rpl::start_with_next([wrap = result.data()]( | rpl::start_with_next([wrap = result.data()](

View File

@ -37,6 +37,7 @@ struct ScrollToRequest;
namespace Info { namespace Info {
enum class Wrap; enum class Wrap;
class Controller;
namespace Profile { namespace Profile {
@ -48,13 +49,7 @@ class InnerWidget final : public Ui::RpWidget {
public: public:
InnerWidget( InnerWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> &&wrapValue, not_null<Controller*> controller);
not_null<Window::Controller*> controller,
not_null<PeerData*> peer);
not_null<PeerData*> peer() const {
return _peer;
}
void saveState(not_null<Memento*> memento); void saveState(not_null<Memento*> memento);
void restoreState(not_null<Memento*> memento); void restoreState(not_null<Memento*> memento);
@ -77,13 +72,9 @@ protected:
int visibleBottom) override; int visibleBottom) override;
private: private:
object_ptr<RpWidget> setupContent( object_ptr<RpWidget> setupContent(RpWidget *parent);
RpWidget *parent,
rpl::producer<Wrap> &&wrapValue);
object_ptr<RpWidget> setupDetails(RpWidget *parent) const; object_ptr<RpWidget> setupDetails(RpWidget *parent) const;
object_ptr<RpWidget> setupSharedMedia( object_ptr<RpWidget> setupSharedMedia(RpWidget *parent);
RpWidget *parent,
rpl::producer<Wrap> &&wrapValue);
object_ptr<RpWidget> setupMuteToggle(RpWidget *parent) const; object_ptr<RpWidget> setupMuteToggle(RpWidget *parent) const;
object_ptr<RpWidget> setupInfo(RpWidget *parent) const; object_ptr<RpWidget> setupInfo(RpWidget *parent) const;
void setupUserButtons( void setupUserButtons(
@ -105,8 +96,9 @@ private:
rpl::event_stream<bool> _isStackBottom; rpl::event_stream<bool> _isStackBottom;
not_null<Window::Controller*> _controller; const not_null<Controller*> _controller;
not_null<PeerData*> _peer; const not_null<PeerData*> _peer;
PeerData * const _migrated = nullptr;
Members *_members = nullptr; Members *_members = nullptr;
Cover *_cover = nullptr; Cover *_cover = nullptr;

View File

@ -27,6 +27,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "info/profile/info_profile_values.h" #include "info/profile/info_profile_values.h"
#include "info/profile/info_profile_members_controllers.h" #include "info/profile/info_profile_members_controllers.h"
#include "info/info_content_widget.h" #include "info/info_content_widget.h"
#include "info/info_controller.h"
#include "profile/profile_block_group_members.h" #include "profile/profile_block_group_members.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
@ -48,12 +49,11 @@ constexpr auto kEnableSearchMembersAfterCount = 50;
Members::Members( Members::Members(
QWidget *parent, QWidget *parent,
not_null<Window::Controller*> controller, not_null<Controller*> controller,
rpl::producer<Wrap> &&wrapValue,
not_null<PeerData*> peer) not_null<PeerData*> peer)
: RpWidget(parent) : RpWidget(parent)
, _peer(peer) , _peer(peer)
, _listController(CreateMembersController(controller, _peer)) , _listController(CreateMembersController(controller->window(), _peer))
, _labelWrap(this) , _labelWrap(this)
, _label(setupHeader()) , _label(setupHeader())
, _addMember(this, st::infoMembersAddMember) , _addMember(this, st::infoMembersAddMember)
@ -65,7 +65,7 @@ Members::Members(
, _cancelSearch(this, st::infoMembersCancelSearch) , _cancelSearch(this, st::infoMembersCancelSearch)
, _list(setupList(this, _listController.get())) { , _list(setupList(this, _listController.get())) {
setupButtons(); setupButtons();
std::move(wrapValue) controller->wrapValue()
| rpl::start_with_next([this](Wrap wrap) { | rpl::start_with_next([this](Wrap wrap) {
_wrap = wrap; _wrap = wrap;
updateSearchOverrides(); updateSearchOverrides();

View File

@ -38,6 +38,7 @@ class ParticipantsBoxController;
namespace Info { namespace Info {
class Controller;
enum class Wrap; enum class Wrap;
namespace Profile { namespace Profile {
@ -50,8 +51,7 @@ class Members
public: public:
Members( Members(
QWidget *parent, QWidget *parent,
not_null<Window::Controller*> controller, not_null<Controller*> controller,
rpl::producer<Wrap> &&wrapValue,
not_null<PeerData*> peer); not_null<PeerData*> peer);
rpl::producer<Ui::ScrollToRequest> scrollToRequests() const { rpl::producer<Ui::ScrollToRequest> scrollToRequests() const {

View File

@ -164,17 +164,14 @@ rpl::producer<int> MembersCountValue(
rpl::producer<int> SharedMediaCountValue( rpl::producer<int> SharedMediaCountValue(
not_null<PeerData*> peer, not_null<PeerData*> peer,
PeerData *migrated,
Storage::SharedMediaType type) { Storage::SharedMediaType type) {
auto real = peer->migrateTo() ? peer->migrateTo() : peer;
auto migrated = real->migrateFrom()
? real->migrateFrom()
: nullptr;
auto aroundId = 0; auto aroundId = 0;
auto limit = 0; auto limit = 0;
auto updated = SharedMediaMergedViewer( auto updated = SharedMediaMergedViewer(
SharedMediaMergedKey( SharedMediaMergedKey(
SparseIdsMergedSlice::Key( SparseIdsMergedSlice::Key(
real->id, peer->id,
migrated ? migrated->id : 0, migrated ? migrated->id : 0,
aroundId), aroundId),
type), type),

View File

@ -67,6 +67,7 @@ rpl::producer<int> MembersCountValue(
not_null<PeerData*> peer); not_null<PeerData*> peer);
rpl::producer<int> SharedMediaCountValue( rpl::producer<int> SharedMediaCountValue(
not_null<PeerData*> peer, not_null<PeerData*> peer,
PeerData *migrated,
Storage::SharedMediaType type); Storage::SharedMediaType type);
rpl::producer<int> CommonGroupsCountValue( rpl::producer<int> CommonGroupsCountValue(
not_null<UserData*> user); not_null<UserData*> user);

View File

@ -22,35 +22,39 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "info/profile/info_profile_inner_widget.h" #include "info/profile/info_profile_inner_widget.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "info/info_controller.h"
namespace Info { namespace Info {
namespace Profile { namespace Profile {
Memento::Memento(not_null<Controller*> controller)
: Memento(
controller->peerId(),
controller->migratedPeerId()) {
}
Section Memento::section() const {
return Section(Section::Type::Profile);
}
object_ptr<ContentWidget> Memento::createWidget( object_ptr<ContentWidget> Memento::createWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller,
not_null<Window::Controller*> controller,
const QRect &geometry) { const QRect &geometry) {
auto result = object_ptr<Widget>( auto result = object_ptr<Widget>(
parent, parent,
std::move(wrap), controller);
controller,
App::peer(peerId()));
result->setInternalState(geometry, this); result->setInternalState(geometry, this);
return std::move(result); return std::move(result);
} }
Widget::Widget( Widget::Widget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller)
not_null<Window::Controller*> controller, : ContentWidget(parent, controller) {
not_null<PeerData*> peer)
: ContentWidget(parent, rpl::duplicate(wrap), controller, peer) {
_inner = setInnerWidget(object_ptr<InnerWidget>( _inner = setInnerWidget(object_ptr<InnerWidget>(
this, this,
std::move(wrap), controller));
controller,
peer));
_inner->move(0, 0); _inner->move(0, 0);
_inner->scrollToRequests() _inner->scrollToRequests()
| rpl::start_with_next([this](Ui::ScrollToRequest request) { | rpl::start_with_next([this](Ui::ScrollToRequest request) {
@ -67,20 +71,17 @@ void Widget::setIsStackBottom(bool isStackBottom) {
_inner->setIsStackBottom(isStackBottom); _inner->setIsStackBottom(isStackBottom);
} }
Section Widget::section() const {
return Section(Section::Type::Profile);
}
void Widget::setInnerFocus() { void Widget::setInnerFocus() {
_inner->setFocus(); _inner->setFocus();
} }
bool Widget::showInternal(not_null<ContentMemento*> memento) { bool Widget::showInternal(not_null<ContentMemento*> memento) {
if (!controller()->validateMementoPeer(memento)) {
return false;
}
if (auto profileMemento = dynamic_cast<Memento*>(memento.get())) { if (auto profileMemento = dynamic_cast<Memento*>(memento.get())) {
if (profileMemento->peerId() == peer()->id) { restoreState(profileMemento);
restoreState(profileMemento); return true;
return true;
}
} }
return false; return false;
} }
@ -92,7 +93,7 @@ void Widget::setInternalState(const QRect &geometry, not_null<Memento*> memento)
} }
std::unique_ptr<ContentMemento> Widget::createMemento() { std::unique_ptr<ContentMemento> Widget::createMemento() {
auto result = std::make_unique<Memento>(peer()->id); auto result = std::make_unique<Memento>(controller());
saveState(result.get()); saveState(result.get());
return std::move(result); return std::move(result);
} }

View File

@ -31,18 +31,17 @@ class InnerWidget;
class Memento final : public ContentMemento { class Memento final : public ContentMemento {
public: public:
Memento(PeerId peerId) : ContentMemento(peerId) { Memento(not_null<Controller*> controller);
Memento(PeerId peerId, PeerId migratedPeerId)
: ContentMemento(peerId, migratedPeerId) {
} }
object_ptr<ContentWidget> createWidget( object_ptr<ContentWidget> createWidget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller,
not_null<Window::Controller*> controller,
const QRect &geometry) override; const QRect &geometry) override;
Section section() const override { Section section() const override;
return Section(Section::Type::Profile);
}
void setInfoExpanded(bool expanded) { void setInfoExpanded(bool expanded) {
_infoExpanded = expanded; _infoExpanded = expanded;
@ -74,12 +73,9 @@ class Widget final : public ContentWidget {
public: public:
Widget( Widget(
QWidget *parent, QWidget *parent,
rpl::producer<Wrap> wrap, not_null<Controller*> controller);
not_null<Window::Controller*> controller,
not_null<PeerData*> peer);
void setIsStackBottom(bool isStackBottom) override; void setIsStackBottom(bool isStackBottom) override;
Section section() const override;
bool showInternal( bool showInternal(
not_null<ContentMemento*> memento) override; not_null<ContentMemento*> memento) override;

View File

@ -50,17 +50,19 @@ public:
} }
auto events() const { auto events() const {
return make_producer<Value>([weak = weak()]( return make_producer<Value>([weak = weak()](
const auto &consumer) { const auto &consumer) {
if (auto strong = weak.lock()) { if (auto strong = weak.lock()) {
auto result = [weak, consumer] { auto result = [weak, consumer] {
if (auto strong = weak.lock()) { if (auto strong = weak.lock()) {
auto it = base::find(*strong, consumer); auto it = base::find(
if (it != strong->end()) { strong->consumers,
consumer);
if (it != strong->consumers.end()) {
it->terminate(); it->terminate();
} }
} }
}; };
strong->push_back(std::move(consumer)); strong->consumers.push_back(std::move(consumer));
return lifetime(std::move(result)); return lifetime(std::move(result));
} }
return lifetime(); return lifetime();
@ -76,9 +78,13 @@ public:
~event_stream(); ~event_stream();
private: private:
std::weak_ptr<std::vector<consumer<Value, no_error>>> weak() const; struct Data {
std::vector<consumer<Value, no_error>> consumers;
int depth = 0;
};
std::weak_ptr<Data> weak() const;
mutable std::shared_ptr<std::vector<consumer<Value, no_error>>> _consumers; mutable std::shared_ptr<Data> _data;
}; };
@ -88,13 +94,13 @@ inline event_stream<Value>::event_stream() {
template <typename Value> template <typename Value>
inline event_stream<Value>::event_stream(event_stream &&other) inline event_stream<Value>::event_stream(event_stream &&other)
: _consumers(base::take(other._consumers)) { : _data(base::take(other._data)) {
} }
template <typename Value> template <typename Value>
inline event_stream<Value> &event_stream<Value>::operator=( inline event_stream<Value> &event_stream<Value>::operator=(
event_stream &&other) { event_stream &&other) {
_consumers = base::take(other._consumers); _data = base::take(other._data);
return *this; return *this;
} }
@ -102,11 +108,13 @@ template <typename Value>
template <typename OtherValue> template <typename OtherValue>
inline void event_stream<Value>::fire_forward( inline void event_stream<Value>::fire_forward(
OtherValue &&value) const { OtherValue &&value) const {
if (!_consumers) { auto copy = _data;
if (!copy) {
return; return;
} }
auto &consumers = *_consumers; ++copy->depth;
auto &consumers = copy->consumers;
auto begin = base::index_based_begin(consumers); auto begin = base::index_based_begin(consumers);
auto end = base::index_based_end(consumers); auto end = base::index_based_end(consumers);
if (begin != end) { if (begin != end) {
@ -136,24 +144,28 @@ inline void event_stream<Value>::fire_forward(
} }
// Erase stale consumers. // Erase stale consumers.
consumers.erase(removeFrom.base(), consumers.end()); if (copy->depth == 1) {
consumers.erase(removeFrom.base(), consumers.end());
}
} }
} }
--copy->depth;
} }
template <typename Value> template <typename Value>
inline std::weak_ptr<std::vector<consumer<Value, no_error>>> event_stream<Value>::weak() const { inline auto event_stream<Value>::weak() const
if (!_consumers) { -> std::weak_ptr<Data> {
_consumers = std::make_shared<std::vector<consumer<Value, no_error>>>(); if (!_data) {
_data = std::make_shared<Data>();
} }
return _consumers; return _data;
} }
template <typename Value> template <typename Value>
inline event_stream<Value>::~event_stream() { inline event_stream<Value>::~event_stream() {
if (auto consumers = base::take(_consumers)) { if (auto data = base::take(_data)) {
for (auto &consumer : *consumers) { for (auto &consumer : data->consumers) {
consumer.put_done(); consumer.put_done();
} }
} }

View File

@ -81,6 +81,9 @@ public:
auto value() const { auto value() const {
return _changes.events_starting_with_copy(_data); return _changes.events_starting_with_copy(_data);
} }
auto changes() const {
return _changes.events();
}
private: private:
template <typename A, typename B> template <typename A, typename B>

View File

@ -29,20 +29,20 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
namespace Ui { namespace Ui {
object_ptr<Ui::RpWidget> SearchFieldController::createView( base::unique_qptr<Ui::RpWidget> SearchFieldController::createView(
QWidget *parent, QWidget *parent,
const style::SearchFieldRow &st) { const style::SearchFieldRow &st) {
auto result = object_ptr<Ui::FixedHeightWidget>( auto result = base::make_unique_q<Ui::FixedHeightWidget>(
parent, parent,
st.height); st.height);
auto cancel = CreateChild<Ui::CrossButton>( auto cancel = CreateChild<Ui::CrossButton>(
result.data(), result.get(),
st.fieldCancel); st.fieldCancel);
cancel->addClickHandler([=] { clearQuery(); }); cancel->addClickHandler([=] { clearQuery(); });
auto field = CreateChild<Ui::InputField>( auto field = CreateChild<Ui::InputField>(
result.data(), result.get(),
st.field, st.field,
langFactory(lng_dlg_filter), langFactory(lng_dlg_filter),
_query.current()); _query.current());
@ -54,7 +54,7 @@ object_ptr<Ui::RpWidget> SearchFieldController::createView(
clearQuery(); clearQuery();
}); });
auto shadow = CreateChild<Ui::PlainShadow>(result.data()); auto shadow = CreateChild<Ui::PlainShadow>(result.get());
shadow->show(); shadow->show();
result->widthValue() result->widthValue()
@ -84,7 +84,7 @@ object_ptr<Ui::RpWidget> SearchFieldController::createView(
_view.wrap->width()); _view.wrap->width());
}, result->lifetime()); }, result->lifetime());
_view.wrap.reset(result); _view.wrap.reset(result.get());
_view.cancel = cancel; _view.cancel = cancel;
_view.field = field; _view.field = field;
return std::move(result); return std::move(result);

View File

@ -35,7 +35,7 @@ class InputField;
class SearchFieldController { class SearchFieldController {
public: public:
object_ptr<Ui::RpWidget> createView( base::unique_qptr<Ui::RpWidget> createView(
QWidget *parent, QWidget *parent,
const style::SearchFieldRow &st); const style::SearchFieldRow &st);

View File

@ -219,6 +219,8 @@
<(src_loc)/info/info_common_groups_widget.h <(src_loc)/info/info_common_groups_widget.h
<(src_loc)/info/info_content_widget.cpp <(src_loc)/info/info_content_widget.cpp
<(src_loc)/info/info_content_widget.h <(src_loc)/info/info_content_widget.h
<(src_loc)/info/info_controller.cpp
<(src_loc)/info/info_controller.h
<(src_loc)/info/info_layer_widget.cpp <(src_loc)/info/info_layer_widget.cpp
<(src_loc)/info/info_layer_widget.h <(src_loc)/info/info_layer_widget.h
<(src_loc)/info/info_memento.cpp <(src_loc)/info/info_memento.cpp