edit_participants_box.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #pragma once
  8. #include <rpl/variable.h>
  9. #include "mtproto/sender.h"
  10. #include "base/timer.h"
  11. #include "base/weak_ptr.h"
  12. #include "info/profile/info_profile_members_controllers.h"
  13. class PeerListStories;
  14. struct ChatAdminRightsInfo;
  15. struct ChatRestrictionsInfo;
  16. namespace Ui {
  17. class Show;
  18. } // namespace Ui
  19. namespace Window {
  20. class SessionNavigation;
  21. } // namespace Window
  22. namespace Api {
  23. class ChatParticipant;
  24. } // namespace Api
  25. Fn<void(
  26. ChatAdminRightsInfo oldRights,
  27. ChatAdminRightsInfo newRights,
  28. const QString &rank)> SaveAdminCallback(
  29. std::shared_ptr<Ui::Show> show,
  30. not_null<PeerData*> peer,
  31. not_null<UserData*> user,
  32. Fn<void(
  33. ChatAdminRightsInfo newRights,
  34. const QString &rank)> onDone,
  35. Fn<void()> onFail);
  36. Fn<void(
  37. ChatRestrictionsInfo oldRights,
  38. ChatRestrictionsInfo newRights)> SaveRestrictedCallback(
  39. not_null<PeerData*> peer,
  40. not_null<PeerData*> participant,
  41. Fn<void(ChatRestrictionsInfo newRights)> onDone,
  42. Fn<void()> onFail);
  43. void SubscribeToMigration(
  44. not_null<PeerData*> peer,
  45. rpl::lifetime &lifetime,
  46. Fn<void(not_null<ChannelData*>)> migrate);
  47. enum class ParticipantsRole {
  48. Profile,
  49. Members,
  50. Admins,
  51. Restricted,
  52. Kicked,
  53. };
  54. class ParticipantsOnlineSorter {
  55. public:
  56. ParticipantsOnlineSorter(
  57. not_null<PeerData*> peer,
  58. not_null<PeerListDelegate*> delegate);
  59. void sort();
  60. rpl::producer<int> onlineCountValue() const;
  61. private:
  62. void sortDelayed();
  63. void refreshOnlineCount();
  64. const not_null<PeerData*> _peer;
  65. const not_null<PeerListDelegate*> _delegate;
  66. base::Timer _sortByOnlineTimer;
  67. rpl::variable<int> _onlineCount = 0;
  68. rpl::lifetime _lifetime;
  69. };
  70. class ParticipantsAdditionalData {
  71. public:
  72. using Role = ParticipantsRole;
  73. ParticipantsAdditionalData(not_null<PeerData*> peer, Role role);
  74. PeerData *applyParticipant(const Api::ChatParticipant &data);
  75. PeerData *applyParticipant(
  76. const Api::ChatParticipant &data,
  77. Role overrideRole);
  78. void setExternal(not_null<PeerData*> participant);
  79. void checkForLoaded(not_null<PeerData*> participant);
  80. void fillFromPeer();
  81. [[nodiscard]] bool infoLoaded(not_null<PeerData*> participant) const;
  82. [[nodiscard]] bool canEditAdmin(not_null<UserData*> user) const;
  83. [[nodiscard]] bool canAddOrEditAdmin(not_null<UserData*> user) const;
  84. [[nodiscard]] bool canRestrictParticipant(
  85. not_null<PeerData*> participant) const;
  86. [[nodiscard]] bool canRemoveParticipant(
  87. not_null<PeerData*> participant) const;
  88. [[nodiscard]] std::optional<ChatAdminRightsInfo> adminRights(
  89. not_null<UserData*> user) const;
  90. [[nodiscard]] QString adminRank(not_null<UserData*> user) const;
  91. [[nodiscard]] std::optional<ChatRestrictionsInfo> restrictedRights(
  92. not_null<PeerData*> participant) const;
  93. [[nodiscard]] bool isCreator(not_null<UserData*> user) const;
  94. [[nodiscard]] bool isExternal(not_null<PeerData*> participant) const;
  95. [[nodiscard]] bool isKicked(not_null<PeerData*> participant) const;
  96. [[nodiscard]] UserData *adminPromotedBy(not_null<UserData*> user) const;
  97. [[nodiscard]] UserData *restrictedBy(
  98. not_null<PeerData*> participant) const;
  99. [[nodiscard]] TimeId adminPromotedSince(not_null<UserData*>) const;
  100. [[nodiscard]] TimeId restrictedSince(not_null<PeerData*>) const;
  101. [[nodiscard]] TimeId memberSince(not_null<UserData*>) const;
  102. void migrate(not_null<ChatData*> chat, not_null<ChannelData*> channel);
  103. void applyAdminLocally(
  104. UserData *user,
  105. ChatAdminRightsInfo rights,
  106. const QString &rank);
  107. void applyBannedLocally(
  108. not_null<PeerData*> participant,
  109. ChatRestrictionsInfo rights);
  110. private:
  111. UserData *applyCreator(const Api::ChatParticipant &data);
  112. UserData *applyAdmin(const Api::ChatParticipant &data);
  113. UserData *applyRegular(UserId userId);
  114. PeerData *applyBanned(const Api::ChatParticipant &data);
  115. void fillFromChat(not_null<ChatData*> chat);
  116. void fillFromChannel(not_null<ChannelData*> channel);
  117. not_null<PeerData*> _peer;
  118. Role _role = Role::Members;
  119. UserData *_creator = nullptr;
  120. // Data for chats.
  121. base::flat_set<not_null<UserData*>> _members;
  122. base::flat_set<not_null<UserData*>> _admins;
  123. // Data for channels.
  124. base::flat_map<not_null<UserData*>, ChatAdminRightsInfo> _adminRights;
  125. base::flat_map<not_null<UserData*>, QString> _adminRanks;
  126. base::flat_map<not_null<UserData*>, TimeId> _adminPromotedSince;
  127. base::flat_map<not_null<PeerData*>, TimeId> _restrictedSince;
  128. base::flat_map<not_null<UserData*>, TimeId> _memberSince;
  129. base::flat_set<not_null<UserData*>> _adminCanEdit;
  130. base::flat_map<not_null<UserData*>, not_null<UserData*>> _adminPromotedBy;
  131. std::map<not_null<PeerData*>, ChatRestrictionsInfo> _restrictedRights;
  132. std::set<not_null<PeerData*>> _kicked;
  133. std::map<not_null<PeerData*>, not_null<UserData*>> _restrictedBy;
  134. std::set<not_null<PeerData*>> _external;
  135. std::set<not_null<PeerData*>> _infoNotLoaded;
  136. };
  137. // Viewing admins, banned or restricted users list with search.
  138. class ParticipantsBoxController
  139. : public PeerListController
  140. , public base::has_weak_ptr {
  141. public:
  142. using Role = ParticipantsRole;
  143. static void Start(
  144. not_null<Window::SessionNavigation*> navigation,
  145. not_null<PeerData*> peer,
  146. Role role);
  147. ParticipantsBoxController(
  148. not_null<Window::SessionNavigation*> navigation,
  149. not_null<PeerData*> peer,
  150. Role role);
  151. Main::Session &session() const override;
  152. void prepare() override;
  153. void rowClicked(not_null<PeerListRow*> row) override;
  154. void rowRightActionClicked(not_null<PeerListRow*> row) override;
  155. base::unique_qptr<Ui::PopupMenu> rowContextMenu(
  156. QWidget *parent,
  157. not_null<PeerListRow*> row) override;
  158. void loadMoreRows() override;
  159. bool trackSelectedList() override {
  160. return !_stories;
  161. }
  162. void peerListSearchAddRow(not_null<PeerData*> peer) override;
  163. std::unique_ptr<PeerListRow> createSearchRow(
  164. not_null<PeerData*> peer) override;
  165. std::unique_ptr<PeerListRow> createRestoredRow(
  166. not_null<PeerData*> peer) override;
  167. std::unique_ptr<PeerListState> saveState() const override;
  168. void restoreState(std::unique_ptr<PeerListState> state) override;
  169. [[nodiscard]] rpl::producer<int> onlineCountValue() const;
  170. [[nodiscard]] rpl::producer<int> fullCountValue() const;
  171. void setStoriesShown(bool shown);
  172. protected:
  173. // Allow child controllers not providing navigation.
  174. // This is their responsibility to override all methods that use it.
  175. struct CreateTag {
  176. };
  177. ParticipantsBoxController(
  178. CreateTag,
  179. Window::SessionNavigation *navigation,
  180. not_null<PeerData*> peer,
  181. Role role);
  182. virtual std::unique_ptr<PeerListRow> createRow(
  183. not_null<PeerData*> participant) const;
  184. private:
  185. using Row = Info::Profile::MemberListRow;
  186. using Type = Row::Type;
  187. using Rights = Row::Rights;
  188. struct SavedState : SavedStateBase {
  189. explicit SavedState(const ParticipantsAdditionalData &additional);
  190. using SearchStateBase = PeerListSearchController::SavedStateBase;
  191. std::unique_ptr<SearchStateBase> searchState;
  192. int offset = 0;
  193. bool allLoaded = false;
  194. bool wasLoading = false;
  195. ParticipantsAdditionalData additional;
  196. rpl::lifetime lifetime;
  197. };
  198. static std::unique_ptr<PeerListSearchController> CreateSearchController(
  199. not_null<PeerData*> peer,
  200. Role role,
  201. not_null<ParticipantsAdditionalData*> additional);
  202. QPointer<Ui::BoxContent> showBox(object_ptr<Ui::BoxContent> box) const;
  203. void prepareChatRows(not_null<ChatData*> chat);
  204. void rebuildChatRows(not_null<ChatData*> chat);
  205. void rebuildChatParticipants(not_null<ChatData*> chat);
  206. void rebuildChatAdmins(not_null<ChatData*> chat);
  207. void chatListReady();
  208. void rebuildRowTypes();
  209. void rebuild();
  210. void unload();
  211. void addNewItem();
  212. void addNewParticipants();
  213. void refreshDescription();
  214. void setupListChangeViewers();
  215. void showAdmin(not_null<UserData*> user);
  216. void editAdminDone(
  217. not_null<UserData*> user,
  218. ChatAdminRightsInfo rights,
  219. const QString &rank);
  220. void showRestricted(not_null<UserData*> user);
  221. void editRestrictedDone(
  222. not_null<PeerData*> participant,
  223. ChatRestrictionsInfo rights);
  224. void removeKicked(
  225. not_null<PeerListRow*> row,
  226. not_null<PeerData*> participant);
  227. void removeKickedWithRow(not_null<PeerData*> participant);
  228. void removeKicked(not_null<PeerData*> participant);
  229. void kickParticipant(not_null<PeerData*> participant);
  230. void kickParticipantSure(not_null<PeerData*> participant);
  231. void unkickParticipant(not_null<UserData*> user);
  232. void removeAdmin(not_null<UserData*> user);
  233. void removeAdminSure(not_null<UserData*> user);
  234. bool appendRow(not_null<PeerData*> participant);
  235. bool prependRow(not_null<PeerData*> participant);
  236. bool removeRow(not_null<PeerData*> participant);
  237. void refreshCustomStatus(not_null<PeerListRow*> row) const;
  238. bool feedMegagroupLastParticipants();
  239. Type computeType(not_null<PeerData*> participant) const;
  240. void recomputeTypeFor(not_null<PeerData*> participant);
  241. void subscribeToMigration();
  242. void migrate(not_null<ChatData*> chat, not_null<ChannelData*> channel);
  243. void subscribeToCreatorChange(not_null<ChannelData*> channel);
  244. void fullListRefresh();
  245. void refreshRows();
  246. // It may be nullptr in subclasses of this controller.
  247. Window::SessionNavigation *_navigation = nullptr;
  248. not_null<PeerData*> _peer;
  249. MTP::Sender _api;
  250. Role _role = Role::Admins;
  251. int _offset = 0;
  252. mtpRequestId _loadRequestId = 0;
  253. bool _allLoaded = false;
  254. ParticipantsAdditionalData _additional;
  255. std::unique_ptr<ParticipantsOnlineSorter> _onlineSorter;
  256. rpl::variable<int> _onlineCountValue;
  257. rpl::variable<int> _fullCountValue;
  258. Ui::BoxPointer _editBox;
  259. Ui::BoxPointer _addBox;
  260. QPointer<Ui::BoxContent> _editParticipantBox;
  261. std::unique_ptr<PeerListStories> _stories;
  262. };
  263. // Members, banned and restricted users server side search.
  264. class ParticipantsBoxSearchController : public PeerListSearchController {
  265. public:
  266. using Role = ParticipantsBoxController::Role;
  267. ParticipantsBoxSearchController(
  268. not_null<ChannelData*> channel,
  269. Role role,
  270. not_null<ParticipantsAdditionalData*> additional);
  271. void searchQuery(const QString &query) override;
  272. bool isLoading() override;
  273. bool loadMoreRows() override;
  274. std::unique_ptr<SavedStateBase> saveState() const override;
  275. void restoreState(std::unique_ptr<SavedStateBase> state) override;
  276. private:
  277. struct SavedState : SavedStateBase {
  278. QString query;
  279. int offset = 0;
  280. bool allLoaded = false;
  281. bool wasLoading = false;
  282. };
  283. struct CacheEntry {
  284. MTPchannels_ChannelParticipants result;
  285. int requestedCount = 0;
  286. };
  287. struct Query {
  288. QString text;
  289. int offset = 0;
  290. };
  291. void searchOnServer();
  292. bool searchInCache();
  293. void searchDone(
  294. mtpRequestId requestId,
  295. const MTPchannels_ChannelParticipants &result,
  296. int requestedCount);
  297. not_null<ChannelData*> _channel;
  298. Role _role = Role::Restricted;
  299. not_null<ParticipantsAdditionalData*> _additional;
  300. MTP::Sender _api;
  301. base::Timer _timer;
  302. QString _query;
  303. mtpRequestId _requestId = 0;
  304. int _offset = 0;
  305. bool _allLoaded = false;
  306. std::map<QString, CacheEntry> _cache;
  307. std::map<mtpRequestId, Query> _queries;
  308. };