From 513a9f8d45dca063a89b6e748aba1766b0c230ce Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 7 Jun 2017 15:59:45 +0300 Subject: [PATCH] Add rich supergroup/channel admin support. --- Telegram/Resources/langs/lang.strings | 26 ++++ Telegram/SourceFiles/apiwrap.cpp | 11 +- Telegram/SourceFiles/boxes/contacts_box.cpp | 14 +- Telegram/SourceFiles/boxes/contacts_box.h | 6 +- .../boxes/edit_participant_box.cpp | 129 ++++++++++++++++++ .../SourceFiles/boxes/edit_participant_box.h | 95 +++++++++++++ Telegram/SourceFiles/boxes/members_box.cpp | 14 +- Telegram/SourceFiles/boxes/members_box.h | 13 +- .../profile/profile_block_group_members.cpp | 67 ++++----- .../profile/profile_block_group_members.h | 4 +- Telegram/SourceFiles/structs.cpp | 4 +- Telegram/SourceFiles/structs.h | 3 +- Telegram/gyp/telegram_sources.txt | 2 + 13 files changed, 326 insertions(+), 62 deletions(-) create mode 100644 Telegram/SourceFiles/boxes/edit_participant_box.cpp create mode 100644 Telegram/SourceFiles/boxes/edit_participant_box.h diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 44108d73b..0b35ffbc8 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1244,6 +1244,32 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org "lng_player_message_yesterday" = "Yesterday at {time}"; "lng_player_message_date" = "{date} at {time}"; +"lng_rights_edit_admin" = "Edit administrator"; +"lng_rights_edit_admin_header" = "What can this admin do?"; +"lng_rights_about_add_admins_yes" = "This admin will be able to add new admins with the same (or more limited) permissions than they have."; +"lng_rights_about_add_admins_no" = "This admin will not be able to add new admins."; +"lng_rights_user_restrictions" = "User restrictions"; +"lng_rights_user_restrictions_header" = "What can this user do?"; + +"lng_rights_channel_info" = "Change channel info"; +"lng_rights_channel_post" = "Post messages"; +"lng_rights_channel_edit" = "Edit messages of others"; +"lng_rights_group_info" = "Change group info"; +"lng_rights_group_ban" = "Ban users"; +"lng_rights_group_invite" = "Add users"; +"lng_rights_group_invite_link" = "Invite users via link"; +"lng_rights_group_pin" = "Pin messages"; +"lng_rights_delete" = "Delete messages of others"; +"lng_rights_add_admins" = "Add new admins"; +"lng_rights_chat_read" = "Read messages"; +"lng_rights_chat_send_text" = "Send messages"; +"lng_rights_chat_send_media" = "Send media"; +"lng_rights_chat_send_stickers" = "Send stickers & GIFs"; +"lng_rights_chat_send_links" = "Embed links"; +"lng_rights_chat_banned_until" = "Banned until: {when}"; +"lng_rights_chat_banned_forever" = "Forever"; +"lng_rights_chat_banned_block" = "Block and remove from group"; + // Not used "lng_topbar_info" = "Info"; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index ca694f7ea..2545fab24 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -553,16 +553,17 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP auto needBotsInfos = false; auto botStatus = peer->mgInfo->botStatus; auto keyboardBotFound = !h || !h->lastKeyboardFrom; + auto emptyRights = MTP_channelAdminRights(MTP_flags(0)); for_const (auto &participant, v) { auto userId = UserId(0); - bool admin = false; + auto rights = emptyRights; switch (participant.type()) { case mtpc_channelParticipant: userId = participant.c_channelParticipant().vuser_id.v; break; case mtpc_channelParticipantSelf: userId = participant.c_channelParticipantSelf().vuser_id.v; break; - case mtpc_channelParticipantAdmin: userId = participant.c_channelParticipantAdmin().vuser_id.v; admin = true; break; + case mtpc_channelParticipantAdmin: userId = participant.c_channelParticipantAdmin().vuser_id.v; rights = participant.c_channelParticipantAdmin().vadmin_rights; break; case mtpc_channelParticipantBanned: userId = participant.c_channelParticipantBanned().vuser_id.v; break; - case mtpc_channelParticipantCreator: userId = participant.c_channelParticipantCreator().vuser_id.v; admin = true; break; + case mtpc_channelParticipantCreator: userId = participant.c_channelParticipantCreator().vuser_id.v; break; } if (!userId) { continue; @@ -583,7 +584,9 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP } else { if (peer->mgInfo->lastParticipants.indexOf(u) < 0) { peer->mgInfo->lastParticipants.push_back(u); - if (admin) peer->mgInfo->lastAdmins.insert(u); + if (rights.c_channelAdminRights().vflags.v) { + peer->mgInfo->lastAdmins.insert(u, rights); + } if (u->botInfo) { peer->mgInfo->bots.insert(u); if (peer->mgInfo->botStatus != 0 && peer->mgInfo->botStatus < 2) { diff --git a/Telegram/SourceFiles/boxes/contacts_box.cpp b/Telegram/SourceFiles/boxes/contacts_box.cpp index aeadcf90a..5393ea95c 100644 --- a/Telegram/SourceFiles/boxes/contacts_box.cpp +++ b/Telegram/SourceFiles/boxes/contacts_box.cpp @@ -39,6 +39,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/effects/ripple_animation.h" #include "boxes/photo_crop_box.h" #include "boxes/confirm_box.h" +#include "boxes/edit_participant_box.h" #include "window/themes/window_theme.h" #include "observer_peer.h" #include "apiwrap.h" @@ -736,7 +737,7 @@ void ContactsBox::Inner::onAllAdminsChanged() { update(); } -void ContactsBox::Inner::addAdminDone(const MTPUpdates &result, mtpRequestId req) { +void ContactsBox::Inner::addAdminDone(MTPChannelAdminRights rights, const MTPUpdates &result, mtpRequestId req) { if (App::main()) App::main()->sentUpdatesReceived(result); if (req != _addAdminRequestId) return; @@ -747,7 +748,7 @@ void ContactsBox::Inner::addAdminDone(const MTPUpdates &result, mtpRequestId req _channel->mgInfo->lastParticipants.push_front(_addAdmin); update.flags |= Notify::PeerUpdate::Flag::MembersChanged; } - _channel->mgInfo->lastAdmins.insert(_addAdmin); + _channel->mgInfo->lastAdmins.insert(_addAdmin, rights); update.flags |= Notify::PeerUpdate::Flag::AdminsChanged; if (_addAdmin->botInfo) { _channel->mgInfo->bots.insert(_addAdmin); @@ -1412,9 +1413,14 @@ void ContactsBox::Inner::chooseParticipant() { _addAdminRequestId = 0; } if (_addAdminBox) _addAdminBox->deleteLater(); - _addAdminBox = Ui::show(Box(lng_channel_admin_sure(lt_user, _addAdmin->firstName), base::lambda_guarded(this, [this] { + using Right = MTPDchannelAdminRights::Flag; + auto defaultRights = _channel->isMegagroup() + ? (Right::f_change_info | Right::f_delete_messages | Right::f_ban_users | Right::f_invite_users | Right::f_invite_link | Right::f_pin_messages) + : (Right::f_change_info | Right::f_post_messages | Right::f_edit_messages | Right::f_delete_messages); + auto currentRights = (_channel->isMegagroup() ? _channel->mgInfo->lastAdmins : QMap()).value(_addAdmin, MTP_channelAdminRights(MTP_flags(defaultRights))); + _addAdminBox = Ui::show(Box(_channel, _addAdmin, currentRights, base::lambda_guarded(this, [this](const MTPChannelAdminRights &rights) { if (_addAdminRequestId) return; -// _addAdminRequestId = MTP::send(MTPchannels_EditAdmin(_channel->inputChannel, _addAdmin->inputUser, MTP_channelRoleEditor()), rpcDone(&Inner::addAdminDone), rpcFail(&Inner::addAdminFail)); + _addAdminRequestId = MTP::send(MTPchannels_EditAdmin(_channel->inputChannel, _addAdmin->inputUser, rights), rpcDone(&Inner::addAdminDone, rights), rpcFail(&Inner::addAdminFail)); })), KeepOtherLayers); } else if (sharingBotGame()) { _addToPeer = peer; diff --git a/Telegram/SourceFiles/boxes/contacts_box.h b/Telegram/SourceFiles/boxes/contacts_box.h index 31af500f9..572f9eb4a 100644 --- a/Telegram/SourceFiles/boxes/contacts_box.h +++ b/Telegram/SourceFiles/boxes/contacts_box.h @@ -25,6 +25,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/effects/round_checkbox.h" #include "boxes/members_box.h" +class EditAdminBox; + namespace Dialogs { class Row; class IndexedList; @@ -249,7 +251,7 @@ private: void updateSelectedRow(); int getRowTopWithPeer(PeerData *peer) const; void updateRowWithPeer(PeerData *peer); - void addAdminDone(const MTPUpdates &result, mtpRequestId req); + void addAdminDone(MTPChannelAdminRights rights, const MTPUpdates &result, mtpRequestId req); bool addAdminFail(const RPCError &error, mtpRequestId req); void paintDialog(Painter &p, TimeMs ms, PeerData *peer, ContactData *data, bool sel); @@ -293,7 +295,7 @@ private: PeerData *_addToPeer = nullptr; UserData *_addAdmin = nullptr; mtpRequestId _addAdminRequestId = 0; - QPointer _addAdminBox; + QPointer _addAdminBox; int32 _time; diff --git a/Telegram/SourceFiles/boxes/edit_participant_box.cpp b/Telegram/SourceFiles/boxes/edit_participant_box.cpp new file mode 100644 index 000000000..bceef1779 --- /dev/null +++ b/Telegram/SourceFiles/boxes/edit_participant_box.cpp @@ -0,0 +1,129 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +*/ +#include "boxes/edit_participant_box.h" + +#include "lang/lang_keys.h" +#include "ui/widgets/checkbox.h" +#include "ui/widgets/labels.h" +#include "styles/style_boxes.h" + +EditParticipantBox::EditParticipantBox(QWidget*, gsl::not_null channel, gsl::not_null user) : BoxContent() +, _channel(channel) +, _user(user) { +} + +void EditParticipantBox::resizeToContent() { + auto newWidth = st::boxWideWidth; + auto newHeight = 0; + auto rowWidth = newWidth - st::boxPadding.left() - st::boxPadding.right(); + for (auto &&row : _rows) { + row->resizeToNaturalWidth(rowWidth); + newHeight += row->heightNoMargins(); + } + if (!_rows.empty()) { + newHeight += (_rows.size() - 1) * st::boxLittleSkip; + } + setDimensions(st::boxWideWidth, newHeight); +} + +void EditParticipantBox::resizeEvent(QResizeEvent *e) { + auto top = 0; + for (auto &&row : _rows) { + row->moveToLeft(st::boxPadding.left(), top); + top += row->heightNoMargins() + st::boxLittleSkip; + } +} + +void EditParticipantBox::paintEvent(QPaintEvent *e) { + Painter p(this); + + p.fillRect(e->rect(), st::boxBg); +} + +EditAdminBox::EditAdminBox(QWidget*, gsl::not_null channel, gsl::not_null user, const MTPChannelAdminRights &rights, base::lambda callback) : EditParticipantBox(nullptr, channel, user) +, _rights(rights) { +} + +void EditAdminBox::prepare() { + setTitle(langFactory(lng_rights_edit_admin)); + + addControl(object_ptr(this, lang(lng_rights_edit_admin_header), Ui::FlatLabel::InitType::Simple, st::boxLabel)); + + auto addCheckbox = [this](Flag flag, const QString &text) { + auto checked = (_rights.c_channelAdminRights().vflags.v & flag) != 0; + auto control = addControl(object_ptr(this, text, checked, st::defaultBoxCheckbox)); + _checkboxes.emplace(flag, control); + }; + if (channel()->isMegagroup()) { + addCheckbox(Flag::f_change_info, lang(lng_rights_group_info)); + addCheckbox(Flag::f_delete_messages, lang(lng_rights_delete)); + addCheckbox(Flag::f_ban_users, lang(lng_rights_group_ban)); + addCheckbox(Flag::f_invite_users, lang(lng_rights_group_invite)); + addCheckbox(Flag::f_invite_link, lang(lng_rights_group_invite_link)); + addCheckbox(Flag::f_pin_messages, lang(lng_rights_group_pin)); + addCheckbox(Flag::f_add_admins, lang(lng_rights_add_admins)); + } else { + addCheckbox(Flag::f_change_info, lang(lng_rights_channel_info)); + addCheckbox(Flag::f_post_messages, lang(lng_rights_channel_post)); + addCheckbox(Flag::f_edit_messages, lang(lng_rights_channel_edit)); + addCheckbox(Flag::f_delete_messages, lang(lng_rights_delete)); + addCheckbox(Flag::f_add_admins, lang(lng_rights_add_admins)); + } + + _aboutAddAdmins = addControl(object_ptr(this, st::boxLabel)); + auto addAdmins = _checkboxes.find(Flag::f_add_admins); + t_assert(addAdmins != _checkboxes.end()); + connect(addAdmins->second, &Ui::Checkbox::changed, this, [this] { + refreshAboutAddAdminsText(); + }); + refreshAboutAddAdminsText(); + + resizeToContent(); +} + +void EditAdminBox::refreshAboutAddAdminsText() { + auto addAdmins = _checkboxes.find(Flag::f_add_admins); + t_assert(addAdmins != _checkboxes.end()); + _aboutAddAdmins->setText(lang(addAdmins->second->checked() ? lng_rights_about_add_admins_yes : lng_rights_about_add_admins_no)); + + resizeToContent(); +} + +EditRestrictedBox::EditRestrictedBox(QWidget*, gsl::not_null channel, gsl::not_null user, const MTPChannelBannedRights &rights, base::lambda callback) : EditParticipantBox(nullptr, channel, user) { +} + +void EditRestrictedBox::prepare() { + setTitle(langFactory(lng_rights_user_restrictions)); + + addControl(object_ptr(this, lang(lng_rights_edit_admin_header), Ui::FlatLabel::InitType::Simple, st::boxLabel)); + + auto addCheckbox = [this](Flag flag, const QString &text) { + auto checked = (_rights.c_channelBannedRights().vflags.v & flag) != 0; + auto control = addControl(object_ptr(this, text, checked, st::defaultBoxCheckbox)); + _checkboxes.emplace(flag, control); + }; + addCheckbox(Flag::f_view_messages, lang(lng_rights_chat_read)); + addCheckbox(Flag::f_send_messages, lang(lng_rights_chat_send_text)); + addCheckbox(Flag::f_send_media, lang(lng_rights_chat_send_media)); + addCheckbox(Flag::f_send_stickers, lang(lng_rights_chat_send_stickers)); + addCheckbox(Flag::f_embed_links, lang(lng_rights_chat_send_links)); + resizeToContent(); +} diff --git a/Telegram/SourceFiles/boxes/edit_participant_box.h b/Telegram/SourceFiles/boxes/edit_participant_box.h new file mode 100644 index 000000000..9b450888f --- /dev/null +++ b/Telegram/SourceFiles/boxes/edit_participant_box.h @@ -0,0 +1,95 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +*/ +#pragma once + +#include "boxes/abstract_box.h" + +namespace Ui { +class FlatLabel; +class LinkButton; +class Checkbox; +} // namespace Ui + +class EditParticipantBox : public BoxContent { +public: + EditParticipantBox(QWidget*, gsl::not_null channel, gsl::not_null user); + +protected: + void resizeToContent(); + + void resizeEvent(QResizeEvent *e) override; + void paintEvent(QPaintEvent *e) override; + + gsl::not_null user() const { + return _user; + } + gsl::not_null channel() const { + return _channel; + } + + template + QPointer addControl(object_ptr row) { + _rows.push_back(std::move(row)); + return static_cast(_rows.back().data()); + } + +private: + gsl::not_null _user; + gsl::not_null _channel; + + std::vector> _rows; + +}; + +class EditAdminBox : public EditParticipantBox { +public: + EditAdminBox(QWidget*, gsl::not_null channel, gsl::not_null user, const MTPChannelAdminRights &rights, base::lambda callback); + +protected: + void prepare() override; + +private: + using Flag = MTPDchannelAdminRights::Flag; + + void refreshAboutAddAdminsText(); + + MTPChannelAdminRights _rights; + + std::map> _checkboxes; + QPointer _aboutAddAdmins; + +}; + +class EditRestrictedBox : public EditParticipantBox { +public: + EditRestrictedBox(QWidget*, gsl::not_null channel, gsl::not_null user, const MTPChannelBannedRights &rights, base::lambda callback); + +protected: + void prepare() override; + +private: + using Flag = MTPDchannelBannedRights::Flag; + + MTPChannelBannedRights _rights; + + std::map> _checkboxes; + +}; diff --git a/Telegram/SourceFiles/boxes/members_box.cpp b/Telegram/SourceFiles/boxes/members_box.cpp index fb887b1d9..e0381f444 100644 --- a/Telegram/SourceFiles/boxes/members_box.cpp +++ b/Telegram/SourceFiles/boxes/members_box.cpp @@ -535,9 +535,11 @@ void MembersBox::Inner::membersReceived(const MTPchannels_ChannelParticipants &r } App::feedUsers(d.vusers); + auto emptyRights = MTP_channelAdminRights(MTP_flags(0)); for (QVector::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) { int32 userId = 0, addedTime = 0; - MemberRole role = MemberRole::None; + auto role = MemberRole::None; + auto rights = emptyRights; switch (i->type()) { case mtpc_channelParticipant: userId = i->c_channelParticipant().vuser_id.v; @@ -552,6 +554,7 @@ void MembersBox::Inner::membersReceived(const MTPchannels_ChannelParticipants &r role = MemberRole::Admin; userId = i->c_channelParticipantAdmin().vuser_id.v; addedTime = i->c_channelParticipantAdmin().vdate.v; + rights = i->c_channelParticipantAdmin().vadmin_rights; break; case mtpc_channelParticipantCreator: userId = i->c_channelParticipantCreator().vuser_id.v; @@ -567,7 +570,8 @@ void MembersBox::Inner::membersReceived(const MTPchannels_ChannelParticipants &r _rows.push_back(user); _dates.push_back(date(addedTime)); _roles.push_back(role); - _datas.push_back(0); + _adminRights.push_back(rights); + _datas.push_back(nullptr); } } @@ -575,8 +579,8 @@ void MembersBox::Inner::membersReceived(const MTPchannels_ChannelParticipants &r if (_filter == MembersFilter::Admins && _channel->isMegagroup() && _rows.size() < Global::ChatSizeMax()) { _channel->mgInfo->lastAdmins.clear(); for (int32 i = 0, l = _rows.size(); i != l; ++i) { - if (_roles.at(i) == MemberRole::Creator || _roles.at(i) == MemberRole::Admin) { - _channel->mgInfo->lastAdmins.insert(_rows.at(i)); + if (_roles[i] == MemberRole::Admin) { + _channel->mgInfo->lastAdmins.insert(_rows[i], _adminRights[i]); } } @@ -587,7 +591,7 @@ void MembersBox::Inner::membersReceived(const MTPchannels_ChannelParticipants &r _rows.push_back(App::self()); _dates.push_back(date(MTP_int(_channel->date))); _roles.push_back(MemberRole::Self); - _datas.push_back(0); + _datas.push_back(nullptr); } clearSel(); diff --git a/Telegram/SourceFiles/boxes/members_box.h b/Telegram/SourceFiles/boxes/members_box.h index 5cd5e47a8..359b6cbaa 100644 --- a/Telegram/SourceFiles/boxes/members_box.h +++ b/Telegram/SourceFiles/boxes/members_box.h @@ -194,14 +194,11 @@ private: bool _loading = true; mtpRequestId _loadingRequestId = 0; - typedef QVector MemberRows; - typedef QVector MemberDates; - typedef QVector MemberRoles; - typedef QVector MemberDatas; - MemberRows _rows; - MemberDates _dates; - MemberRoles _roles; - MemberDatas _datas; + QVector _rows; + QVector _dates; + QVector _roles; + QVector _adminRights; + QVector _datas; int _aboutWidth = 0; Text _about; diff --git a/Telegram/SourceFiles/profile/profile_block_group_members.cpp b/Telegram/SourceFiles/profile/profile_block_group_members.cpp index f2581a947..f86d690af 100644 --- a/Telegram/SourceFiles/profile/profile_block_group_members.cpp +++ b/Telegram/SourceFiles/profile/profile_block_group_members.cpp @@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "styles/style_profile.h" #include "ui/widgets/labels.h" #include "boxes/confirm_box.h" +#include "boxes/edit_participant_box.h" #include "ui/widgets/popup_menu.h" #include "mainwidget.h" #include "apiwrap.h" @@ -66,42 +67,40 @@ GroupMembersWidget::GroupMembersWidget(QWidget *parent, PeerData *peer, TitleVis refreshMembers(); } -void GroupMembersWidget::addAdmin(PeerData *selectedPeer) { - auto user = selectedPeer->asUser(); - auto text = lng_channel_admin_sure(lt_user, user->firstName); - Ui::show(Box(text, base::lambda_guarded(this, [this, user] { +void GroupMembersWidget::addAdmin(gsl::not_null user) { + auto megagroup = peer()->asMegagroup(); + if (!megagroup) { + return; // not supported + } + auto currentRights = megagroup->mgInfo->lastAdmins.value(user, MTP_channelAdminRights(MTP_flags(0))); + Ui::show(Box(megagroup, user, currentRights, base::lambda_guarded(this, [this, megagroup, user](const MTPChannelAdminRights &rights) { Ui::hideLayer(); - if (auto chat = peer()->asChat()) { - // not supported - } else if (auto channel = peer()->asMegagroup()) { - //MTP::send(MTPchannels_EditAdmin(channel->inputChannel, user->inputUser, MTP_channelRoleEditor()), rpcDone(base::lambda_guarded(this, [this, channel, user](const MTPUpdates &result) { - // if (App::main()) App::main()->sentUpdatesReceived(result); - // channel->mgInfo->lastAdmins.insert(user); - // channel->setAdminsCount(channel->adminsCount() + 1); - // if (App::main()) emit App::main()->peerUpdated(channel); - // Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::AdminsChanged); - //}))); - } + MTP::send(MTPchannels_EditAdmin(megagroup->inputChannel, user->inputUser, rights), rpcDone(base::lambda_guarded(this, [this, megagroup, user, rights](const MTPUpdates &result) { + if (App::main()) App::main()->sentUpdatesReceived(result); + megagroup->mgInfo->lastAdmins.insert(user, rights); + megagroup->setAdminsCount(megagroup->adminsCount() + 1); + if (App::main()) emit App::main()->peerUpdated(megagroup); + Notify::peerUpdatedDelayed(megagroup, Notify::PeerUpdate::Flag::AdminsChanged); + }))); }))); } -void GroupMembersWidget::removeAdmin(PeerData *selectedPeer) { - auto user = selectedPeer->asUser(); +void GroupMembersWidget::removeAdmin(gsl::not_null user) { auto text = lng_profile_sure_kick_admin(lt_user, user->firstName); Ui::show(Box(text, lang(lng_box_remove), base::lambda_guarded(this, [this, user] { Ui::hideLayer(); if (auto chat = peer()->asChat()) { // not supported } else if (auto channel = peer()->asMegagroup()) { - //MTP::send(MTPchannels_EditAdmin(channel->inputChannel, user->inputUser, MTP_channelRoleEmpty()), rpcDone(base::lambda_guarded(this, [this, channel, user](const MTPUpdates &result) { - // if (App::main()) App::main()->sentUpdatesReceived(result); - // channel->mgInfo->lastAdmins.remove(user); - // if (channel->adminsCount() > 1) { - // channel->setAdminsCount(channel->adminsCount() - 1); - // if (App::main()) emit App::main()->peerUpdated(channel); - // } - // Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::AdminsChanged); - //}))); + MTP::send(MTPchannels_EditAdmin(channel->inputChannel, user->inputUser, MTP_channelAdminRights(MTP_flags(0))), rpcDone(base::lambda_guarded(this, [this, channel, user](const MTPUpdates &result) { + if (App::main()) App::main()->sentUpdatesReceived(result); + channel->mgInfo->lastAdmins.remove(user); + if (channel->adminsCount() > 1) { + channel->setAdminsCount(channel->adminsCount() - 1); + if (App::main()) emit App::main()->peerUpdated(channel); + } + Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::AdminsChanged); + }))); } }))); } @@ -198,9 +197,11 @@ void GroupMembersWidget::paintContents(Painter &p) { } Ui::PopupMenu *GroupMembersWidget::fillPeerMenu(PeerData *selectedPeer) { + Expects(selectedPeer->isUser()); if (emptyTitle()) { return nullptr; } + auto user = selectedPeer->asUser(); auto result = new Ui::PopupMenu(nullptr); result->addAction(lang(lng_context_view_profile), [selectedPeer] { Ui::showPeerProfile(selectedPeer); @@ -222,12 +223,12 @@ Ui::PopupMenu *GroupMembersWidget::fillPeerMenu(PeerData *selectedPeer) { return false; }; if (channel && channel->amCreator() && !item->hasAdminStar) { - result->addAction(lang(lng_context_promote_admin), base::lambda_guarded(this, [this, selectedPeer] { - addAdmin(selectedPeer); + result->addAction(lang(lng_context_promote_admin), base::lambda_guarded(this, [this, user] { + addAdmin(user); })); } else if (canRemoveAdmin()) { - result->addAction(lang(lng_context_remove_admin), base::lambda_guarded(this, [this, selectedPeer] { - removeAdmin(selectedPeer); + result->addAction(lang(lng_context_remove_admin), base::lambda_guarded(this, [this, user] { + removeAdmin(user); })); } if (item->hasRemoveLink) { @@ -326,12 +327,12 @@ void GroupMembersWidget::checkSelfAdmin(ChatData *chat) { void GroupMembersWidget::checkSelfAdmin(ChannelData *megagroup) { if (megagroup->mgInfo->lastParticipants.isEmpty()) return; - auto amAdmin = megagroup->hasAdminRights() || megagroup->amCreator(); + auto amAdmin = megagroup->hasAdminRights(); auto self = App::self(); if (amAdmin && !megagroup->mgInfo->lastAdmins.contains(self)) { - megagroup->mgInfo->lastAdmins.insert(self); + megagroup->selfAdminUpdated(); } else if (!amAdmin && megagroup->mgInfo->lastAdmins.contains(self)) { - megagroup->mgInfo->lastAdmins.remove(self); + megagroup->selfAdminUpdated(); } } diff --git a/Telegram/SourceFiles/profile/profile_block_group_members.h b/Telegram/SourceFiles/profile/profile_block_group_members.h index d27db54c1..b2cd1d90e 100644 --- a/Telegram/SourceFiles/profile/profile_block_group_members.h +++ b/Telegram/SourceFiles/profile/profile_block_group_members.h @@ -67,8 +67,8 @@ private: // Observed notifications. void notifyPeerUpdated(const Notify::PeerUpdate &update); - void addAdmin(PeerData *selectedPeer); - void removeAdmin(PeerData *selectedPeer); + void addAdmin(gsl::not_null user); + void removeAdmin(gsl::not_null user); void removePeer(PeerData *selectedPeer); void refreshMembers(); void fillChatMembers(ChatData *chat); diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 0050b89e3..702ccddf2 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -768,8 +768,8 @@ void ChannelData::flagsUpdated() { void ChannelData::selfAdminUpdated() { if (isMegagroup()) { - if (amEditor()) { - mgInfo->lastAdmins.insert(App::self()); + if (hasAdminRights()) { + mgInfo->lastAdmins.insert(App::self(), _adminRights); } else { mgInfo->lastAdmins.remove(App::self()); } diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index cd3456b07..a48b579e7 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -707,8 +707,7 @@ private: struct MegagroupInfo { typedef QList LastParticipants; LastParticipants lastParticipants; - typedef OrderedSet LastAdmins; - LastAdmins lastAdmins; + QMap lastAdmins; typedef OrderedSet MarkupSenders; MarkupSenders markupSenders; typedef OrderedSet Bots; diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index c7177ecda..47f841b44 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -46,6 +46,8 @@ <(src_loc)/boxes/download_path_box.h <(src_loc)/boxes/edit_color_box.cpp <(src_loc)/boxes/edit_color_box.h +<(src_loc)/boxes/edit_participant_box.cpp +<(src_loc)/boxes/edit_participant_box.h <(src_loc)/boxes/edit_privacy_box.cpp <(src_loc)/boxes/edit_privacy_box.h <(src_loc)/boxes/emoji_box.cpp