diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 3c29ae2ea..4274fa160 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1438,6 +1438,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_feed_select_more_channels#one" = "Select {count} channel or more."; "lng_feed_select_more_channels#other" = "Select {count} channels or more."; "lng_feed_create" = "Create"; +"lng_feed_edit_title" = "Edit feed"; +"lng_feed_channels_not_found" = "No channels found"; "lng_info_feed_title" = "Feed Info"; "lng_info_feed_is_default" = "Group new channels"; diff --git a/Telegram/SourceFiles/info/channels/info_channels_widget.cpp b/Telegram/SourceFiles/info/channels/info_channels_widget.cpp new file mode 100644 index 000000000..d6bbd1671 --- /dev/null +++ b/Telegram/SourceFiles/info/channels/info_channels_widget.cpp @@ -0,0 +1,97 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "info/channels/info_channels_widget.h" + +#include "info/feed/info_feed_channels.h" +#include "info/info_controller.h" +#include "ui/widgets/scroll_area.h" +#include "styles/style_info.h" + +namespace Info { +namespace Channels { + +Memento::Memento(not_null controller) +: Memento(controller->feed()) { +} + +Memento::Memento(not_null feed) +: ContentMemento(feed) { +} + +Section Memento::section() const { + return Section(Section::Type::Channels); +} + +object_ptr Memento::createWidget( + QWidget *parent, + not_null controller, + const QRect &geometry) { + auto result = object_ptr( + parent, + controller); + result->setInternalState(geometry, this); + return std::move(result); +} + +void Memento::setState(std::unique_ptr state) { + _state = std::move(state); +} + +std::unique_ptr Memento::state() { + return std::move(_state); +} + +Memento::~Memento() = default; + +Widget::Widget( + QWidget *parent, + not_null controller) +: ContentWidget(parent, controller) { + _inner = setInnerWidget(object_ptr( + this, + controller)); +} + +bool Widget::showInternal(not_null memento) { + if (!controller()->validateMementoPeer(memento)) { + return false; + } + if (auto membersMemento = dynamic_cast(memento.get())) { + restoreState(membersMemento); + return true; + } + return false; +} + +void Widget::setInternalState( + const QRect &geometry, + not_null memento) { + setGeometry(geometry); + Ui::SendPendingMoveResizeEvents(this); + restoreState(memento); +} + +std::unique_ptr Widget::doCreateMemento() { + auto result = std::make_unique(controller()); + saveState(result.get()); + return std::move(result); +} + +void Widget::saveState(not_null memento) { + memento->setScrollTop(scrollTopSave()); + memento->setState(_inner->saveState()); +} + +void Widget::restoreState(not_null memento) { + _inner->restoreState(memento->state()); + auto scrollTop = memento->scrollTop(); + scrollTopRestore(memento->scrollTop()); +} + +} // namespace Channels +} // namespace Info diff --git a/Telegram/SourceFiles/info/channels/info_channels_widget.h b/Telegram/SourceFiles/info/channels/info_channels_widget.h new file mode 100644 index 000000000..431f94ec1 --- /dev/null +++ b/Telegram/SourceFiles/info/channels/info_channels_widget.h @@ -0,0 +1,74 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "info/info_content_widget.h" + +struct PeerListState; + +namespace Data { +class Feed; +} // namespace Data + +namespace Info { +namespace FeedProfile { +class Channels; +struct ChannelsState; +} // namespace FeedProfile + +namespace Channels { + +using SavedState = FeedProfile::ChannelsState; + +class Memento final : public ContentMemento { +public: + explicit Memento(not_null controller); + explicit Memento(not_null feed); + + object_ptr createWidget( + QWidget *parent, + not_null controller, + const QRect &geometry) override; + + Section section() const override; + + void setState(std::unique_ptr state); + std::unique_ptr state(); + + ~Memento(); + +private: + std::unique_ptr _state; + +}; + +class Widget final : public ContentWidget { +public: + Widget( + QWidget *parent, + not_null controller); + + bool showInternal( + not_null memento) override; + + void setInternalState( + const QRect &geometry, + not_null memento); + +private: + void saveState(not_null memento); + void restoreState(not_null memento); + + std::unique_ptr doCreateMemento() override; + + FeedProfile::Channels *_inner = nullptr; + +}; + +} // namespace Channels +} // namespace Info diff --git a/Telegram/SourceFiles/info/feed/info_feed_channels.cpp b/Telegram/SourceFiles/info/feed/info_feed_channels.cpp index 7a6d79fe2..9650f1a8b 100644 --- a/Telegram/SourceFiles/info/feed/info_feed_channels.cpp +++ b/Telegram/SourceFiles/info/feed/info_feed_channels.cpp @@ -11,7 +11,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/profile/info_profile_icon.h" #include "info/profile/info_profile_button.h" #include "info/profile/info_profile_values.h" +#include "info/channels/info_channels_widget.h" #include "info/info_controller.h" +#include "info/info_memento.h" #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" #include "ui/widgets/scroll_area.h" @@ -58,7 +60,7 @@ Channels::Channels( int Channels::desiredHeight() const { auto desired = _header ? _header->height() : 0; - desired += st::infoMembersList.item.height + desired += st::infoChannelsList.item.height * std::max(int(_feed->channels().size()), _list->fullRowsCount()); return qMax(height(), desired); } @@ -81,7 +83,7 @@ void Channels::restoreState(std::unique_ptr state) { } void Channels::setupHeader() { - if (_controller->section().type() == Section::Type::Members) { + if (_controller->section().type() == Section::Type::Channels) { return; } _header = object_ptr( @@ -135,28 +137,24 @@ void Channels::setupButtons() { showChannelsWithSearch(false); }); - //auto addMemberShown = CanAddMemberValue(_peer) - // | rpl::start_spawning(lifetime()); - //_addChannel->showOn(rpl::duplicate(addMemberShown)); - //_addChannel->addClickHandler([this] { // TODO throttle(ripple duration) - // this->addMember(); - //}); + _addChannel->addClickHandler([this] { // TODO throttle(ripple duration) + this->addChannel(); + }); - //auto searchShown = MembersCountValue(_peer) - // | rpl::map(_1 >= kEnableSearchMembersAfterCount) - // | rpl::distinct_until_changed() - // | rpl::start_spawning(lifetime()); - //_search->showOn(rpl::duplicate(searchShown)); - //_search->addClickHandler([this] { // TODO throttle(ripple duration) - // this->showMembersWithSearch(true); - //}); + auto searchShown = Profile::FeedChannelsCountValue(_feed) + | rpl::map(_1 >= kEnableSearchChannelsAfterCount) + | rpl::distinct_until_changed() + | rpl::start_spawning(lifetime()); + _search->showOn(rpl::duplicate(searchShown)); + _search->addClickHandler([this] { // TODO throttle(ripple duration) + this->showChannelsWithSearch(true); + }); - //rpl::combine( - // std::move(addMemberShown), - // std::move(searchShown) - //) | rpl::start_with_next([this] { - // updateHeaderControlsGeometry(width()); - //}, lifetime()); + std::move( + searchShown + ) | rpl::start_with_next([this] { + updateHeaderControlsGeometry(width()); + }, lifetime()); } void Channels::setupList() { @@ -164,7 +162,7 @@ void Channels::setupList() { _list = object_ptr( this, _listController.get(), - st::infoCommonGroupsList); + st::infoChannelsList); _list->scrollToRequests( ) | rpl::start_with_next([this](Ui::ScrollToRequest request) { auto addmin = (request.ymin < 0 || !_header) @@ -271,34 +269,18 @@ void Channels::updateHeaderControlsGeometry(int newWidth) { } void Channels::addChannel() { - //if (const auto chat = _peer->asChat()) { - // if (chat->count >= Global::ChatSizeMax() && chat->amCreator()) { - // Ui::show(Box(chat)); - // } else { - // AddParticipantsBoxController::Start(chat); - // } - //} else if (const auto channel = _peer->asChannel()) { - // const auto state = _listController->saveState(); - // const auto users = ranges::view::all( - // state->list - // ) | ranges::view::transform([](not_null peer) { - // return peer->asUser(); - // }) | ranges::to_vector; - // AddParticipantsBoxController::Start( - // channel, - // { users.begin(), users.end() }); - //} + EditController::Start(_feed); } void Channels::showChannelsWithSearch(bool withSearch) { - //auto contentMemento = std::make_unique( - // _controller); - //contentMemento->setState(saveState()); - //contentMemento->setSearchStartsFocused(withSearch); - //auto mementoStack = std::vector>(); - //mementoStack.push_back(std::move(contentMemento)); - //_controller->showSection( - // Info::Memento(std::move(mementoStack))); + auto contentMemento = std::make_unique( + _controller); + contentMemento->setState(saveState()); + contentMemento->setSearchStartsFocused(withSearch); + auto mementoStack = std::vector>(); + mementoStack.push_back(std::move(contentMemento)); + _controller->showSection( + Info::Memento(std::move(mementoStack))); } void Channels::visibleTopBottomUpdated( diff --git a/Telegram/SourceFiles/info/feed/info_feed_channels_controllers.cpp b/Telegram/SourceFiles/info/feed/info_feed_channels_controllers.cpp index 4c444db79..1631b8192 100644 --- a/Telegram/SourceFiles/info/feed/info_feed_channels_controllers.cpp +++ b/Telegram/SourceFiles/info/feed/info_feed_channels_controllers.cpp @@ -114,7 +114,7 @@ std::unique_ptr ChannelsController::createRestoredRow( } void ChannelsController::prepare() { - setSearchNoResultsText(lang(lng_bot_groups_not_found)); + setSearchNoResultsText(lang(lng_feed_channels_not_found)); delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled); delegate()->peerListSetTitle(langFactory(lng_info_feed_channels)); @@ -241,7 +241,7 @@ NotificationsController::NotificationsController( } void NotificationsController::prepare() { - setSearchNoResultsText(lang(lng_blocked_list_not_found)); + setSearchNoResultsText(lang(lng_feed_channels_not_found)); delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled); delegate()->peerListSetTitle(langFactory(lng_feed_notifications)); @@ -377,9 +377,12 @@ EditController::EditController( } void EditController::prepare() { - setSearchNoResultsText(lang(lng_blocked_list_not_found)); + setSearchNoResultsText(lang(lng_feed_channels_not_found)); delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled); - delegate()->peerListSetTitle(langFactory(lng_feed_create_new)); + delegate()->peerListSetTitle(langFactory( + (_feed->channels().size() < kChannelsInFeedMin + ? lng_feed_create_new + : lng_feed_edit_title))); loadMoreRows(); } @@ -429,6 +432,7 @@ void EditController::applyFeedSources( setDescriptionText(lng_feed_too_few_channels( lt_count, kChannelsInFeedMin)); + delegate()->peerListSetSearchMode(PeerListSearchMode::Disabled); } else { auto alreadyInFeed = ranges::view::all( channels diff --git a/Telegram/SourceFiles/info/feed/info_feed_cover.cpp b/Telegram/SourceFiles/info/feed/info_feed_cover.cpp index 0690d380e..f61a05fea 100644 --- a/Telegram/SourceFiles/info/feed/info_feed_cover.cpp +++ b/Telegram/SourceFiles/info/feed/info_feed_cover.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_feed.h" #include "data/data_session.h" #include "info/info_controller.h" +#include "info/info_memento.h" #include "lang/lang_keys.h" #include "ui/widgets/labels.h" #include "ui/special_buttons.h" @@ -81,12 +82,12 @@ void Cover::refreshStatusText() { } return lng_feed_channels(lt_count, _feed->channels().size()); }(); - _status->setRichText(statusText); - //_status->setLink(1, std::make_shared([=] { - // _controller->showSection(Info::Memento( - // _feed, - // Section::Type::Channels)); - //})); // #TODO channels list + _status->setRichText(textcmdLink(1, statusText)); + _status->setLink(1, std::make_shared([=] { + _controller->showSection(Info::Memento( + _feed, + Section::Type::Channels)); + })); refreshStatusGeometry(width()); } diff --git a/Telegram/SourceFiles/info/info_content_widget.h b/Telegram/SourceFiles/info/info_content_widget.h index 304231dca..af08bf641 100644 --- a/Telegram/SourceFiles/info/info_content_widget.h +++ b/Telegram/SourceFiles/info/info_content_widget.h @@ -119,7 +119,7 @@ public: : _peerId(peerId) , _migratedPeerId(migratedPeerId) { } - ContentMemento(not_null feed) + explicit ContentMemento(not_null feed) : _feed(feed) { } diff --git a/Telegram/SourceFiles/info/info_controller.cpp b/Telegram/SourceFiles/info/info_controller.cpp index 29e46e735..8c169840a 100644 --- a/Telegram/SourceFiles/info/info_controller.cpp +++ b/Telegram/SourceFiles/info/info_controller.cpp @@ -156,7 +156,9 @@ void Controller::updateSearchControllers( auto hasCommonGroupsSearch = (type == Type::CommonGroups); auto hasMembersSearch - = (type == Type::Members || type == Type::Profile); + = (type == Type::Members + || type == Type::Profile + || type == Type::Channels); auto searchQuery = memento->searchFieldQuery(); if (isMedia) { _searchController diff --git a/Telegram/SourceFiles/info/info_controller.h b/Telegram/SourceFiles/info/info_controller.h index 9ae08a170..d4ed642ab 100644 --- a/Telegram/SourceFiles/info/info_controller.h +++ b/Telegram/SourceFiles/info/info_controller.h @@ -42,6 +42,7 @@ public: Media, CommonGroups, Members, + Channels, }; using MediaType = Storage::SharedMediaType; diff --git a/Telegram/SourceFiles/info/info_memento.cpp b/Telegram/SourceFiles/info/info_memento.cpp index 8a8567c68..57206bf09 100644 --- a/Telegram/SourceFiles/info/info_memento.cpp +++ b/Telegram/SourceFiles/info/info_memento.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "info/profile/info_profile_widget.h" #include "info/media/info_media_widget.h" #include "info/members/info_members_widget.h" +#include "info/channels/info_channels_widget.h" #include "info/common_groups/info_common_groups_widget.h" #include "info/feed/info_feed_profile_widget.h" #include "info/info_section_widget.h" @@ -108,6 +109,8 @@ std::unique_ptr Memento::DefaultContent( switch (section.type()) { case Section::Type::Profile: return std::make_unique(feed); + case Section::Type::Channels: + return std::make_unique(feed); } Unexpected("Wrong feed section in Info::Memento::DefaultContent()"); } diff --git a/Telegram/SourceFiles/info/info_top_bar.cpp b/Telegram/SourceFiles/info/info_top_bar.cpp index 5e972dd95..cc81e2e1b 100644 --- a/Telegram/SourceFiles/info/info_top_bar.cpp +++ b/Telegram/SourceFiles/info/info_top_bar.cpp @@ -584,6 +584,9 @@ rpl::producer TitleValue( case Section::Type::Members: return lng_profile_participants_section; + case Section::Type::Channels: + return lng_info_feed_channels; + } Unexpected("Bad section type in Info::TitleValue()"); }()); diff --git a/Telegram/SourceFiles/info/members/info_members_widget.h b/Telegram/SourceFiles/info/members/info_members_widget.h index f7159336a..c44153733 100644 --- a/Telegram/SourceFiles/info/members/info_members_widget.h +++ b/Telegram/SourceFiles/info/members/info_members_widget.h @@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once -#include #include "info/info_content_widget.h" struct PeerListState; diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index f430d22ff..a9c36e092 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -286,6 +286,8 @@ <(src_loc)/info/info_top_bar.h <(src_loc)/info/info_wrap_widget.cpp <(src_loc)/info/info_wrap_widget.h +<(src_loc)/info/channels/info_channels_widget.cpp +<(src_loc)/info/channels/info_channels_widget.h <(src_loc)/info/common_groups/info_common_groups_inner_widget.cpp <(src_loc)/info/common_groups/info_common_groups_inner_widget.h <(src_loc)/info/common_groups/info_common_groups_widget.cpp