Display feed channels list in feed info.

This commit is contained in:
John Preston 2018-02-07 15:40:37 +03:00
parent a144e35f84
commit 99c686e3e1
11 changed files with 310 additions and 40 deletions

View file

@ -1429,6 +1429,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_feed_channels#other" = "{count} channels";
"lng_info_feed_title" = "Feed Info";
"lng_info_feed_is_default" = "Group new channels";
"lng_info_feed_channels" = "Channels";
// Wnd specific

View file

@ -7,8 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "info/feed/info_feed_channels.h"
#include "info/feed/info_feed_channels_controllers.h"
#include "info/profile/info_profile_icon.h"
#include "info/profile/info_profile_button.h"
#include "info/profile/info_profile_values.h"
#include "info/info_controller.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h"
@ -16,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/padding_wrap.h"
#include "ui/search_field_controller.h"
#include "boxes/peer_list_controllers.h"
#include "lang/lang_keys.h"
#include "styles/style_boxes.h"
#include "styles/style_info.h"
@ -33,7 +36,7 @@ Channels::Channels(
: RpWidget(parent)
, _controller(controller)
, _feed(_controller->key().feed())
, _listController(std::make_unique<ContactsBoxController>()) {
, _listController(std::make_unique<ChannelsController>(_controller)) {
setupHeader();
setupList();
setContent(_list.data());
@ -44,12 +47,12 @@ Channels::Channels(
peerListScrollToTop();
content()->searchQueryChanged(std::move(query));
}, lifetime());
//MembersCountValue(
// _peer
//) | rpl::start_with_next([this](int count) {
// const auto enabled = (count >= kEnableSearchChannelsAfterCount);
// _controller->setSearchEnabledByContent(enabled);
//}, lifetime());
Profile::FeedChannelsCountValue(
_feed
) | rpl::start_with_next([this](int count) {
const auto enabled = (count >= kEnableSearchChannelsAfterCount);
_controller->setSearchEnabledByContent(enabled);
}, lifetime());
}
int Channels::desiredHeight() const {
@ -122,12 +125,11 @@ void Channels::setupHeader() {
object_ptr<Ui::FlatLabel> Channels::setupTitle() {
auto result = object_ptr<Ui::FlatLabel>(
_titleWrap,
rpl::single(QString("Contacts")),
//MembersCountValue(
// _peer
//) | rpl::map([](int count) {
// return lng_chat_status_members(lt_count, count);
//}) | ToUpperValue(),
Profile::FeedChannelsCountValue(
_feed
) | rpl::map([](int count) {
return lng_feed_channels(lt_count, count);
}) | Profile::ToUpperValue(),
st::infoBlockHeaderLabel);
result->setAttribute(Qt::WA_TransparentForMouseEvents);
return result;

View file

@ -0,0 +1,110 @@
/*
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/feed/info_feed_channels_controllers.h"
#include "data/data_feed.h"
#include "data/data_session.h"
#include "info/info_controller.h"
#include "lang/lang_keys.h"
#include "auth_session.h"
#include "history/history.h"
namespace Info {
namespace FeedProfile {
ChannelsController::ChannelsController(not_null<Controller*> controller)
: PeerListController()
, _controller(controller)
, _feed(_controller->key().feed()) {
_controller->setSearchEnabledByContent(false);
}
std::unique_ptr<PeerListRow> ChannelsController::createRow(
not_null<PeerData*> peer) {
auto result = std::make_unique<PeerListRow>(peer);
result->setCustomStatus(QString());
return result;
}
std::unique_ptr<PeerListRow> ChannelsController::createRestoredRow(
not_null<PeerData*> peer) {
return createRow(peer);
}
void ChannelsController::prepare() {
setSearchNoResultsText(lang(lng_bot_groups_not_found));
delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled);
delegate()->peerListSetTitle(langFactory(lng_info_feed_channels));
rebuildRows();
using Flag = Data::FeedUpdateFlag;
rpl::single(
Data::FeedUpdate{ _feed, Flag::Channels }
) | rpl::then(
Auth().data().feedUpdated()
) | rpl::filter([=](const Data::FeedUpdate &update) {
return (update.feed == _feed) && (update.flag == Flag::Channels);
}) | rpl::filter([=] {
return _feed->channelsLoaded();
}) | rpl::start_with_next([=] {
rebuildRows();
}, lifetime());
}
void ChannelsController::rebuildRows() {
if (!_feed->channelsLoaded()) {
return;
}
const auto &channels = _feed->channels();
auto count = delegate()->peerListFullRowsCount();
for (auto i = 0; i != count;) {
const auto row = delegate()->peerListRowAt(i);
const auto peer = row->peer();
if (ranges::find_if(channels, [=](not_null<History*> history) {
return (history->peer == peer);
}) != end(channels)) {
++i;
} else {
delegate()->peerListRemoveRow(row);
--count;
}
}
for (const auto history : channels) {
if (auto row = createRow(history->peer)) {
delegate()->peerListAppendRow(std::move(row));
}
}
}
std::unique_ptr<PeerListState> ChannelsController::saveState() const {
auto result = PeerListController::saveState();
auto my = std::make_unique<SavedState>();
using Flag = Data::FeedUpdateFlag;
Auth().data().feedUpdated(
) | rpl::filter([=](const Data::FeedUpdate &update) {
return (update.feed == _feed) && (update.flag == Flag::Channels);
}) | rpl::start_with_next([state = result.get()] {
state->controllerState = nullptr;
}, my->lifetime);
result->controllerState = std::move(my);
return result;
}
void ChannelsController::restoreState(
std::unique_ptr<PeerListState> state) {
PeerListController::restoreState(std::move(state));
}
void ChannelsController::rowClicked(not_null<PeerListRow*> row) {
_controller->parentController()->showPeerHistory(
row->peer(),
Window::SectionShow::Way::Forward);
}
} // namespace FeedProfile
} // namespace Info

View file

@ -0,0 +1,51 @@
/*
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 "boxes/peer_list_box.h"
namespace Data {
class Feed;
} // namespace Data
namespace Info {
class Controller;
namespace FeedProfile {
class ChannelsController
: public PeerListController
, private base::Subscriber {
public:
ChannelsController(not_null<Controller*> controller);
void prepare() override;
void rowClicked(not_null<PeerListRow*> row) override;
std::unique_ptr<PeerListRow> createRestoredRow(
not_null<PeerData*> peer) override;
std::unique_ptr<PeerListState> saveState() const override;
void restoreState(std::unique_ptr<PeerListState> state) override;
private:
struct SavedState : SavedStateBase {
rpl::lifetime lifetime;
};
void rebuildRows();
std::unique_ptr<PeerListRow> createRow(not_null<PeerData*> peer);
const not_null<Controller*> _controller;
not_null<Data::Feed*> _feed;
};
} // namespace FeedProfile
} // namespace Info

View file

@ -42,6 +42,7 @@ Cover::Cover(
_name->setSelectable(true);
_name->setContextCopyText(lang(lng_profile_copy_fullname));
refreshNameText();
refreshStatusText();
initViewers();
setupChildGeometry();
@ -62,7 +63,7 @@ void Cover::setupChildGeometry() {
void Cover::initViewers() {
Auth().data().feedUpdated(
) | rpl::filter([](const Data::FeedUpdate &update) {
return update.flag == Data::FeedUpdateFlag::Channels;
return (update.flag == Data::FeedUpdateFlag::Channels);
}) | rpl::start_with_next(
[=] { refreshStatusText(); },
lifetime());

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/feed/info_feed_profile_widget.h"
#include "info/feed/info_feed_cover.h"
#include "info/feed/info_feed_channels.h"
#include "info/profile/info_profile_actions.h"
#include "ui/widgets/scroll_area.h"
#include "ui/wrap/vertical_layout.h"
@ -39,32 +40,26 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
_cover = result->add(object_ptr<Cover>(
result,
_controller));
//auto details = SetupDetails(_controller, parent, _peer);
//result->add(std::move(details));
//if (auto members = SetupChannelMembers(_controller, result.data(), _peer)) {
// result->add(std::move(members));
//}
//result->add(object_ptr<BoxContentDivider>(result));
//if (auto actions = SetupActions(_controller, result.data(), _peer)) {
// result->add(std::move(actions));
//}
auto details = Profile::SetupFeedDetails(_controller, parent, _feed);
result->add(std::move(details));
result->add(object_ptr<BoxContentDivider>(result));
//_channels = result->add(object_ptr<Channels>(
// result,
// _controller)
//);
//_channels->scrollToRequests(
//) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
// auto min = (request.ymin < 0)
// ? request.ymin
// : mapFromGlobal(_channels->mapToGlobal({ 0, request.ymin })).y();
// auto max = (request.ymin < 0)
// ? mapFromGlobal(_channels->mapToGlobal({ 0, 0 })).y()
// : (request.ymax < 0)
// ? request.ymax
// : mapFromGlobal(_channels->mapToGlobal({ 0, request.ymax })).y();
// _scrollToRequests.fire({ min, max });
//}, _channels->lifetime());
_channels = result->add(object_ptr<Channels>(
result,
_controller)
);
_channels->scrollToRequests(
) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
auto min = (request.ymin < 0)
? request.ymin
: mapFromGlobal(_channels->mapToGlobal({ 0, request.ymin })).y();
auto max = (request.ymin < 0)
? mapFromGlobal(_channels->mapToGlobal({ 0, 0 })).y()
: (request.ymax < 0)
? request.ymax
: mapFromGlobal(_channels->mapToGlobal({ 0, request.ymax })).y();
_scrollToRequests.fire({ min, max });
}, _channels->lifetime());
return std::move(result);
}

View file

@ -164,6 +164,37 @@ private:
};
class FeedDetailsFiller {
public:
FeedDetailsFiller(
not_null<Controller*> controller,
not_null<Ui::RpWidget*> parent,
not_null<Data::Feed*> feed);
object_ptr<Ui::RpWidget> fill();
private:
object_ptr<Ui::RpWidget> setupDefaultToggle();
template <
typename Widget,
typename = std::enable_if_t<
std::is_base_of_v<Ui::RpWidget, Widget>>>
Widget *add(
object_ptr<Widget> &&child,
const style::margins &margin = style::margins()) {
return _wrap->add(
std::move(child),
margin);
}
not_null<Controller*> _controller;
not_null<Ui::RpWidget*> _parent;
not_null<Data::Feed*> _feed;
object_ptr<Ui::VerticalLayout> _wrap;
};
DetailsFiller::DetailsFiller(
not_null<Controller*> controller,
not_null<Ui::RpWidget*> parent,
@ -650,6 +681,42 @@ object_ptr<Ui::RpWidget> ActionsFiller::fill() {
return { nullptr };
}
FeedDetailsFiller::FeedDetailsFiller(
not_null<Controller*> controller,
not_null<Ui::RpWidget*> parent,
not_null<Data::Feed*> feed)
: _controller(controller)
, _parent(parent)
, _feed(feed)
, _wrap(_parent) {
}
object_ptr<Ui::RpWidget> FeedDetailsFiller::fill() {
add(object_ptr<BoxContentDivider>(_wrap));
add(CreateSkipWidget(_wrap));
add(setupDefaultToggle());
add(CreateSkipWidget(_wrap));
return std::move(_wrap);
}
object_ptr<Ui::RpWidget> FeedDetailsFiller::setupDefaultToggle() {
const auto feed = _feed;
auto result = object_ptr<Button>(
_wrap,
Lang::Viewer(lng_info_feed_is_default),
st::infoNotificationsButton);
result->toggleOn(
rpl::single(false)// #TODO default
)->addClickHandler([=] {
});
object_ptr<FloatingIcon>(
result,
st::infoIconNotifications,
st::infoNotificationsIconPosition);
return std::move(result);
}
} // namespace
object_ptr<Ui::RpWidget> SetupDetails(
@ -746,5 +813,13 @@ object_ptr<Ui::RpWidget> SetupChannelMembers(
return std::move(result);
}
object_ptr<Ui::RpWidget> SetupFeedDetails(
not_null<Controller*> controller,
not_null<Ui::RpWidget*> parent,
not_null<Data::Feed*> feed) {
FeedDetailsFiller filler(controller, parent, feed);
return filler.fill();
}
} // namespace Profile
} // namespace Info

View file

@ -7,9 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace Data {
class Feed;
} // namespace Data
namespace Ui {
class RpWidget;
}
} // namespace Ui
namespace Info {
@ -32,5 +36,10 @@ object_ptr<Ui::RpWidget> SetupChannelMembers(
not_null<Ui::RpWidget*> parent,
not_null<PeerData*> peer);
object_ptr<Ui::RpWidget> SetupFeedDetails(
not_null<Controller*> controller,
not_null<Ui::RpWidget*> parent,
not_null<Data::Feed*> feed);
} // namespace Profile
} // namespace Info

View file

@ -13,9 +13,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <rpl/combine.h>
#include "observer_peer.h"
#include "messenger.h"
#include "auth_session.h"
#include "ui/wrap/slide_wrap.h"
#include "data/data_peer_values.h"
#include "data/data_shared_media.h"
#include "data/data_feed.h"
#include "data/data_session.h"
namespace Info {
namespace Profile {
@ -292,5 +295,22 @@ rpl::producer<bool> VerifiedValue(
return rpl::single(false);
}
rpl::producer<int> FeedChannelsCountValue(
not_null<Data::Feed*> feed) {
using Flag = Data::FeedUpdateFlag;
return rpl::single(
Data::FeedUpdate{ feed, Flag::Channels }
) | rpl::then(
Auth().data().feedUpdated()
) | rpl::filter([=](const Data::FeedUpdate &update) {
return (update.feed == feed) && (update.flag == Flag::Channels);
}) | rpl::filter([=] {
return feed->channelsLoaded();
}) | rpl::map([=] {
return int(feed->channels().size());
}) | rpl::distinct_until_changed();
}
} // namespace Profile
} // namespace Info

View file

@ -83,5 +83,8 @@ rpl::producer<bool> CanAddMemberValue(
rpl::producer<bool> VerifiedValue(
not_null<PeerData*> peer);
rpl::producer<int> FeedChannelsCountValue(
not_null<Data::Feed*> feed);
} // namespace Profile
} // namespace Info

View file

@ -292,6 +292,8 @@
<(src_loc)/info/common_groups/info_common_groups_widget.h
<(src_loc)/info/feed/info_feed_channels.cpp
<(src_loc)/info/feed/info_feed_channels.h
<(src_loc)/info/feed/info_feed_channels_controllers.cpp
<(src_loc)/info/feed/info_feed_channels_controllers.h
<(src_loc)/info/feed/info_feed_cover.cpp
<(src_loc)/info/feed/info_feed_cover.h
<(src_loc)/info/feed/info_feed_profile_inner_widget.cpp