diff --git a/Telegram/SourceFiles/base/unique_qptr.h b/Telegram/SourceFiles/base/unique_qptr.h index c87f1ba296..f10a357dab 100644 --- a/Telegram/SourceFiles/base/unique_qptr.h +++ b/Telegram/SourceFiles/base/unique_qptr.h @@ -40,7 +40,7 @@ public: unique_qptr &operator=(unique_qptr &&other) { if (_object != other._object) { destroy(); - _object = std::move(other._object); + _object = base::take(other._object); } return *this; } @@ -58,18 +58,17 @@ public: unique_qptr &operator=(unique_qptr &&other) { if (_object != other._object) { destroy(); - _object = std::move(other._object); + _object = base::take(other._object); } return *this; } unique_qptr &operator=(std::nullptr_t) { destroy(); - _object = nullptr; return *this; } - void reset(T *value) { + void reset(T *value = nullptr) { if (_object != value) { destroy(); _object = value; diff --git a/Telegram/SourceFiles/info/info_common_groups_inner_widget.cpp b/Telegram/SourceFiles/info/info_common_groups_inner_widget.cpp index 5a2daf79a6..d93c826be2 100644 --- a/Telegram/SourceFiles/info/info_common_groups_inner_widget.cpp +++ b/Telegram/SourceFiles/info/info_common_groups_inner_widget.cpp @@ -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_widget.h" +#include "info/info_controller.h" #include "lang/lang_keys.h" #include "styles/style_info.h" #include "styles/style_widgets.h" @@ -35,13 +36,13 @@ namespace { constexpr int kCommonGroupsPerPage = 40; -class Controller +class ListController : public PeerListController , private base::Subscriber , private MTP::Sender { public: - Controller( - not_null window, + ListController( + not_null controller, not_null user); void prepare() override; @@ -49,7 +50,7 @@ public: void loadMoreRows() override; private: - not_null _window; + const not_null _controller; not_null _user; mtpRequestId _preloadRequestId = 0; bool _allLoaded = false; @@ -57,21 +58,21 @@ private: }; -Controller::Controller( - not_null window, +ListController::ListController( + not_null controller, not_null user) : PeerListController() -, _window(window) +, _controller(controller) , _user(user) { } -void Controller::prepare() { +void ListController::prepare() { setSearchNoResultsText(lang(lng_blocked_list_not_found)); delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled); delegate()->peerListSetTitle(langFactory(lng_profile_common_groups_section)); } -void Controller::loadMoreRows() { +void ListController::loadMoreRows() { if (_preloadRequestId || _allLoaded) { return; } @@ -103,8 +104,8 @@ void Controller::loadMoreRows() { }).send(); } -void Controller::rowClicked(not_null row) { - _window->showPeerHistory( +void ListController::rowClicked(not_null row) { + _controller->window()->showPeerHistory( row->peer(), Window::SectionShow::Way::Forward); } @@ -113,11 +114,11 @@ void Controller::rowClicked(not_null row) { InnerWidget::InnerWidget( QWidget *parent, - not_null controller, + not_null controller, not_null user) : RpWidget(parent) , _user(user) -, _listController(std::make_unique(controller, _user)) +, _listController(std::make_unique(controller, _user)) , _list(setupList(this, _listController.get())) { setContent(_list.data()); _listController->setDelegate(static_cast(this)); diff --git a/Telegram/SourceFiles/info/info_common_groups_inner_widget.h b/Telegram/SourceFiles/info/info_common_groups_inner_widget.h index f12d835be8..06a3eb91a9 100644 --- a/Telegram/SourceFiles/info/info_common_groups_inner_widget.h +++ b/Telegram/SourceFiles/info/info_common_groups_inner_widget.h @@ -25,6 +25,9 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "boxes/peer_list_box.h" namespace Info { + +class Controller; + namespace CommonGroups { class Memento; @@ -35,7 +38,7 @@ class InnerWidget final public: InnerWidget( QWidget *parent, - not_null controller, + not_null controller, not_null user); not_null user() const { diff --git a/Telegram/SourceFiles/info/info_common_groups_widget.cpp b/Telegram/SourceFiles/info/info_common_groups_widget.cpp index eb7a249311..3ca5368229 100644 --- a/Telegram/SourceFiles/info/info_common_groups_widget.cpp +++ b/Telegram/SourceFiles/info/info_common_groups_widget.cpp @@ -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_inner_widget.h" +#include "info/info_controller.h" #include "ui/widgets/scroll_area.h" namespace Info { namespace CommonGroups { +Section Memento::section() const { + return Section(Section::Type::CommonGroups); +} + object_ptr Memento::createWidget( QWidget *parent, - rpl::producer wrap, - not_null controller, + not_null controller, const QRect &geometry) { auto result = object_ptr( parent, - std::move(wrap), controller, App::user(userId())); result->setInternalState(geometry, this); @@ -42,10 +45,9 @@ object_ptr Memento::createWidget( Widget::Widget( QWidget *parent, - rpl::producer wrap, - not_null controller, + not_null controller, not_null user) -: ContentWidget(parent, wrap, controller, user) { +: ContentWidget(parent, controller) { _inner = setInnerWidget(object_ptr( this, controller, @@ -56,11 +58,10 @@ not_null Widget::user() const { return _inner->user(); } -Section Widget::section() const { - return Section(Section::Type::CommonGroups); -} - bool Widget::showInternal(not_null memento) { + if (!controller()->validateMementoPeer(memento)) { + return false; + } if (auto groupsMemento = dynamic_cast(memento.get())) { if (groupsMemento->userId() == user()->bareId()) { restoreState(groupsMemento); diff --git a/Telegram/SourceFiles/info/info_common_groups_widget.h b/Telegram/SourceFiles/info/info_common_groups_widget.h index 77ae99bd51..eb9955fc9b 100644 --- a/Telegram/SourceFiles/info/info_common_groups_widget.h +++ b/Telegram/SourceFiles/info/info_common_groups_widget.h @@ -30,18 +30,16 @@ class InnerWidget; class Memento final : public ContentMemento { public: - Memento(UserId userId) : ContentMemento(peerFromUser(userId)) { + Memento(UserId userId) + : ContentMemento(peerFromUser(userId), 0) { } object_ptr createWidget( QWidget *parent, - rpl::producer wrap, - not_null controller, + not_null controller, const QRect &geometry) override; - Section section() const override { - return Section(Section::Type::CommonGroups); - } + Section section() const override; UserId userId() const { return peerToUser(peerId()); @@ -55,12 +53,10 @@ class Widget final : public ContentWidget { public: Widget( QWidget *parent, - rpl::producer wrap, - not_null controller, + not_null controller, not_null user); not_null user() const; - Section section() const override; bool showInternal( not_null memento) override; diff --git a/Telegram/SourceFiles/info/info_content_widget.cpp b/Telegram/SourceFiles/info/info_content_widget.cpp index e61344deaa..9c7f229629 100644 --- a/Telegram/SourceFiles/info/info_content_widget.cpp +++ b/Telegram/SourceFiles/info/info_content_widget.cpp @@ -31,6 +31,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "info/info_common_groups_widget.h" #include "info/info_layer_widget.h" #include "info/info_section_widget.h" +#include "info/info_controller.h" #include "styles/style_info.h" #include "styles/style_profile.h" @@ -38,22 +39,18 @@ namespace Info { ContentWidget::ContentWidget( QWidget *parent, - rpl::producer wrap, - not_null controller, - not_null peer) + not_null controller) : RpWidget(parent) , _controller(controller) -, _peer(peer) , _scroll(this, st::infoScroll) { setAttribute(Qt::WA_OpaquePaintEvent); - std::move(wrap) | rpl::start_with_next( - [this](Wrap value) { + _controller->wrapValue() + | rpl::start_with_next([this](Wrap value) { _bg = (value == Wrap::Layer) ? st::boxBg : st::profileBg; update(); - }, - lifetime()); + }, lifetime()); } void ContentWidget::resizeEvent(QResizeEvent *e) { diff --git a/Telegram/SourceFiles/info/info_content_widget.h b/Telegram/SourceFiles/info/info_content_widget.h index fbf4c57cef..b515b194a6 100644 --- a/Telegram/SourceFiles/info/info_content_widget.h +++ b/Telegram/SourceFiles/info/info_content_widget.h @@ -33,21 +33,16 @@ class ScrollArea; struct ScrollToRequest; } // namespace Ui -namespace Window { -class Controller; -} // namespace Window - namespace Info { class ContentMemento; +class Controller; class ContentWidget : public Ui::RpWidget { public: ContentWidget( QWidget *parent, - rpl::producer wrap, - not_null controller, - not_null peer); + not_null controller); virtual bool showInternal( not_null memento) = 0; @@ -57,11 +52,6 @@ public: virtual void setIsStackBottom(bool isStackBottom) { } - virtual Section section() const = 0; - not_null peer() const { - return _peer; - } - rpl::producer desiredHeightValue() const override; rpl::producer desiredShadowVisibility() const; bool hasTopBarShadow() const; @@ -94,7 +84,7 @@ protected: doSetInnerWidget(std::move(inner), scrollTopSkip)); } - not_null controller() const { + not_null controller() const { return _controller; } @@ -112,8 +102,7 @@ private: int scrollTopSkip); void updateControlsGeometry(); - const not_null _controller; - const not_null _peer; + const not_null _controller; style::color _bg; int _scrollTopSkip = 0; @@ -127,18 +116,23 @@ private: class ContentMemento { public: - ContentMemento(PeerId peerId) : _peerId(peerId) { + ContentMemento(PeerId peerId, PeerId migratedPeerId) + : _peerId(peerId) + , _migratedPeerId(migratedPeerId) { } virtual object_ptr createWidget( QWidget *parent, - rpl::producer wrap, - not_null controller, + not_null controller, const QRect &geometry) = 0; - virtual PeerId peerId() const { + PeerId peerId() const { return _peerId; } + PeerId migratedPeerId() const { + return _migratedPeerId; + } + virtual Section section() const = 0; virtual ~ContentMemento() = default; @@ -151,7 +145,8 @@ public: } private: - PeerId _peerId = 0; + const PeerId _peerId = 0; + const PeerId _migratedPeerId = 0; int _scrollTop = 0; }; diff --git a/Telegram/SourceFiles/info/info_controller.cpp b/Telegram/SourceFiles/info/info_controller.cpp new file mode 100644 index 0000000000..8ae3700ffc --- /dev/null +++ b/Telegram/SourceFiles/info/info_controller.cpp @@ -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 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 widget, + not_null window, + not_null 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 Controller::wrapValue() const { + return _widget->wrapValue(); +} + +bool Controller::validateMementoPeer( + not_null memento) const { + return memento->peerId() == peerId() + && memento->migratedPeerId() == migratedPeerId(); +} + +void Controller::setSection(const Section §ion) { + _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(); + _searchController->setQueryFast(produceSearchQuery()); + } else { + _searchController = nullptr; + } + if (hasMediaSearch) { + _searchFieldController + = std::make_unique(); + _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 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 diff --git a/Telegram/SourceFiles/info/info_controller.h b/Telegram/SourceFiles/info/info_controller.h new file mode 100644 index 0000000000..ed0e7831c0 --- /dev/null +++ b/Telegram/SourceFiles/info/info_controller.h @@ -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 +#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 widget, + not_null window, + not_null memento); + + not_null 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 §ion() const { + return _section; + } + + bool validateMementoPeer( + not_null memento) const; + + Wrap wrap() const; + rpl::producer wrapValue() const; + void setSection(const Section §ion); + + not_null window() const { + return _window; + } + Ui::SearchFieldController *searchFieldController() const { + return _searchFieldController.get(); + } + rpl::producer 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 _widget; + not_null _peer; + PeerData *_migrated = nullptr; + not_null _window; + rpl::variable _wrap; + Section _section; + + std::unique_ptr _searchFieldController; + std::unique_ptr _searchController; + + rpl::lifetime _lifetime; + +}; + +} // namespace Info \ No newline at end of file diff --git a/Telegram/SourceFiles/info/info_memento.cpp b/Telegram/SourceFiles/info/info_memento.cpp index 2cf8f1c7cd..ef718e65b0 100644 --- a/Telegram/SourceFiles/info/info_memento.cpp +++ b/Telegram/SourceFiles/info/info_memento.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "info/info_common_groups_widget.h" #include "info/info_section_widget.h" #include "info/info_layer_widget.h" +#include "info/info_controller.h" namespace Info { @@ -40,23 +41,28 @@ Memento::Memento(std::unique_ptr content) : _content(std::move(content)) { } -PeerId Memento::peerId() const { - return _content->peerId(); -} - -Section Memento::section() const { - return _content->section(); -} - std::unique_ptr Memento::Default( PeerId peerId, 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()) { case Section::Type::Profile: - return std::make_unique(peerId); + return std::make_unique( + peerId, + migratedPeerId); case Section::Type::Media: return std::make_unique( peerId, + migratedPeerId, section.mediaType()); case Section::Type::CommonGroups: Assert(peerIsUser(peerId)); diff --git a/Telegram/SourceFiles/info/info_memento.h b/Telegram/SourceFiles/info/info_memento.h index 8010788525..b4fef5be04 100644 --- a/Telegram/SourceFiles/info/info_memento.h +++ b/Telegram/SourceFiles/info/info_memento.h @@ -59,9 +59,6 @@ public: return _content.get(); } - PeerId peerId() const; - Section section() const; - ~Memento(); private: diff --git a/Telegram/SourceFiles/info/info_section_widget.cpp b/Telegram/SourceFiles/info/info_section_widget.cpp index c1b24eca59..309762962d 100644 --- a/Telegram/SourceFiles/info/info_section_widget.cpp +++ b/Telegram/SourceFiles/info/info_section_widget.cpp @@ -24,25 +24,26 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "info/info_wrap_widget.h" #include "info/info_layer_widget.h" #include "info/info_memento.h" +#include "info/info_controller.h" namespace Info { SectionWidget::SectionWidget( QWidget *parent, - not_null controller, + not_null window, Wrap wrap, not_null memento) -: Window::SectionWidget(parent, controller) -, _content(this, controller, wrap, memento) { +: Window::SectionWidget(parent, window) +, _content(this, window, wrap, memento) { init(); } SectionWidget::SectionWidget( QWidget *parent, - not_null controller, + not_null window, Wrap wrap, not_null memento) -: Window::SectionWidget(parent, controller) +: Window::SectionWidget(parent, window) , _content(memento->takeContent(this, wrap)) { init(); } @@ -55,6 +56,11 @@ void SectionWidget::init() { }, _content->lifetime()); } +not_null SectionWidget::controller() const { + Expects(_content != nullptr); + return _content->controller(); +} + PeerData *SectionWidget::peerForDialogs() const { return _content->peerForDialogs(); } @@ -83,19 +89,19 @@ bool SectionWidget::showInternal( } std::unique_ptr SectionWidget::createMemento() { - auto result = std::make_unique(_content->peer()->id); - _content->saveState(result.get()); - return std::move(result); + return _content->createMemento(); } object_ptr SectionWidget::moveContentToLayer( QRect bodyGeometry) { - if (_content->wrap() != Wrap::Narrow + if (controller()->wrap() != Wrap::Narrow || width() < LayerWidget::MinimalSupportedWidth()) { return nullptr; } return MoveMemento( - std::move(_content)).createLayer(controller(), bodyGeometry); + std::move(_content)).createLayer( + controller()->window(), + bodyGeometry); } bool SectionWidget::wheelEventFromFloatPlayer(QEvent *e) { diff --git a/Telegram/SourceFiles/info/info_section_widget.h b/Telegram/SourceFiles/info/info_section_widget.h index b1a440d8b7..499fcf8534 100644 --- a/Telegram/SourceFiles/info/info_section_widget.h +++ b/Telegram/SourceFiles/info/info_section_widget.h @@ -31,6 +31,7 @@ namespace Info { class Memento; class MoveMemento; +class Controller; class WrapWidget; enum class Wrap; @@ -38,12 +39,12 @@ class SectionWidget final : public Window::SectionWidget { public: SectionWidget( QWidget *parent, - not_null controller, + not_null window, Wrap wrap, not_null memento); SectionWidget( QWidget *parent, - not_null controller, + not_null window, Wrap wrap, not_null memento); @@ -72,6 +73,8 @@ protected: private: void init(); + not_null controller() const; + object_ptr _content; }; diff --git a/Telegram/SourceFiles/info/info_top_bar.cpp b/Telegram/SourceFiles/info/info_top_bar.cpp index 8ae70aa70b..1f3ccedf5d 100644 --- a/Telegram/SourceFiles/info/info_top_bar.cpp +++ b/Telegram/SourceFiles/info/info_top_bar.cpp @@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_info.h" #include "lang/lang_keys.h" #include "info/info_wrap_widget.h" +#include "info/info_controller.h" #include "storage/storage_shared_media.h" #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" @@ -102,19 +103,19 @@ void TopBar::paintEvent(QPaintEvent *e) { rpl::producer TitleValue( const Section §ion, - PeerId peerId) { + not_null peer) { return Lang::Viewer([&] { switch (section.type()) { case Section::Type::Profile: - if (peerIsUser(peerId)) { - return App::user(peerId)->botInfo + if (auto user = peer->asUser()) { + return user->botInfo ? lng_info_bot_title : lng_info_user_title; - } else if (peerIsChannel(peerId)) { - return App::channel(peerId)->isMegagroup() + } else if (auto channel = peer->asChannel()) { + return channel->isMegagroup() ? lng_info_group_title : lng_info_channel_title; - } else if (peerIsChat(peerId)) { + } else if (peer->isChat()) { return lng_info_group_title; } Unexpected("Bad peer type in Info::TitleValue()"); diff --git a/Telegram/SourceFiles/info/info_top_bar.h b/Telegram/SourceFiles/info/info_top_bar.h index e3a264124d..2f31f955d4 100644 --- a/Telegram/SourceFiles/info/info_top_bar.h +++ b/Telegram/SourceFiles/info/info_top_bar.h @@ -37,7 +37,7 @@ class Section; rpl::producer TitleValue( const Section §ion, - PeerId peerId); + not_null peer); class TopBar : public Ui::RpWidget { public: diff --git a/Telegram/SourceFiles/info/info_wrap_widget.cpp b/Telegram/SourceFiles/info/info_wrap_widget.cpp index d9622bd5fb..24171f0a1c 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.cpp +++ b/Telegram/SourceFiles/info/info_wrap_widget.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "info/profile/info_profile_widget.h" #include "info/media/info_media_widget.h" #include "info/info_content_widget.h" +#include "info/info_controller.h" #include "info/info_memento.h" #include "info/info_top_bar.h" #include "info/info_top_bar_override.h" @@ -57,13 +58,19 @@ struct WrapWidget::StackItem { WrapWidget::WrapWidget( QWidget *parent, - not_null controller, + not_null window, Wrap wrap, not_null memento) -: SectionWidget(parent, controller) +: SectionWidget(parent, window) , _wrap(wrap) +, _controller(createController(window, memento->content())) , _topShadow(this) { _topShadow->toggleOn(topShadowToggledValue()); + _wrap.changes() + | rpl::start_with_next([this] { + setupTop(); + finishShowContent(); + }, lifetime()); selectedListValue() | rpl::start_with_next([this](SelectedItems &&items) { InvokeQueued(this, [this, items = std::move(items)]() mutable { @@ -73,20 +80,18 @@ WrapWidget::WrapWidget( showNewContent(memento->content()); } +std::unique_ptr WrapWidget::createController( + not_null window, + not_null memento) { + auto result = std::make_unique( + this, + window, + memento); + return result; +} + not_null WrapWidget::peer() const { - return _content->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(); - } + return _controller->peer(); } void WrapWidget::createTabs() { @@ -138,9 +143,15 @@ void WrapWidget::showTab(Tab tab) { ? SlideDirection::FromRight : SlideDirection::FromLeft; auto newAnotherMemento = _content->createMemento(); - auto newContent = _anotherTabMemento - ? createContent(_anotherTabMemento.get()) - : createContent(tab); + if (!_anotherTabMemento) { + _anotherTabMemento = createTabMemento(tab); + } + auto newController = createController( + _controller->window(), + _anotherTabMemento.get()); + auto newContent = createContent( + _anotherTabMemento.get(), + newController.get()); auto animationParams = SectionSlideParams(); // animationParams.withFade = (wrap() == Wrap::Layer); animationParams.withTabs = true; @@ -149,6 +160,7 @@ void WrapWidget::showTab(Tab tab) { animationParams.oldContentCache = grabForShowAnimation( animationParams); + _controller = std::move(newController); showContent(std::move(newContent)); showAnimated(direction, animationParams); @@ -157,7 +169,8 @@ void WrapWidget::showTab(Tab tab) { _tab = tab; } -void WrapWidget::setupTabbedTop(const Section §ion) { +void WrapWidget::setupTabbedTop() { + auto section = _controller->section(); switch (section.type()) { case Section::Type::Profile: setupTabs(Tab::Profile); @@ -180,30 +193,26 @@ void WrapWidget::setupTabbedTop(const Section §ion) { } } -void WrapWidget::setupTop( - const Section §ion, - PeerId peerId) { +void WrapWidget::setupTop() { if (wrap() == Wrap::Side && _historyStack.empty()) { - setupTabbedTop(section); + setupTabbedTop(); } else { setupTabs(Tab::None); } if (_topTabs) { _topBar.destroy(); } else { - createTopBar(section, peerId); + createTopBar(); } refreshTopBarOverride(); } -void WrapWidget::createTopBar( - const Section §ion, - PeerId peerId) { +void WrapWidget::createTopBar() { _topBar.create(this, TopBarStyle(wrap())); _topBar->setTitle(TitleValue( - section, - peerId)); + _controller->section(), + _controller->peer())); if (wrap() != Wrap::Layer || !_historyStack.empty()) { _topBar->enableBackButton(true); _topBar->backRequest() @@ -216,7 +225,7 @@ void WrapWidget::createTopBar( _topBar, st::infoLayerTopBarClose)); close->addClickHandler([this] { - controller()->hideSpecialLayer(); + _controller->window()->hideSpecialLayer(); }); } @@ -290,7 +299,7 @@ void WrapWidget::showBackFromStack() { params); _anotherTabMemento = std::move(last.anotherTab); } else { - controller()->showBackFromStack(params); + _controller->window()->showBackFromStack(params); } } @@ -324,7 +333,7 @@ void WrapWidget::finishShowContent() { rpl::producer WrapWidget::topShadowToggledValue() const { using namespace rpl::mappers; return rpl::combine( - _wrap.value(), + _controller->wrapValue(), _desiredShadowVisibilities.events() | rpl::flatten_latest(), ($1 == Wrap::Side) || $2); } @@ -341,39 +350,26 @@ rpl::producer WrapWidget::selectedListValue() const { return _selectedLists.events() | rpl::flatten_latest(); } -object_ptr WrapWidget::createContent(Tab tab) { +std::unique_ptr WrapWidget::createTabMemento( + Tab tab) { switch (tab) { - case Tab::Profile: return createProfileWidget(); - case Tab::Media: return createMediaWidget(); + case Tab::Profile: return std::make_unique( + _controller->peerId(), + _controller->migratedPeerId()); + case Tab::Media: return std::make_unique( + _controller->peerId(), + _controller->migratedPeerId(), + Media::Memento::Type::Photo); } Unexpected("Tab value in Info::WrapWidget::createInner()"); } -object_ptr WrapWidget::createProfileWidget() { - auto result = object_ptr( - this, - _wrap.value(), - controller(), - _content->peer()); - return result; -} - -object_ptr WrapWidget::createMediaWidget() { - auto result = object_ptr( - this, - _wrap.value(), - controller(), - _content->peer(), - Media::Widget::Type::Photo); - return result; -} - object_ptr WrapWidget::createContent( - not_null memento) { + not_null memento, + not_null controller) { return memento->createWidget( this, - _wrap.value(), - controller(), + controller, contentGeometry()); } @@ -423,20 +419,21 @@ bool WrapWidget::showInternal( const Window::SectionShow ¶ms) { if (auto infoMemento = dynamic_cast(memento.get())) { auto content = infoMemento->content(); - if (!_content->showInternal(content)) { - showNewContent( - content, - params); + if (_controller->validateMementoPeer(content)) { + if (_content->showInternal(content)) { + return true; + } } + showNewContent( + content, + params); return true; } return false; } std::unique_ptr WrapWidget::createMemento() { - auto result = std::make_unique(_content->peer()->id); - saveState(result.get()); - return std::move(result); + return std::make_unique(_content->createMemento()); } rpl::producer WrapWidget::desiredHeightValue() const { @@ -446,10 +443,6 @@ rpl::producer WrapWidget::desiredHeightValue() const { | rpl::flatten_latest(); } -void WrapWidget::saveState(not_null memento) { - memento->setInner(_content->createMemento()); -} - QRect WrapWidget::contentGeometry() const { return rect().marginsRemoved({ 0, topWidget()->height(), 0, 0 }); } @@ -462,9 +455,12 @@ void WrapWidget::showNewContent( auto needAnimation = (_content != nullptr) && (params.animated != anim::type::instant); auto animationParams = SectionSlideParams(); + auto newController = createController( + _controller->window(), + memento); auto newContent = object_ptr(nullptr); if (needAnimation) { - newContent = createContent(memento); + newContent = createContent(memento, newController.get()); animationParams.withTopBarShadow = hasTopBarShadow() && newContent->hasTopBarShadow(); animationParams.oldContentCache = grabForShowAnimation( @@ -481,8 +477,10 @@ void WrapWidget::showNewContent( } else if (params.way == Window::SectionShow::Way::ClearStack) { _historyStack.clear(); } + + _controller = std::move(newController); if (newContent) { - setupTop(newContent->section(), newContent->peer()->id); + setupTop(); showContent(std::move(newContent)); } else { showNewContent(memento); @@ -498,8 +496,8 @@ void WrapWidget::showNewContent( void WrapWidget::showNewContent(not_null memento) { // Validates contentGeometry(). - setupTop(memento->section(), memento->peerId()); - showContent(createContent(memento)); + setupTop(); + showContent(createContent(memento, _controller.get())); } void WrapWidget::setupTabs(Tab tab) { diff --git a/Telegram/SourceFiles/info/info_wrap_widget.h b/Telegram/SourceFiles/info/info_wrap_widget.h index d9ac111239..48a0c7c97e 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.h +++ b/Telegram/SourceFiles/info/info_wrap_widget.h @@ -43,6 +43,7 @@ namespace Media { class Widget; } // namespace Media +class Controller; class Section; class Memento; class MoveMemento; @@ -57,37 +58,6 @@ enum class Wrap { 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 { explicit SelectedItem(FullMsgId msgId) : msgId(msgId) { } @@ -111,7 +81,7 @@ class WrapWidget final : public Window::SectionWidget { public: WrapWidget( QWidget *parent, - not_null controller, + not_null window, Wrap wrap, not_null memento); @@ -119,9 +89,19 @@ public: PeerData *peerForDialogs() const override { return peer(); } + Wrap wrap() const { + return _wrap.current(); + } + rpl::producer wrapValue() const { + return _wrap.value(); + } + void setWrap(Wrap wrap) { + _wrap = wrap; + } - Wrap wrap() const; - void setWrap(Wrap wrap); + not_null controller() { + return _controller.get(); + } bool hasTopBarShadow() const override; QPixmap grabForShowAnimation( @@ -138,7 +118,6 @@ public: rpl::producer desiredHeightValue() const override; void updateInternalState(not_null memento); - void saveState(not_null memento); // Float player interface. bool wheelEventFromFloatPlayer(QEvent *e) override; @@ -167,13 +146,11 @@ private: void showNewContent( not_null memento, const Window::SectionShow ¶ms); - void setupTop(const Section §ion, PeerId peerId); - void setupTabbedTop(const Section §ion); + void setupTop(); + void setupTabbedTop(); void setupTabs(Tab tab); void createTabs(); - void createTopBar( - const Section §ion, - PeerId peerId); + void createTopBar(); not_null topWidget() const; @@ -185,10 +162,12 @@ private: void showTab(Tab tab); void showContent(object_ptr content); - object_ptr createContent(Tab tab); - object_ptr createProfileWidget(); - object_ptr createMediaWidget(); + std::unique_ptr createTabMemento(Tab tab); object_ptr createContent( + not_null memento, + not_null controller); + std::unique_ptr createController( + not_null window, not_null memento); rpl::producer selectedListValue() const; @@ -198,6 +177,7 @@ private: void destroyTopBarOverride(); rpl::variable _wrap; + std::unique_ptr _controller; object_ptr _content = { nullptr }; object_ptr _topTabsBackground = { nullptr }; object_ptr _topTabs = { nullptr }; diff --git a/Telegram/SourceFiles/info/media/info_media_buttons.h b/Telegram/SourceFiles/info/media/info_media_buttons.h index bb907255a1..5711985b59 100644 --- a/Telegram/SourceFiles/info/media/info_media_buttons.h +++ b/Telegram/SourceFiles/info/media/info_media_buttons.h @@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "lang/lang_keys.h" #include "storage/storage_shared_media.h" #include "info/info_memento.h" +#include "info/info_controller.h" #include "info/profile/info_profile_button.h" #include "info/profile/info_profile_values.h" #include "ui/wrap/slide_wrap.h" @@ -90,11 +91,12 @@ inline auto AddButton( Ui::VerticalLayout *parent, not_null controller, not_null peer, + PeerData *migrated, Type type, Ui::MultiSlideTracker &tracker) { auto result = AddCountedButton( parent, - Profile::SharedMediaCountValue(peer, type), + Profile::SharedMediaCountValue(peer, migrated, type), MediaText(type), tracker)->entity(); result->addClickHandler([controller, peer, type] { @@ -118,9 +120,7 @@ inline auto AddCommonGroupsButton( tracker)->entity(); result->addClickHandler([controller, user] { controller->showSection( - Info::Memento( - user->id, - Section::Type::CommonGroups)); + Info::Memento(user->id, Section::Type::CommonGroups)); }); return std::move(result); }; diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp index 2a679cdd80..8cc414d16e 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.cpp @@ -26,6 +26,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "info/media/info_media_buttons.h" #include "info/profile/info_profile_button.h" #include "info/profile/info_profile_icon.h" +#include "info/info_controller.h" #include "ui/widgets/discrete_sliders.h" #include "ui/widgets/shadow.h" #include "ui/wrap/vertical_layout.h" @@ -61,17 +62,15 @@ Type TabIndexToType(int index) { InnerWidget::InnerWidget( QWidget *parent, - rpl::producer &&wrap, - not_null controller, - not_null peer, - Type type) -: RpWidget(parent) { - _list = setupList(controller, peer, type); - setupOtherTypes(std::move(wrap)); + not_null controller) +: RpWidget(parent) +, _controller(controller) { + _list = setupList(); + setupOtherTypes(); } -void InnerWidget::setupOtherTypes(rpl::producer &&wrap) { - std::move(wrap) +void InnerWidget::setupOtherTypes() { + _controller->wrapValue() | rpl::start_with_next([this](Wrap value) { if (value == Wrap::Side && TypeToTabIndex(type())) { @@ -81,6 +80,7 @@ void InnerWidget::setupOtherTypes(rpl::producer &&wrap) { _otherTypes.destroy(); refreshHeight(); } + refreshSearchField(); }, lifetime()); } @@ -117,8 +117,9 @@ void InnerWidget::createTypeButtons() { const style::icon &icon) { auto result = AddButton( content, - controller(), - peer(), + _controller->window(), + _controller->peer(), + _controller->migrated(), type, tracker); object_ptr( @@ -131,7 +132,7 @@ void InnerWidget::createTypeButtons() { const style::icon &icon) { auto result = AddCommonGroupsButton( content, - controller(), + _controller->window(), user, tracker); object_ptr( @@ -142,7 +143,7 @@ void InnerWidget::createTypeButtons() { addMediaButton(Type::MusicFile, st::infoIconMediaAudio); addMediaButton(Type::Link, st::infoIconMediaLink); - if (auto user = peer()->asUser()) { + if (auto user = _controller->peer()->asUser()) { addCommonGroupsButton(user, st::infoIconMediaGroup); } addMediaButton(Type::VoiceFile, st::infoIconMediaVoice); @@ -170,20 +171,19 @@ void InnerWidget::createTabs() { _otherTabs->sectionActivated() | rpl::map([](int index) { return TabIndexToType(index); }) | rpl::start_with_next( - [this](Type type) { - if (_list->type() != type) { - switchToTab(Memento(peer()->id, type)); + [this](Type newType) { + if (type() != newType) { + switchToTab(Memento( + _controller->peerId(), + _controller->migratedPeerId(), + newType)); } }, _otherTabs->lifetime()); } -not_null InnerWidget::peer() const { - return _list->peer(); -} - Type InnerWidget::type() const { - return _list->type(); + return _controller->section().mediaType(); } void InnerWidget::visibleTopBottomUpdated( @@ -193,7 +193,7 @@ void InnerWidget::visibleTopBottomUpdated( } bool InnerWidget::showInternal(not_null memento) { - if (memento->peerId() != peer()->id) { + if (!_controller->validateMementoPeer(memento)) { return false; } auto mementoType = memento->section().mediaType(); @@ -210,8 +210,9 @@ bool InnerWidget::showInternal(not_null memento) { } void InnerWidget::switchToTab(Memento &&memento) { - auto type = memento.section().mediaType(); - _list = setupList(controller(), peer(), type); + // Save state of the tab before setSection() call. + _controller->setSection(memento.section()); + _list = setupList(); restoreState(&memento); _list->show(); _list->resizeToWidth(width()); @@ -219,48 +220,28 @@ void InnerWidget::switchToTab(Memento &&memento) { if (_otherTypes) { _otherTabsShadow->raise(); _otherTypes->raise(); - _otherTabs->setActiveSection(*TypeToTabIndex(type)); + _otherTabs->setActiveSection(*TypeToTabIndex(type())); } } -not_null InnerWidget::controller() const { - return _list->controller(); -} - -object_ptr InnerWidget::setupList( - not_null controller, - not_null peer, - Type type) { - if (SharedMediaAllowSearch(type)) { - _searchFieldController - = std::make_unique(); - _searchFieldController->queryValue() - | rpl::start_with_next([=](QString &&query) { - _searchController.setQuery(produceSearchQuery( - peer, - type, - std::move(query))); - }, _searchFieldController->lifetime()); - _searchField = _searchFieldController->createView( +void InnerWidget::refreshSearchField() { + auto search = _controller->searchFieldController(); + if (search && _otherTabs) { + _searchField = search->createView( this, st::infoMediaSearch); _searchField->resizeToWidth(width()); _searchField->show(); } else { _searchField = nullptr; - _searchFieldController = nullptr; } - _searchController.setQueryFast(produceSearchQuery(peer, type)); +} + +object_ptr InnerWidget::setupList() { + refreshSearchField(); auto result = object_ptr( this, - controller, - peer, - type, - produceListSource()); - _searchController.sourceChanged() - | rpl::start_with_next([widget = result.data()]{ - widget->restart(); - }, result->lifetime()); + _controller); result->heightValue() | rpl::start_with_next( [this] { refreshHeight(); }, @@ -296,47 +277,6 @@ void InnerWidget::cancelSelection() { 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 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) { _inResize = true; auto guard = gsl::finally([this] { _inResize = false; }); diff --git a/Telegram/SourceFiles/info/media/info_media_inner_widget.h b/Telegram/SourceFiles/info/media/info_media_inner_widget.h index e7d52d2ffd..6dc1d8915c 100644 --- a/Telegram/SourceFiles/info/media/info_media_inner_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_inner_widget.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "ui/rp_widget.h" +#include "base/unique_qptr.h" #include "info/media/info_media_widget.h" #include "info/media/info_media_list_widget.h" #include "history/history_search_controller.h" @@ -32,6 +33,9 @@ class SearchFieldController; } // namespace Ui namespace Info { + +class Controller; + namespace Media { class Memento; @@ -42,13 +46,7 @@ public: using Type = Widget::Type; InnerWidget( QWidget *parent, - rpl::producer &&wrap, - not_null controller, - not_null peer, - Type type); - - not_null peer() const; - Type type() const; + not_null controller); bool showInternal(not_null memento); @@ -72,38 +70,29 @@ protected: private: int recountHeight(); void refreshHeight(); - void setupOtherTypes(rpl::producer &&wrap); + void setupOtherTypes(); void createOtherTypes(); void createTypeButtons(); void createTabs(); void switchToTab(Memento &&memento); - using SearchQuery = Api::DelayedSearchController::Query; - ListWidget::Source produceListSource(); - SearchQuery produceSearchQuery( - not_null peer, - Type type, - QString &&query = QString()) const; + Type type() const; - not_null controller() const; + void refreshSearchField(); + object_ptr setupList(); - object_ptr setupList( - not_null controller, - not_null peer, - Type type); - - bool _inResize = false; + const not_null _controller; Ui::SettingsSlider *_otherTabs = nullptr; object_ptr _otherTypes = { nullptr }; object_ptr _otherTabsShadow = { nullptr }; - std::unique_ptr _searchFieldController; - Ui::RpWidget *_searchField = nullptr; + base::unique_qptr _searchField = nullptr; object_ptr _list = { nullptr }; + bool _inResize = false; + rpl::event_stream _scrollToRequests; rpl::event_stream> _selectedLists; - Api::DelayedSearchController _searchController; }; diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 719386d2f0..05d42d24f4 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -20,6 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #include "info/media/info_media_list_widget.h" +#include "info/info_controller.h" #include "overview/overview_layout.h" #include "history/history_media_types.h" #include "history/history_item.h" @@ -538,15 +539,12 @@ void ListWidget::Section::refreshHeight() { ListWidget::ListWidget( QWidget *parent, - not_null controller, - not_null peer, - Type type, - Source source) + not_null controller) : RpWidget(parent) , _controller(controller) -, _peer(peer) -, _type(type) -, _source(std::move(source)) +, _peer(_controller->peer()) +, _migrated(_controller->migrated()) +, _type(_controller->section().mediaType()) , _slice(sliceKey(_universalAroundId)) { setAttribute(Qt::WA_MouseTracking); start(); @@ -574,6 +572,10 @@ void ListWidget::start() { | rpl::start_with_next([this](auto item) { repaintItem(item); }, lifetime()); + _controller->mediaSourceChanged() + | rpl::start_with_next([this]{ + restart(); + }, lifetime()); } void ListWidget::restart() { @@ -733,13 +735,13 @@ void ListWidget::repaintItem(QRect itemGeometry) { bool ListWidget::isMyItem(not_null item) const { auto peer = item->history()->peer; - return (_peer == peer || _peer == peer->migrateTo()); + return (_peer == peer) || (_migrated == peer); } bool ListWidget::isPossiblyMyId(FullMsgId fullId) const { return (fullId.channel != 0) ? (_peer->isChannel() && _peer->bareId() == fullId.channel) - : (!_peer->isChannel() || _peer->migrateFrom()); + : (!_peer->isChannel() || _migrated); } bool ListWidget::isItemLayout( @@ -757,8 +759,8 @@ void ListWidget::invalidatePaletteCache() { SparseIdsMergedSlice::Key ListWidget::sliceKey( UniversalMsgId universalId) const { using Key = SparseIdsMergedSlice::Key; - if (auto migrateFrom = _peer->migrateFrom()) { - return Key(_peer->id, migrateFrom->id, universalId); + if (_migrated) { + return Key(_peer->id, _migrated->id, universalId); } if (universalId < 0) { // Convert back to plain id for non-migrated histories. @@ -769,7 +771,10 @@ SparseIdsMergedSlice::Key ListWidget::sliceKey( void ListWidget::refreshViewer() { _viewerLifetime.destroy(); - _source(_universalAroundId, _idsLimit, _idsLimit) + _controller->mediaSource( + sliceKey(_universalAroundId).universalId, + _idsLimit, + _idsLimit) | rpl::start_with_next([this]( SparseIdsMergedSlice &&slice) { _slice = std::move(slice); @@ -1752,8 +1757,8 @@ void ListWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butto auto pressLayout = _overLayout; _mouseAction = MouseAction::None; - _pressWasInactive = _controller->window()->wasInactivePress(); - if (_pressWasInactive) _controller->window()->setInactivePress(false); + _pressWasInactive = _controller->window()->window()->wasInactivePress(); + if (_pressWasInactive) _controller->window()->window()->setInactivePress(false); if (ClickHandler::getPressed() && !hasSelected()) { _mouseAction = MouseAction::PrepareDrag; diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h index 8a8104fc7c..44c0ca5da9 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h @@ -39,6 +39,9 @@ class Controller; } // namespace Window namespace Info { + +class Controller; + namespace Media { using BaseLayout = Overview::Layout::ItemBase; @@ -47,27 +50,9 @@ using UniversalMsgId = int32; class ListWidget : public Ui::RpWidget { public: using Type = Widget::Type; - using Source = base::lambda< - rpl::producer( - SparseIdsMergedSlice::UniversalMsgId aroundId, - int limitBefore, - int limitAfter)>; ListWidget( QWidget *parent, - not_null controller, - not_null peer, - Type type, - Source source); - - not_null controller() const { - return _controller; - } - not_null peer() const { - return _peer; - } - Type type() const { - return _type; - } + not_null controller); void restart(); @@ -103,6 +88,7 @@ protected: void leaveEventHook(QEvent *e) override; private: + using Type = Widget::Type; enum class MouseAction { None, PrepareDrag, @@ -280,10 +266,10 @@ private: void validateTrippleClickStartTime(); void checkMoveToOtherViewer(); - not_null _controller; - not_null _peer; + const not_null _controller; + const not_null _peer; + PeerData * const _migrated = nullptr; Type _type = Type::Photo; - Source _source; static constexpr auto kMinimalIdsLimit = 16; static constexpr auto kDefaultAroundId = (ServerMaxMsgId - 1); diff --git a/Telegram/SourceFiles/info/media/info_media_widget.cpp b/Telegram/SourceFiles/info/media/info_media_widget.cpp index 9fcc49a924..5dd2b2ca1e 100644 --- a/Telegram/SourceFiles/info/media/info_media_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_widget.cpp @@ -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_inner_widget.h" +#include "info/info_controller.h" #include "ui/widgets/scroll_area.h" namespace Info { namespace Media { +Memento::Memento(not_null controller) +: Memento( + controller->peerId(), + controller->migratedPeerId(), + controller->section().mediaType()) { +} + +Section Memento::section() const { + return Section(_type); +} + object_ptr Memento::createWidget( QWidget *parent, - rpl::producer wrap, - not_null controller, + not_null controller, const QRect &geometry) { auto result = object_ptr( parent, - std::move(wrap), - controller, - App::peer(peerId()), - _type); + controller); result->setInternalState(geometry, this); return std::move(result); } Widget::Widget( QWidget *parent, - rpl::producer wrap, - not_null controller, - not_null peer, - Type type) -: ContentWidget(parent, rpl::duplicate(wrap), controller, peer) { + not_null controller) +: ContentWidget(parent, controller) { _inner = setInnerWidget(object_ptr( this, - std::move(wrap), - controller, - peer, - type)); + controller)); _inner->scrollToRequests() | rpl::start_with_next([this](int skip) { scrollTo({ skip, -1 }); @@ -68,15 +70,10 @@ void Widget::cancelSelection() { _inner->cancelSelection(); } -Section Widget::section() const { - return Section(type()); -} - -Widget::Type Widget::type() const { - return _inner->type(); -} - bool Widget::showInternal(not_null memento) { + if (!controller()->validateMementoPeer(memento)) { + return false; + } if (auto mediaMemento = dynamic_cast(memento.get())) { if (_inner->showInternal(mediaMemento)) { return true; @@ -92,7 +89,7 @@ void Widget::setInternalState(const QRect &geometry, not_null memento) } std::unique_ptr Widget::createMemento() { - auto result = std::make_unique(peer()->id, type()); + auto result = std::make_unique(controller()); saveState(result.get()); return std::move(result); } diff --git a/Telegram/SourceFiles/info/media/info_media_widget.h b/Telegram/SourceFiles/info/media/info_media_widget.h index f8f7866859..58d5c44837 100644 --- a/Telegram/SourceFiles/info/media/info_media_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_widget.h @@ -33,20 +33,19 @@ class Memento final : public ContentMemento { public: using Type = Storage::SharedMediaType; - Memento(PeerId peerId, Type type) - : ContentMemento(peerId) + Memento(not_null controller); + + Memento(PeerId peerId, PeerId migratedPeerId, Type type) + : ContentMemento(peerId, migratedPeerId) , _type(type) { } object_ptr createWidget( QWidget *parent, - rpl::producer wrap, - not_null controller, + not_null controller, const QRect &geometry) override; - Section section() const override { - return Section(_type); - } + Section section() const override; Type type() const { return _type; @@ -92,13 +91,7 @@ public: Widget( QWidget *parent, - rpl::producer wrap, - not_null controller, - not_null peer, - Type type); - - Type type() const; - Section section() const override; + not_null controller); bool showInternal( not_null memento) override; @@ -114,7 +107,7 @@ public: private: void saveState(not_null memento); void restoreState(not_null memento); - + InnerWidget *_inner = nullptr; }; diff --git a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp index 606a9c7955..b5fb6e3d95 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.cpp @@ -24,6 +24,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include #include #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_widget.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_members.h" #include "info/media/info_media_buttons.h" -#include "info/info_top_bar_override.h" #include "boxes/abstract_box.h" #include "boxes/add_contact_box.h" #include "boxes/confirm_box.h" @@ -59,13 +60,12 @@ namespace Profile { InnerWidget::InnerWidget( QWidget *parent, - rpl::producer &&wrapValue, - not_null controller, - not_null peer) + not_null controller) : RpWidget(parent) , _controller(controller) -, _peer(peer) -, _content(setupContent(this, std::move(wrapValue))) { +, _peer(_controller->peer()) +, _migrated(_controller->migrated()) +, _content(setupContent(this)) { _content->heightValue() | rpl::start_with_next([this](int height) { resizeToWidth(width()); @@ -84,8 +84,7 @@ rpl::producer InnerWidget::canHideDetails() const { } object_ptr InnerWidget::setupContent( - RpWidget *parent, - rpl::producer &&wrapValue) { + RpWidget *parent) { auto result = object_ptr(parent); _cover = result->add(object_ptr( result, @@ -101,7 +100,7 @@ object_ptr InnerWidget::setupContent( } else { result->add(std::move(details)); } - result->add(setupSharedMedia(result, rpl::duplicate(wrapValue))); + result->add(setupSharedMedia(result)); result->add(object_ptr(result)); if (auto user = _peer->asUser()) { result->add(setupUserActions(result, user)); @@ -114,7 +113,6 @@ object_ptr InnerWidget::setupContent( _members = result->add(object_ptr( result, _controller, - std::move(wrapValue), _peer) ); _members->scrollToRequests() @@ -241,10 +239,10 @@ void InnerWidget::setupUserButtons( addButton( Lang::Viewer(lng_profile_send_message) | ToUpperValue() )->toggleOn( - _controller->historyPeer.value() + _controller->window()->historyPeer.value() | rpl::map($1 != user) )->entity()->addClickHandler([this, user] { - _controller->showPeerHistory( + _controller->window()->showPeerHistory( user, Window::SectionShow::Way::Forward); }); @@ -266,8 +264,7 @@ void InnerWidget::setupUserButtons( } object_ptr InnerWidget::setupSharedMedia( - RpWidget *parent, - rpl::producer &&wrapValue) { + RpWidget *parent) { using namespace rpl::mappers; using MediaType = Media::Type; @@ -278,8 +275,9 @@ object_ptr InnerWidget::setupSharedMedia( const style::icon &icon) { auto result = Media::AddButton( content, - _controller, - peer(), + _controller->window(), + _peer, + _migrated, type, tracker); object_ptr( @@ -292,7 +290,7 @@ object_ptr InnerWidget::setupSharedMedia( const style::icon &icon) { auto result = Media::AddCommonGroupsButton( content, - _controller, + _controller->window(), user, tracker); object_ptr( @@ -306,7 +304,7 @@ object_ptr InnerWidget::setupSharedMedia( addMediaButton(MediaType::File, st::infoIconMediaFile); addMediaButton(MediaType::MusicFile, st::infoIconMediaAudio); addMediaButton(MediaType::Link, st::infoIconMediaLink); - if (auto user = peer()->asUser()) { + if (auto user = _peer->asUser()) { addCommonGroupsButton(user, st::infoIconMediaGroup); } addMediaButton(MediaType::VoiceFile, st::infoIconMediaVoice); @@ -320,7 +318,7 @@ object_ptr InnerWidget::setupSharedMedia( using ToggledData = std::tuple; rpl::combine( tracker.atLeastOneShownValue(), - std::move(wrapValue), + _controller->wrapValue(), _isStackBottom.events()) | rpl::combine_previous(ToggledData()) | rpl::start_with_next([wrap = result.data()]( diff --git a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.h b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.h index 371c26ac15..2daf3e8363 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_inner_widget.h +++ b/Telegram/SourceFiles/info/profile/info_profile_inner_widget.h @@ -37,6 +37,7 @@ struct ScrollToRequest; namespace Info { enum class Wrap; +class Controller; namespace Profile { @@ -48,13 +49,7 @@ class InnerWidget final : public Ui::RpWidget { public: InnerWidget( QWidget *parent, - rpl::producer &&wrapValue, - not_null controller, - not_null peer); - - not_null peer() const { - return _peer; - } + not_null controller); void saveState(not_null memento); void restoreState(not_null memento); @@ -77,13 +72,9 @@ protected: int visibleBottom) override; private: - object_ptr setupContent( - RpWidget *parent, - rpl::producer &&wrapValue); + object_ptr setupContent(RpWidget *parent); object_ptr setupDetails(RpWidget *parent) const; - object_ptr setupSharedMedia( - RpWidget *parent, - rpl::producer &&wrapValue); + object_ptr setupSharedMedia(RpWidget *parent); object_ptr setupMuteToggle(RpWidget *parent) const; object_ptr setupInfo(RpWidget *parent) const; void setupUserButtons( @@ -105,8 +96,9 @@ private: rpl::event_stream _isStackBottom; - not_null _controller; - not_null _peer; + const not_null _controller; + const not_null _peer; + PeerData * const _migrated = nullptr; Members *_members = nullptr; Cover *_cover = nullptr; diff --git a/Telegram/SourceFiles/info/profile/info_profile_members.cpp b/Telegram/SourceFiles/info/profile/info_profile_members.cpp index e6e5426e0b..19fa9fe5e4 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_members.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_members.cpp @@ -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_members_controllers.h" #include "info/info_content_widget.h" +#include "info/info_controller.h" #include "profile/profile_block_group_members.h" #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" @@ -48,12 +49,11 @@ constexpr auto kEnableSearchMembersAfterCount = 50; Members::Members( QWidget *parent, - not_null controller, - rpl::producer &&wrapValue, + not_null controller, not_null peer) : RpWidget(parent) , _peer(peer) -, _listController(CreateMembersController(controller, _peer)) +, _listController(CreateMembersController(controller->window(), _peer)) , _labelWrap(this) , _label(setupHeader()) , _addMember(this, st::infoMembersAddMember) @@ -65,7 +65,7 @@ Members::Members( , _cancelSearch(this, st::infoMembersCancelSearch) , _list(setupList(this, _listController.get())) { setupButtons(); - std::move(wrapValue) + controller->wrapValue() | rpl::start_with_next([this](Wrap wrap) { _wrap = wrap; updateSearchOverrides(); diff --git a/Telegram/SourceFiles/info/profile/info_profile_members.h b/Telegram/SourceFiles/info/profile/info_profile_members.h index 6902b9bdcf..d12b5453b3 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_members.h +++ b/Telegram/SourceFiles/info/profile/info_profile_members.h @@ -38,6 +38,7 @@ class ParticipantsBoxController; namespace Info { +class Controller; enum class Wrap; namespace Profile { @@ -50,8 +51,7 @@ class Members public: Members( QWidget *parent, - not_null controller, - rpl::producer &&wrapValue, + not_null controller, not_null peer); rpl::producer scrollToRequests() const { diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.cpp b/Telegram/SourceFiles/info/profile/info_profile_values.cpp index a78cd2e0bb..133b18ee2c 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_values.cpp @@ -164,17 +164,14 @@ rpl::producer MembersCountValue( rpl::producer SharedMediaCountValue( not_null peer, + PeerData *migrated, Storage::SharedMediaType type) { - auto real = peer->migrateTo() ? peer->migrateTo() : peer; - auto migrated = real->migrateFrom() - ? real->migrateFrom() - : nullptr; auto aroundId = 0; auto limit = 0; auto updated = SharedMediaMergedViewer( SharedMediaMergedKey( SparseIdsMergedSlice::Key( - real->id, + peer->id, migrated ? migrated->id : 0, aroundId), type), diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.h b/Telegram/SourceFiles/info/profile/info_profile_values.h index 5d5fc55cbe..5702ac0a61 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.h +++ b/Telegram/SourceFiles/info/profile/info_profile_values.h @@ -67,6 +67,7 @@ rpl::producer MembersCountValue( not_null peer); rpl::producer SharedMediaCountValue( not_null peer, + PeerData *migrated, Storage::SharedMediaType type); rpl::producer CommonGroupsCountValue( not_null user); diff --git a/Telegram/SourceFiles/info/profile/info_profile_widget.cpp b/Telegram/SourceFiles/info/profile/info_profile_widget.cpp index 28b8b89d44..bb09458da4 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_widget.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_widget.cpp @@ -22,35 +22,39 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "info/profile/info_profile_inner_widget.h" #include "ui/widgets/scroll_area.h" +#include "info/info_controller.h" namespace Info { namespace Profile { +Memento::Memento(not_null controller) +: Memento( + controller->peerId(), + controller->migratedPeerId()) { +} + +Section Memento::section() const { + return Section(Section::Type::Profile); +} + object_ptr Memento::createWidget( QWidget *parent, - rpl::producer wrap, - not_null controller, + not_null controller, const QRect &geometry) { auto result = object_ptr( parent, - std::move(wrap), - controller, - App::peer(peerId())); + controller); result->setInternalState(geometry, this); return std::move(result); } Widget::Widget( QWidget *parent, - rpl::producer wrap, - not_null controller, - not_null peer) -: ContentWidget(parent, rpl::duplicate(wrap), controller, peer) { + not_null controller) +: ContentWidget(parent, controller) { _inner = setInnerWidget(object_ptr( this, - std::move(wrap), - controller, - peer)); + controller)); _inner->move(0, 0); _inner->scrollToRequests() | rpl::start_with_next([this](Ui::ScrollToRequest request) { @@ -67,20 +71,17 @@ void Widget::setIsStackBottom(bool isStackBottom) { _inner->setIsStackBottom(isStackBottom); } -Section Widget::section() const { - return Section(Section::Type::Profile); -} - void Widget::setInnerFocus() { _inner->setFocus(); } bool Widget::showInternal(not_null memento) { + if (!controller()->validateMementoPeer(memento)) { + return false; + } if (auto profileMemento = dynamic_cast(memento.get())) { - if (profileMemento->peerId() == peer()->id) { - restoreState(profileMemento); - return true; - } + restoreState(profileMemento); + return true; } return false; } @@ -92,7 +93,7 @@ void Widget::setInternalState(const QRect &geometry, not_null memento) } std::unique_ptr Widget::createMemento() { - auto result = std::make_unique(peer()->id); + auto result = std::make_unique(controller()); saveState(result.get()); return std::move(result); } diff --git a/Telegram/SourceFiles/info/profile/info_profile_widget.h b/Telegram/SourceFiles/info/profile/info_profile_widget.h index 40b087987d..0a129826c1 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_widget.h +++ b/Telegram/SourceFiles/info/profile/info_profile_widget.h @@ -31,18 +31,17 @@ class InnerWidget; class Memento final : public ContentMemento { public: - Memento(PeerId peerId) : ContentMemento(peerId) { + Memento(not_null controller); + Memento(PeerId peerId, PeerId migratedPeerId) + : ContentMemento(peerId, migratedPeerId) { } object_ptr createWidget( QWidget *parent, - rpl::producer wrap, - not_null controller, + not_null controller, const QRect &geometry) override; - Section section() const override { - return Section(Section::Type::Profile); - } + Section section() const override; void setInfoExpanded(bool expanded) { _infoExpanded = expanded; @@ -74,12 +73,9 @@ class Widget final : public ContentWidget { public: Widget( QWidget *parent, - rpl::producer wrap, - not_null controller, - not_null peer); + not_null controller); void setIsStackBottom(bool isStackBottom) override; - Section section() const override; bool showInternal( not_null memento) override; diff --git a/Telegram/SourceFiles/rpl/event_stream.h b/Telegram/SourceFiles/rpl/event_stream.h index c1b517a441..969ad38e1a 100644 --- a/Telegram/SourceFiles/rpl/event_stream.h +++ b/Telegram/SourceFiles/rpl/event_stream.h @@ -50,17 +50,19 @@ public: } auto events() const { return make_producer([weak = weak()]( - const auto &consumer) { + const auto &consumer) { if (auto strong = weak.lock()) { auto result = [weak, consumer] { if (auto strong = weak.lock()) { - auto it = base::find(*strong, consumer); - if (it != strong->end()) { + auto it = base::find( + strong->consumers, + consumer); + if (it != strong->consumers.end()) { it->terminate(); } } }; - strong->push_back(std::move(consumer)); + strong->consumers.push_back(std::move(consumer)); return lifetime(std::move(result)); } return lifetime(); @@ -76,9 +78,13 @@ public: ~event_stream(); private: - std::weak_ptr>> weak() const; + struct Data { + std::vector> consumers; + int depth = 0; + }; + std::weak_ptr weak() const; - mutable std::shared_ptr>> _consumers; + mutable std::shared_ptr _data; }; @@ -88,13 +94,13 @@ inline event_stream::event_stream() { template inline event_stream::event_stream(event_stream &&other) -: _consumers(base::take(other._consumers)) { +: _data(base::take(other._data)) { } template inline event_stream &event_stream::operator=( event_stream &&other) { - _consumers = base::take(other._consumers); + _data = base::take(other._data); return *this; } @@ -102,11 +108,13 @@ template template inline void event_stream::fire_forward( OtherValue &&value) const { - if (!_consumers) { + auto copy = _data; + if (!copy) { return; } - auto &consumers = *_consumers; + ++copy->depth; + auto &consumers = copy->consumers; auto begin = base::index_based_begin(consumers); auto end = base::index_based_end(consumers); if (begin != end) { @@ -136,24 +144,28 @@ inline void event_stream::fire_forward( } // Erase stale consumers. - consumers.erase(removeFrom.base(), consumers.end()); + if (copy->depth == 1) { + consumers.erase(removeFrom.base(), consumers.end()); + } } } + --copy->depth; } template -inline std::weak_ptr>> event_stream::weak() const { - if (!_consumers) { - _consumers = std::make_shared>>(); +inline auto event_stream::weak() const +-> std::weak_ptr { + if (!_data) { + _data = std::make_shared(); } - return _consumers; + return _data; } template inline event_stream::~event_stream() { - if (auto consumers = base::take(_consumers)) { - for (auto &consumer : *consumers) { + if (auto data = base::take(_data)) { + for (auto &consumer : data->consumers) { consumer.put_done(); } } diff --git a/Telegram/SourceFiles/rpl/variable.h b/Telegram/SourceFiles/rpl/variable.h index d7d5ae5182..049a468798 100644 --- a/Telegram/SourceFiles/rpl/variable.h +++ b/Telegram/SourceFiles/rpl/variable.h @@ -81,6 +81,9 @@ public: auto value() const { return _changes.events_starting_with_copy(_data); } + auto changes() const { + return _changes.events(); + } private: template diff --git a/Telegram/SourceFiles/ui/search_field_controller.cpp b/Telegram/SourceFiles/ui/search_field_controller.cpp index aa521360ca..5222fa42ab 100644 --- a/Telegram/SourceFiles/ui/search_field_controller.cpp +++ b/Telegram/SourceFiles/ui/search_field_controller.cpp @@ -29,20 +29,20 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org namespace Ui { -object_ptr SearchFieldController::createView( +base::unique_qptr SearchFieldController::createView( QWidget *parent, const style::SearchFieldRow &st) { - auto result = object_ptr( + auto result = base::make_unique_q( parent, st.height); auto cancel = CreateChild( - result.data(), + result.get(), st.fieldCancel); cancel->addClickHandler([=] { clearQuery(); }); auto field = CreateChild( - result.data(), + result.get(), st.field, langFactory(lng_dlg_filter), _query.current()); @@ -54,7 +54,7 @@ object_ptr SearchFieldController::createView( clearQuery(); }); - auto shadow = CreateChild(result.data()); + auto shadow = CreateChild(result.get()); shadow->show(); result->widthValue() @@ -84,7 +84,7 @@ object_ptr SearchFieldController::createView( _view.wrap->width()); }, result->lifetime()); - _view.wrap.reset(result); + _view.wrap.reset(result.get()); _view.cancel = cancel; _view.field = field; return std::move(result); diff --git a/Telegram/SourceFiles/ui/search_field_controller.h b/Telegram/SourceFiles/ui/search_field_controller.h index 98020989f5..5dff1db2be 100644 --- a/Telegram/SourceFiles/ui/search_field_controller.h +++ b/Telegram/SourceFiles/ui/search_field_controller.h @@ -35,7 +35,7 @@ class InputField; class SearchFieldController { public: - object_ptr createView( + base::unique_qptr createView( QWidget *parent, const style::SearchFieldRow &st); diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index 0664c3e5e7..abcbe4a820 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -219,6 +219,8 @@ <(src_loc)/info/info_common_groups_widget.h <(src_loc)/info/info_content_widget.cpp <(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.h <(src_loc)/info/info_memento.cpp