| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- /*
- 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/profile/info_profile_members.h"
- #include <rpl/combine.h>
- #include "info/profile/info_profile_widget.h"
- #include "info/profile/info_profile_values.h"
- #include "info/profile/info_profile_icon.h"
- #include "info/profile/info_profile_values.h"
- #include "info/profile/info_profile_members_controllers.h"
- #include "info/members/info_members_widget.h"
- #include "info/info_content_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/fields/input_field.h"
- #include "ui/widgets/scroll_area.h"
- #include "ui/wrap/padding_wrap.h"
- #include "ui/text/text_utilities.h" // Ui::Text::ToUpper
- #include "ui/search_field_controller.h"
- #include "lang/lang_keys.h"
- #include "ui/boxes/confirm_box.h"
- #include "boxes/peers/add_participants_box.h"
- #include "window/window_session_controller.h"
- #include "data/data_channel.h"
- #include "data/data_chat.h"
- #include "data/data_user.h"
- #include "styles/style_boxes.h"
- #include "styles/style_info.h"
- namespace Info {
- namespace Profile {
- namespace {
- constexpr auto kEnableSearchMembersAfterCount = 20;
- } // namespace
- Members::Members(
- QWidget *parent,
- not_null<Controller*> controller)
- : RpWidget(parent)
- , _show(controller->uiShow())
- , _controller(controller)
- , _peer(_controller->key().peer())
- , _listController(CreateMembersController(controller, _peer)) {
- _listController->setStoriesShown(true);
- setupHeader();
- setupList();
- setContent(_list.data());
- _listController->setDelegate(static_cast<PeerListDelegate*>(this));
- _controller->searchFieldController()->queryValue(
- ) | rpl::start_with_next([this](QString &&query) {
- peerListScrollToTop();
- content()->searchQueryChanged(std::move(query));
- }, lifetime());
- MembersCountValue(
- _peer
- ) | rpl::start_with_next([this](int count) {
- const auto enabled = (count >= kEnableSearchMembersAfterCount);
- _controller->setSearchEnabledByContent(enabled);
- }, lifetime());
- }
- int Members::desiredHeight() const {
- auto desired = _header ? _header->height() : 0;
- auto count = [this] {
- if (auto chat = _peer->asChat()) {
- return chat->count;
- } else if (auto channel = _peer->asChannel()) {
- return channel->membersCount();
- }
- return 0;
- }();
- desired += qMax(count, _list->fullRowsCount())
- * st::infoMembersList.item.height;
- return qMax(height(), desired);
- }
- rpl::producer<int> Members::onlineCountValue() const {
- return _listController->onlineCountValue();
- }
- rpl::producer<int> Members::fullCountValue() const {
- return _listController->fullCountValue();
- }
- rpl::producer<Ui::ScrollToRequest> Members::scrollToRequests() const {
- return _scrollToRequests.events();
- }
- std::unique_ptr<MembersState> Members::saveState() {
- auto result = std::make_unique<MembersState>();
- result->list = _listController->saveState();
- //if (_searchShown) {
- // result->search = _searchField->getLastText();
- //}
- return result;
- }
- void Members::restoreState(std::unique_ptr<MembersState> state) {
- if (!state) {
- return;
- }
- _listController->restoreState(std::move(state->list));
- //updateSearchEnabledByContent();
- //if (!_controller->searchFieldController()->query().isEmpty()) {
- // if (!_searchShown) {
- // toggleSearch(anim::type::instant);
- // }
- //} else if (_searchShown) {
- // toggleSearch(anim::type::instant);
- //}
- }
- void Members::setupHeader() {
- if (_controller->section().type() == Section::Type::Members) {
- return;
- }
- _header = object_ptr<Ui::FixedHeightWidget>(
- this,
- st::infoMembersHeader);
- auto parent = _header.data();
- _openMembers = Ui::CreateChild<Ui::SettingsButton>(
- parent,
- rpl::single(QString()));
- object_ptr<FloatingIcon>(
- parent,
- st::infoIconMembers,
- st::infoGroupMembersIconPosition);
- _titleWrap = Ui::CreateChild<Ui::RpWidget>(parent);
- _title = setupTitle();
- _addMember = Ui::CreateChild<Ui::IconButton>(
- _openMembers,
- st::infoMembersAddMember);
- //_searchField = _controller->searchFieldController()->createField(
- // parent,
- // st::infoMembersSearchField);
- _search = Ui::CreateChild<Ui::IconButton>(
- _openMembers,
- st::infoMembersSearch);
- //_cancelSearch = Ui::CreateChild<Ui::CrossButton>(
- // parent,
- // st::infoMembersCancelSearch);
- setupButtons();
- //_controller->wrapValue(
- //) | rpl::start_with_next([this](Wrap wrap) {
- // _wrap = wrap;
- // updateSearchOverrides();
- //}, lifetime());
- widthValue(
- ) | rpl::start_with_next([this](int width) {
- _header->resizeToWidth(width);
- }, _header->lifetime());
- }
- object_ptr<Ui::FlatLabel> Members::setupTitle() {
- auto visible = _peer->isMegagroup()
- ? CanViewParticipantsValue(_peer->asMegagroup())
- : rpl::single(true);
- auto result = object_ptr<Ui::FlatLabel>(
- _titleWrap,
- rpl::conditional(
- std::move(visible),
- tr::lng_chat_status_members(
- lt_count_decimal,
- MembersCountValue(_peer) | tr::to_count(),
- Ui::Text::Upper),
- tr::lng_channel_admins(Ui::Text::Upper)),
- st::infoBlockHeaderLabel);
- result->setAttribute(Qt::WA_TransparentForMouseEvents);
- return result;
- }
- void Members::setupButtons() {
- using namespace rpl::mappers;
- _openMembers->addClickHandler([this] {
- showMembersWithSearch(false);
- });
- //_searchField->hide();
- //_cancelSearch->setVisible(false);
- auto visible = _peer->isMegagroup()
- ? CanViewParticipantsValue(_peer->asMegagroup())
- : rpl::single(true);
- rpl::duplicate(visible) | rpl::start_with_next([=](bool visible) {
- _openMembers->setVisible(visible);
- }, lifetime());
- auto addMemberShown = CanAddMemberValue(
- _peer
- ) | rpl::start_spawning(lifetime());
- _addMember->showOn(rpl::duplicate(addMemberShown));
- _addMember->addClickHandler([this] { // TODO throttle(ripple duration)
- this->addMember();
- });
- 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);
- });
- //_cancelSearch->addClickHandler([this] {
- // this->cancelSearch();
- //});
- rpl::combine(
- std::move(addMemberShown),
- std::move(searchShown),
- std::move(visible)
- ) | rpl::start_with_next([this] {
- updateHeaderControlsGeometry(width());
- }, lifetime());
- }
- void Members::setupList() {
- auto topSkip = _header ? _header->height() : 0;
- _listController->setStyleOverrides(&st::infoMembersList);
- _listController->setStoriesShown(true);
- _list = object_ptr<ListWidget>(
- this,
- _listController.get());
- _list->scrollToRequests(
- ) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
- auto addmin = (request.ymin < 0 || !_header)
- ? 0
- : _header->height();
- auto addmax = (request.ymax < 0 || !_header)
- ? 0
- : _header->height();
- _scrollToRequests.fire({
- request.ymin + addmin,
- request.ymax + addmax });
- }, _list->lifetime());
- widthValue(
- ) | rpl::start_with_next([this](int newWidth) {
- _list->resizeToWidth(newWidth);
- }, _list->lifetime());
- _list->heightValue(
- ) | rpl::start_with_next([=](int listHeight) {
- auto newHeight = (listHeight > st::membersMarginBottom)
- ? (topSkip
- + listHeight
- + st::membersMarginBottom)
- : 0;
- resize(width(), newHeight);
- }, _list->lifetime());
- _list->moveToLeft(0, topSkip);
- }
- int Members::resizeGetHeight(int newWidth) {
- if (_header) {
- updateHeaderControlsGeometry(newWidth);
- }
- return heightNoMargins();
- }
- //void Members::updateSearchEnabledByContent() {
- // _controller->setSearchEnabledByContent(
- // peerListFullRowsCount() >= kEnableSearchMembersAfterCount);
- //}
- void Members::updateHeaderControlsGeometry(int newWidth) {
- _openMembers->setGeometry(0, st::infoProfileSkip, newWidth, st::infoMembersButton.height);
- auto availableWidth = newWidth
- - st::infoMembersButtonPosition.x();
- //auto cancelLeft = availableWidth - _cancelSearch->width();
- //_cancelSearch->moveToLeft(
- // cancelLeft,
- // st::infoMembersButtonPosition.y());
- //auto searchShownLeft = st::infoIconPosition.x()
- // - st::infoMembersSearch.iconPosition.x();
- //auto searchHiddenLeft = availableWidth - _search->width();
- //auto searchShown = _searchShownAnimation.value(_searchShown ? 1. : 0.);
- //auto searchCurrentLeft = anim::interpolate(
- // searchHiddenLeft,
- // searchShownLeft,
- // searchShown);
- //_search->moveToLeft(
- // searchCurrentLeft,
- // st::infoMembersButtonPosition.y());
- //if (!_search->isHidden()) {
- // availableWidth -= st::infoMembersSearch.width;
- //}
- _addMember->moveToLeft(
- availableWidth - _addMember->width(),
- st::infoMembersButtonPosition.y(),
- newWidth);
- if (!_addMember->isHidden()) {
- availableWidth -= st::infoMembersSearch.width;
- }
- _search->moveToLeft(
- availableWidth - _search->width(),
- st::infoMembersButtonPosition.y(),
- newWidth);
- //auto fieldLeft = anim::interpolate(
- // cancelLeft,
- // st::infoBlockHeaderPosition.x(),
- // searchShown);
- //_searchField->setGeometryToLeft(
- // fieldLeft,
- // st::infoMembersSearchTop,
- // cancelLeft - fieldLeft,
- // _searchField->height());
- //_titleWrap->resize(
- // searchCurrentLeft - st::infoBlockHeaderPosition.x(),
- // _title->height());
- _titleWrap->resize(
- availableWidth - _addMember->width() - st::infoBlockHeaderPosition.x(),
- _title->height());
- _titleWrap->moveToLeft(
- st::infoBlockHeaderPosition.x(),
- st::infoBlockHeaderPosition.y(),
- newWidth);
- _titleWrap->setAttribute(Qt::WA_TransparentForMouseEvents);
- //_title->resizeToWidth(searchHiddenLeft);
- _title->resizeToWidth(_titleWrap->width());
- _title->moveToLeft(0, 0);
- }
- void Members::addMember() {
- if (const auto chat = _peer->asChat()) {
- AddParticipantsBoxController::Start(_controller, chat);
- } else if (const auto channel = _peer->asChannel()) {
- const auto state = _listController->saveState();
- const auto users = ranges::views::all(
- state->list
- ) | ranges::views::transform([](not_null<PeerData*> peer) {
- return peer->asUser();
- }) | ranges::to_vector;
- AddParticipantsBoxController::Start(
- _controller,
- channel,
- { users.begin(), users.end() });
- }
- }
- void Members::showMembersWithSearch(bool withSearch) {
- //if (!_searchShown) {
- // toggleSearch();
- //}
- auto contentMemento = std::make_shared<Info::Members::Memento>(
- _controller);
- contentMemento->setState(saveState());
- contentMemento->setSearchStartsFocused(withSearch);
- auto mementoStack = std::vector<std::shared_ptr<ContentMemento>>();
- mementoStack.push_back(std::move(contentMemento));
- _controller->showSection(
- std::make_shared<Info::Memento>(std::move(mementoStack)));
- }
- //void Members::toggleSearch(anim::type animated) {
- // _searchShown = !_searchShown;
- // _cancelSearch->toggle(_searchShown, animated);
- // if (animated == anim::type::normal) {
- // _searchShownAnimation.start(
- // [this] { searchAnimationCallback(); },
- // _searchShown ? 0. : 1.,
- // _searchShown ? 1. : 0.,
- // st::slideWrapDuration);
- // } else {
- // _searchShownAnimation.finish();
- // searchAnimationCallback();
- // }
- // _search->setDisabled(_searchShown);
- // if (_searchShown) {
- // _searchField->show();
- // _searchField->setFocus();
- // } else {
- // setFocus();
- // }
- //}
- //
- //void Members::searchAnimationCallback() {
- // if (!_searchShownAnimation.animating()) {
- // _searchField->setVisible(_searchShown);
- // updateSearchOverrides();
- // _search->setPointerCursor(!_searchShown);
- // }
- // updateHeaderControlsGeometry(width());
- //}
- //
- //void Members::updateSearchOverrides() {
- // auto iconOverride = !_searchShown
- // ? nullptr
- // : (_wrap == Wrap::Layer)
- // ? &st::infoMembersSearchActiveLayer
- // : &st::infoMembersSearchActive;
- // _search->setIconOverride(iconOverride, iconOverride);
- //}
- //
- //void Members::cancelSearch() {
- // if (_searchShown) {
- // if (!_searchField->getLastText().isEmpty()) {
- // _searchField->setText(QString());
- // _searchField->setFocus();
- // } else {
- // toggleSearch();
- // }
- // }
- //}
- void Members::visibleTopBottomUpdated(
- int visibleTop,
- int visibleBottom) {
- setChildVisibleTopBottom(_list, visibleTop, visibleBottom);
- }
- void Members::peerListSetTitle(rpl::producer<QString> title) {
- }
- void Members::peerListSetAdditionalTitle(rpl::producer<QString> title) {
- }
- bool Members::peerListIsRowChecked(not_null<PeerListRow*> row) {
- return false;
- }
- int Members::peerListSelectedRowsCount() {
- return 0;
- }
- void Members::peerListScrollToTop() {
- _scrollToRequests.fire({ -1, -1 });
- }
- void Members::peerListAddSelectedPeerInBunch(not_null<PeerData*> peer) {
- Unexpected("Item selection in Info::Profile::Members.");
- }
- void Members::peerListAddSelectedRowInBunch(not_null<PeerListRow*> row) {
- Unexpected("Item selection in Info::Profile::Members.");
- }
- void Members::peerListFinishSelectedRowsBunch() {
- }
- std::shared_ptr<Main::SessionShow> Members::peerListUiShow() {
- return _show;
- }
- void Members::peerListSetDescription(
- object_ptr<Ui::FlatLabel> description) {
- description.destroy();
- }
- } // namespace Profile
- } // namespace Info
|