/* 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 #include "boxes/peer_list_box.h" #include "mtproto/sender.h" #include "base/timer.h" #include "base/weak_ptr.h" #include "info/profile/info_profile_members_controllers.h" struct ChatAdminRightsInfo; struct ChatRestrictionsInfo; namespace Window { class SessionNavigation; } // namespace Window namespace Api { class ChatParticipant; } // namespace Api Fn SaveAdminCallback( not_null peer, not_null user, Fn onDone, Fn onFail); Fn SaveRestrictedCallback( not_null peer, not_null participant, Fn onDone, Fn onFail); void SubscribeToMigration( not_null peer, rpl::lifetime &lifetime, Fn)> migrate); enum class ParticipantsRole { Profile, Members, Admins, Restricted, Kicked, }; class ParticipantsOnlineSorter { public: ParticipantsOnlineSorter( not_null peer, not_null delegate); void sort(); rpl::producer onlineCountValue() const; private: void sortDelayed(); void refreshOnlineCount(); const not_null _peer; const not_null _delegate; base::Timer _sortByOnlineTimer; rpl::variable _onlineCount = 0; rpl::lifetime _lifetime; }; class ParticipantsAdditionalData { public: using Role = ParticipantsRole; ParticipantsAdditionalData(not_null peer, Role role); PeerData *applyParticipant(const Api::ChatParticipant &data); PeerData *applyParticipant( const Api::ChatParticipant &data, Role overrideRole); void setExternal(not_null participant); void checkForLoaded(not_null participant); void fillFromPeer(); [[nodiscard]] bool infoLoaded(not_null participant) const; [[nodiscard]] bool canEditAdmin(not_null user) const; [[nodiscard]] bool canAddOrEditAdmin(not_null user) const; [[nodiscard]] bool canRestrictParticipant( not_null participant) const; [[nodiscard]] bool canRemoveParticipant( not_null participant) const; [[nodiscard]] std::optional adminRights( not_null user) const; QString adminRank(not_null user) const; [[nodiscard]] std::optional restrictedRights( not_null participant) const; [[nodiscard]] bool isCreator(not_null user) const; [[nodiscard]] bool isExternal(not_null participant) const; [[nodiscard]] bool isKicked(not_null participant) const; [[nodiscard]] UserData *adminPromotedBy(not_null user) const; [[nodiscard]] UserData *restrictedBy(not_null participant) const; void migrate(not_null chat, not_null channel); void applyAdminLocally( UserData *user, ChatAdminRightsInfo rights, const QString &rank); void applyBannedLocally( not_null participant, ChatRestrictionsInfo rights); private: UserData *applyCreator(const Api::ChatParticipant &data); UserData *applyAdmin(const Api::ChatParticipant &data); UserData *applyRegular(UserId userId); PeerData *applyBanned(const Api::ChatParticipant &data); void fillFromChat(not_null chat); void fillFromChannel(not_null channel); not_null _peer; Role _role = Role::Members; UserData *_creator = nullptr; // Data for chats. base::flat_set> _members; base::flat_set> _admins; // Data for channels. base::flat_map, ChatAdminRightsInfo> _adminRights; base::flat_map, QString> _adminRanks; base::flat_set> _adminCanEdit; base::flat_map, not_null> _adminPromotedBy; std::map, ChatRestrictionsInfo> _restrictedRights; std::set> _kicked; std::map, not_null> _restrictedBy; std::set> _external; std::set> _infoNotLoaded; }; // Viewing admins, banned or restricted users list with search. class ParticipantsBoxController : public PeerListController , public base::has_weak_ptr { public: using Role = ParticipantsRole; static void Start( not_null navigation, not_null peer, Role role); ParticipantsBoxController( not_null navigation, not_null peer, Role role); Main::Session &session() const override; void prepare() override; void rowClicked(not_null row) override; void rowRightActionClicked(not_null row) override; base::unique_qptr rowContextMenu( QWidget *parent, not_null row) override; void loadMoreRows() override; void peerListSearchAddRow(not_null peer) override; std::unique_ptr createSearchRow( not_null peer) override; std::unique_ptr createRestoredRow( not_null peer) override; std::unique_ptr saveState() const override; void restoreState(std::unique_ptr state) override; rpl::producer onlineCountValue() const override; protected: // Allow child controllers not providing navigation. // This is their responsibility to override all methods that use it. struct CreateTag { }; ParticipantsBoxController( CreateTag, Window::SessionNavigation *navigation, not_null peer, Role role); virtual std::unique_ptr createRow( not_null participant) const; private: using Row = Info::Profile::MemberListRow; using Type = Row::Type; using Rights = Row::Rights; struct SavedState : SavedStateBase { explicit SavedState(const ParticipantsAdditionalData &additional); using SearchStateBase = PeerListSearchController::SavedStateBase; std::unique_ptr searchState; int offset = 0; bool allLoaded = false; bool wasLoading = false; ParticipantsAdditionalData additional; rpl::lifetime lifetime; }; static std::unique_ptr CreateSearchController( not_null peer, Role role, not_null additional); void prepareChatRows(not_null chat); void rebuildChatRows(not_null chat); void rebuildChatParticipants(not_null chat); void rebuildChatAdmins(not_null chat); void chatListReady(); void rebuildRowTypes(); void addNewItem(); void addNewParticipants(); void refreshDescription(); void setupListChangeViewers(); void showAdmin(not_null user); void editAdminDone( not_null user, ChatAdminRightsInfo rights, const QString &rank); void showRestricted(not_null user); void editRestrictedDone( not_null participant, ChatRestrictionsInfo rights); void removeKicked( not_null row, not_null participant); void removeKickedWithRow(not_null participant); void removeKicked(not_null participant); void kickParticipant(not_null participant); void kickParticipantSure(not_null participant); void unkickParticipant(not_null user); void removeAdmin(not_null user); void removeAdminSure(not_null user); bool appendRow(not_null participant); bool prependRow(not_null participant); bool removeRow(not_null participant); void refreshCustomStatus(not_null row) const; bool feedMegagroupLastParticipants(); Type computeType(not_null participant) const; void recomputeTypeFor(not_null participant); void subscribeToMigration(); void migrate(not_null chat, not_null channel); void subscribeToCreatorChange(not_null channel); void fullListRefresh(); // It may be nullptr in subclasses of this controller. Window::SessionNavigation *_navigation = nullptr; not_null _peer; MTP::Sender _api; Role _role = Role::Admins; int _offset = 0; mtpRequestId _loadRequestId = 0; bool _allLoaded = false; ParticipantsAdditionalData _additional; std::unique_ptr _onlineSorter; Ui::BoxPointer _editBox; Ui::BoxPointer _addBox; QPointer _editParticipantBox; }; // Members, banned and restricted users server side search. class ParticipantsBoxSearchController : public PeerListSearchController { public: using Role = ParticipantsBoxController::Role; ParticipantsBoxSearchController( not_null channel, Role role, not_null additional); void searchQuery(const QString &query) override; bool isLoading() override; bool loadMoreRows() override; std::unique_ptr saveState() const override; void restoreState(std::unique_ptr state) override; private: struct SavedState : SavedStateBase { QString query; int offset = 0; bool allLoaded = false; bool wasLoading = false; }; struct CacheEntry { MTPchannels_ChannelParticipants result; int requestedCount = 0; }; struct Query { QString text; int offset = 0; }; void searchOnServer(); bool searchInCache(); void searchDone( mtpRequestId requestId, const MTPchannels_ChannelParticipants &result, int requestedCount); not_null _channel; Role _role = Role::Restricted; not_null _additional; MTP::Sender _api; base::Timer _timer; QString _query; mtpRequestId _requestId = 0; int _offset = 0; bool _allLoaded = false; std::map _cache; std::map _queries; };