Edit admin and restricted rights in channels.

This commit is contained in:
John Preston 2017-06-09 18:12:02 +02:00
parent 513a9f8d45
commit 7d2d5c6100
26 changed files with 1138 additions and 590 deletions

View File

@ -140,6 +140,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_error_pinned_max#one" = "Sorry, you can pin no more than {count} chat to the top.";
"lng_error_pinned_max#other" = "Sorry, you can pin no more than {count} chats to the top.";
"lng_error_public_groups_denied" = "Unfortunately, you were banned from participating in public groups.\n{more_info}";
"lng_error_cant_edit_admin" = "Sorry, you can't edit permissions for this admin.";
"lng_error_cant_add_member" = "Sorry, you can't add the bot to this group.";
"lng_edit_deleted" = "This message was deleted";
"lng_edit_too_long" = "Your message text is too long";
@ -577,6 +579,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_profile_delete_and_exit" = "Leave";
"lng_profile_kick" = "Remove";
"lng_profile_admin" = "admin";
"lng_profile_edit_admin" = "Edit";
"lng_profile_sure_kick" = "Remove {user} from the group?";
"lng_profile_sure_kick_channel" = "Remove {user} from the channel?";
"lng_profile_sure_kick_admin" = "Remove {user} from administrators?";
@ -993,7 +996,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_context_unpin_from_top" = "Unpin from top";
"lng_context_promote_admin" = "Promote to admin";
"lng_context_remove_admin" = "Remove from admins";
"lng_context_edit_permissions" = "Edit permissions";
"lng_context_restrict_user" = "Restrict user";
"lng_context_remove_from_group" = "Remove from group";
"lng_context_copy_link" = "Copy Link";
@ -1246,7 +1250,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"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_yes" = "This admin will be able to add new admins with the same (or more limited) permissions.";
"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?";
@ -1254,12 +1258,13 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_rights_channel_info" = "Change channel info";
"lng_rights_channel_post" = "Post messages";
"lng_rights_channel_edit" = "Edit messages of others";
"lng_rights_channel_delete" = "Delete 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_invite_link" = "Invite users via link";
"lng_rights_group_pin" = "Pin messages";
"lng_rights_delete" = "Delete messages of others";
"lng_rights_group_delete" = "Delete messages";
"lng_rights_add_admins" = "Add new admins";
"lng_rights_chat_read" = "Read messages";
"lng_rights_chat_send_text" = "Send messages";

View File

@ -317,6 +317,7 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt
channel->setAbout(qs(f.vabout));
channel->setMembersCount(f.has_participants_count() ? f.vparticipants_count.v : 0);
channel->setAdminsCount(f.has_admins_count() ? f.vadmins_count.v : 0);
channel->setRestrictedCount(f.has_banned_count() ? f.vbanned_count.v : 0);
channel->setKickedCount(f.has_kicked_count() ? f.vkicked_count.v : 0);
channel->setInviteLink((f.vexported_invite.type() == mtpc_chatInviteExported) ? qs(f.vexported_invite.c_chatInviteExported().vlink) : QString());
if (auto h = App::historyLoaded(channel->id)) {
@ -335,8 +336,8 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt
}
channel->fullUpdated();
if (canViewAdmins != channel->canViewAdmins()) Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::ChannelCanViewAdmins);
if (canViewMembers != channel->canViewMembers()) Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::ChannelCanViewMembers);
if (canViewAdmins != channel->canViewAdmins()
|| canViewMembers != channel->canViewMembers()) Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::ChannelRightsChanged);
notifySettingReceived(MTP_inputNotifyPeer(peer->input), f.vnotify_settings);
}
@ -553,16 +554,26 @@ 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));
auto emptyAdminRights = MTP_channelAdminRights(MTP_flags(0));
auto emptyRestrictedRights = MTP_channelBannedRights(MTP_flags(0), MTP_int(0));
for_const (auto &participant, v) {
auto userId = UserId(0);
auto rights = emptyRights;
auto adminCanEdit = false;
auto adminRights = emptyAdminRights;
auto restrictedRights = emptyRestrictedRights;
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; rights = participant.c_channelParticipantAdmin().vadmin_rights; break;
case mtpc_channelParticipantBanned: userId = participant.c_channelParticipantBanned().vuser_id.v; break;
case mtpc_channelParticipantAdmin:
userId = participant.c_channelParticipantAdmin().vuser_id.v;
adminCanEdit = participant.c_channelParticipantAdmin().is_can_edit();
adminRights = participant.c_channelParticipantAdmin().vadmin_rights;
break;
case mtpc_channelParticipantBanned:
userId = participant.c_channelParticipantBanned().vuser_id.v;
restrictedRights = participant.c_channelParticipantBanned().vbanned_rights;
break;
case mtpc_channelParticipantCreator: userId = participant.c_channelParticipantCreator().vuser_id.v; break;
}
if (!userId) {
@ -570,6 +581,9 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP
}
auto u = App::user(userId);
if (participant.type() == mtpc_channelParticipantCreator) {
peer->mgInfo->creator = u;
}
if (bots) {
if (u->botInfo) {
peer->mgInfo->bots.insert(u);
@ -584,8 +598,10 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP
} else {
if (peer->mgInfo->lastParticipants.indexOf(u) < 0) {
peer->mgInfo->lastParticipants.push_back(u);
if (rights.c_channelAdminRights().vflags.v) {
peer->mgInfo->lastAdmins.insert(u, rights);
if (adminRights.c_channelAdminRights().vflags.v) {
peer->mgInfo->lastAdmins.insert(u, MegagroupInfo::Admin { adminRights, adminCanEdit });
} else if (restrictedRights.c_channelBannedRights().vflags.v != 0) {
peer->mgInfo->lastRestricted.insert(u, MegagroupInfo::Restricted { restrictedRights });
}
if (u->botInfo) {
peer->mgInfo->bots.insert(u);
@ -647,6 +663,9 @@ void ApiWrap::requestSelfParticipant(ChannelData *channel) {
auto &d = p.vparticipant.c_channelParticipantCreator();
channel->inviter = _session->userId();
channel->inviteDate = date(MTP_int(channel->date));
if (channel->mgInfo) {
channel->mgInfo->creator = App::self();
}
} break;
case mtpc_channelParticipantAdmin: {
auto &d = p.vparticipant.c_channelParticipantAdmin();
@ -671,44 +690,17 @@ void ApiWrap::kickParticipant(PeerData *peer, UserData *user) {
if (_kickRequests.contains(kick)) return;
if (auto channel = peer->asChannel()) {
//auto requestId = request(MTPchannels_KickFromChannel(channel->inputChannel, user->inputUser, MTP_bool(true))).done([this, peer, user](const MTPUpdates &result) {
// applyUpdates(result);
auto rights = ChannelData::KickedRestrictedRights();
auto requestId = request(MTPchannels_EditBanned(channel->inputChannel, user->inputUser, rights)).done([this, channel, user, rights](const MTPUpdates &result) {
applyUpdates(result);
// _kickRequests.remove(KickRequest(peer, user));
// if (auto channel = peer->asMegagroup()) {
// auto megagroupInfo = channel->mgInfo;
_kickRequests.remove(KickRequest(channel, user));
channel->applyEditBanned(user, rights);
}).fail([this, kick](const RPCError &error) {
_kickRequests.remove(kick);
}).send();
// auto i = megagroupInfo->lastParticipants.indexOf(user);
// if (i >= 0) {
// megagroupInfo->lastParticipants.removeAt(i);
// }
// if (channel->membersCount() > 1) {
// channel->setMembersCount(channel->membersCount() - 1);
// } else {
// megagroupInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsCountOutdated;
// megagroupInfo->lastParticipantsCount = 0;
// }
// channel->setKickedCount(channel->kickedCount() + 1);
// if (megagroupInfo->lastAdmins.contains(user)) {
// megagroupInfo->lastAdmins.remove(user);
// if (channel->adminsCount() > 1) {
// channel->setAdminsCount(channel->adminsCount() - 1);
// }
// Notify::peerUpdatedDelayed(channel, Notify::PeerUpdate::Flag::AdminsChanged);
// }
// megagroupInfo->bots.remove(user);
// if (megagroupInfo->bots.isEmpty() && megagroupInfo->botStatus > 0) {
// megagroupInfo->botStatus = -1;
// }
// }
// Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::MembersChanged);
// fullPeerUpdated().notify(peer);
//}).fail([this, kick](const RPCError &error) {
// _kickRequests.remove(kick);
//}).send();
//_kickRequests.insert(kick, requestId);
_kickRequests.insert(kick, requestId);
}
}
@ -717,22 +709,22 @@ void ApiWrap::unblockParticipant(PeerData *peer, UserData *user) {
if (_kickRequests.contains(kick)) return;
if (auto channel = peer->asChannel()) {
//auto requestId = request(MTPchannels_KickFromChannel(channel->inputChannel, user->inputUser, MTP_bool(false))).done([this, peer, user](const MTPUpdates &result) {
// applyUpdates(result);
auto requestId = request(MTPchannels_EditBanned(channel->inputChannel, user->inputUser, MTP_channelBannedRights(MTP_flags(0), MTP_int(0)))).done([this, peer, user](const MTPUpdates &result) {
applyUpdates(result);
// _kickRequests.remove(KickRequest(peer, user));
// if (auto channel = peer->asMegagroup()) {
// if (channel->kickedCount() > 0) {
// channel->setKickedCount(channel->kickedCount() - 1);
// } else {
// channel->updateFull(true);
// }
// }
//}).fail([this, kick](const RPCError &error) {
// _kickRequests.remove(kick);
//}).send();
_kickRequests.remove(KickRequest(peer, user));
if (auto channel = peer->asMegagroup()) {
if (channel->kickedCount() > 0) {
channel->setKickedCount(channel->kickedCount() - 1);
} else {
channel->updateFull(true);
}
}
}).fail([this, kick](const RPCError &error) {
_kickRequests.remove(kick);
}).send();
//_kickRequests.insert(kick, requestId);
_kickRequests.insert(kick, requestId);
}
}

View File

@ -681,11 +681,9 @@ namespace {
auto cdata = data->asChannel();
auto wasInChannel = cdata->amIn();
auto canEditInformation = cdata->canEditInformation();
auto canViewAdmins = cdata->canViewAdmins();
auto canViewMembers = cdata->canViewMembers();
auto canAddMembers = cdata->canAddMembers();
auto wasEditor = cdata->amEditor();
if (minimal) {
auto mask = MTPDchannel::Flag::f_broadcast | MTPDchannel::Flag::f_verified | MTPDchannel::Flag::f_megagroup | MTPDchannel::Flag::f_democracy;
@ -694,8 +692,8 @@ namespace {
if (d.has_admin_rights() || cdata->hasAdminRights()) {
cdata->setAdminRights(d.has_admin_rights() ? d.vadmin_rights : MTP_channelAdminRights(MTP_flags(0)));
}
if (d.has_banned_rights() || cdata->hasBannedRights()) {
cdata->setBannedRights(d.has_banned_rights() ? d.vbanned_rights : MTP_channelBannedRights(MTP_flags(0), MTP_int(0)));
if (d.has_banned_rights() || cdata->hasRestrictedRights()) {
cdata->setRestrictedRights(d.has_banned_rights() ? d.vbanned_rights : MTP_channelBannedRights(MTP_flags(0), MTP_int(0)));
}
cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash);
cdata->access = d.vaccess_hash.v;
@ -719,14 +717,9 @@ namespace {
cdata->setPhoto(d.vphoto);
if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn;
if (canEditInformation != cdata->canEditInformation()) update.flags |= UpdateFlag::ChannelCanEditInformation;
if (canViewAdmins != cdata->canViewAdmins()) update.flags |= UpdateFlag::ChannelCanViewAdmins;
if (canViewMembers != cdata->canViewMembers()) update.flags |= UpdateFlag::ChannelCanViewMembers;
if (canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelCanAddMembers;
if (wasEditor != cdata->amEditor()) {
cdata->selfAdminUpdated();
update.flags |= (UpdateFlag::ChannelAmEditor | UpdateFlag::AdminsChanged);
}
if (canViewAdmins != cdata->canViewAdmins()
|| canViewMembers != cdata->canViewMembers()
|| canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelRightsChanged;
} break;
case mtpc_channelForbidden: {
auto &d(chat.c_channelForbidden());
@ -737,11 +730,9 @@ namespace {
auto cdata = data->asChannel();
auto wasInChannel = cdata->amIn();
auto canEditInformation = cdata->canEditInformation();
auto canViewAdmins = cdata->canViewAdmins();
auto canViewMembers = cdata->canViewMembers();
auto canAddMembers = cdata->canAddMembers();
auto wasEditor = cdata->amEditor();
cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash);
@ -752,8 +743,8 @@ namespace {
if (cdata->hasAdminRights()) {
cdata->setAdminRights(MTP_channelAdminRights(MTP_flags(0)));
}
if (cdata->hasBannedRights()) {
cdata->setBannedRights(MTP_channelBannedRights(MTP_flags(0), MTP_int(0)));
if (cdata->hasRestrictedRights()) {
cdata->setRestrictedRights(MTP_channelBannedRights(MTP_flags(0), MTP_int(0)));
}
cdata->setName(qs(d.vtitle), QString());
@ -765,14 +756,9 @@ namespace {
cdata->setIsForbidden(true);
if (wasInChannel != cdata->amIn()) update.flags |= UpdateFlag::ChannelAmIn;
if (canEditInformation != cdata->canEditInformation()) update.flags |= UpdateFlag::ChannelCanEditInformation;
if (canViewAdmins != cdata->canViewAdmins()) update.flags |= UpdateFlag::ChannelCanViewAdmins;
if (canViewMembers != cdata->canViewMembers()) update.flags |= UpdateFlag::ChannelCanViewMembers;
if (canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelCanAddMembers;
if (wasEditor != cdata->amEditor()) {
cdata->selfAdminUpdated();
update.flags |= (UpdateFlag::ChannelAmEditor | UpdateFlag::AdminsChanged);
}
if (canViewAdmins != cdata->canViewAdmins()
|| canViewMembers != cdata->canViewMembers()
|| canAddMembers != cdata->canAddMembers()) update.flags |= UpdateFlag::ChannelRightsChanged;
} break;
}
if (!data) {
@ -825,10 +811,10 @@ namespace {
auto &v = d.vparticipants.v;
chat->count = v.size();
int32 pversion = chat->participants.isEmpty() ? 1 : (chat->participants.begin().value() + 1);
chat->invitedByMe = ChatData::InvitedByMe();
chat->admins = ChatData::Admins();
chat->invitedByMe.clear();
chat->admins.clear();
chat->flags &= ~MTPDchat::Flag::f_admin;
for (QVector<MTPChatParticipant>::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) {
for (auto i = v.cbegin(), e = v.cend(); i != e; ++i) {
int32 uid = 0, inviter = 0;
switch (i->type()) {
case mtpc_chatParticipantCreator: {
@ -870,7 +856,7 @@ namespace {
History *h = App::historyLoaded(chat->id);
bool found = !h || !h->lastKeyboardFrom;
int32 botStatus = -1;
for (ChatData::Participants::iterator i = chat->participants.begin(), e = chat->participants.end(); i != e;) {
for (auto i = chat->participants.begin(), e = chat->participants.end(); i != e;) {
if (i.value() < pversion) {
i = chat->participants.erase(i);
} else {
@ -976,7 +962,7 @@ namespace {
chat->count--;
}
} else {
ChatData::Participants::iterator i = chat->participants.find(user);
auto i = chat->participants.find(user);
if (i != chat->participants.end()) {
chat->participants.erase(i);
chat->count--;
@ -993,7 +979,7 @@ namespace {
}
if (chat->botStatus > 0 && user->botInfo) {
int32 botStatus = -1;
for (ChatData::Participants::const_iterator j = chat->participants.cbegin(), e = chat->participants.cend(); j != e; ++j) {
for (auto j = chat->participants.cbegin(), e = chat->participants.cend(); j != e; ++j) {
if (j.key()->botInfo) {
if (true || botStatus > 0/* || !j.key()->botInfo->readsAllHistory*/) {
botStatus = 2;

View File

@ -938,7 +938,7 @@ void EditChannelBox::prepare() {
connect(_publicLink, SIGNAL(clicked()), this, SLOT(onPublicLink()));
_publicLink->setVisible(_channel->canEditUsername());
_sign->setVisible(!_channel->isMegagroup());
_sign->setVisible(canEditSignatures());
updateMaxHeight();
}
@ -969,10 +969,14 @@ void EditChannelBox::onDescriptionResized() {
update();
}
bool EditChannelBox::canEditSignatures() const {
return _channel->amCreator() && !_channel->isMegagroup();
}
void EditChannelBox::updateMaxHeight() {
auto newHeight = st::newGroupInfoPadding.top() + _title->height();
newHeight += st::newGroupDescriptionPadding.top() + _description->height() + st::newGroupDescriptionPadding.bottom();
if (!_channel->isMegagroup()) {
if (canEditSignatures()) {
newHeight += st::newGroupPublicLinkPadding.top() + _sign->heightNoMargins() + st::newGroupPublicLinkPadding.bottom();
}
if (_channel->canEditUsername()) {
@ -993,10 +997,10 @@ void EditChannelBox::resizeEvent(QResizeEvent *e) {
_sign->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description->y() + _description->height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
if (_channel->isMegagroup()) {
_publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description->y() + _description->height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
} else {
if (canEditSignatures()) {
_publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _sign->bottomNoMargins() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
} else {
_publicLink->moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description->y() + _description->height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top());
}
}
@ -1031,7 +1035,7 @@ void EditChannelBox::saveDescription() {
}
void EditChannelBox::saveSign() {
if (_channel->isMegagroup() || _channel->addsSignature() == _sign->checked()) {
if (!canEditSignatures() || _channel->addsSignature() == _sign->checked()) {
closeBox();
} else {
_saveSignRequestId = MTP::send(MTPchannels_ToggleSignatures(_channel->inputChannel, MTP_bool(_sign->checked())), rpcDone(&EditChannelBox::onSaveSignDone), rpcFail(&EditChannelBox::onSaveFail));

View File

@ -255,6 +255,7 @@ private slots:
private:
void updateMaxHeight();
bool canEditSignatures() const;
void onSaveTitleDone(const MTPUpdates &updates);
void onSaveDescriptionDone(const MTPBool &result);

View File

@ -532,7 +532,7 @@ void DeleteMessagesBox::deleteAndClear() {
if (_moderateFrom) {
if (_banUser && _banUser->checked()) {
// MTP::send(MTPchannels_KickFromChannel(_moderateInChannel->inputChannel, _moderateFrom->inputUser, MTP_boolTrue()), App::main()->rpcDone(&MainWidget::sentUpdatesReceived));
App::api()->kickParticipant(_moderateInChannel, _moderateFrom);
}
if (_reportSpam->checked()) {
MTP::send(MTPchannels_ReportSpam(_moderateInChannel->inputChannel, _moderateFrom->inputUser, MTP_vector<MTPint>(1, MTP_int(_ids[0].msg))));

View File

@ -344,8 +344,8 @@ void ContactsBox::onPeerSelectedChanged(PeerData *peer, bool checked) {
}
void ContactsBox::inviteParticipants() {
QVector<UserData*> users(_inner->selected());
if (users.isEmpty()) {
auto users = _inner->selected();
if (users.empty()) {
_select->entity()->setInnerFocus();
return;
}
@ -363,7 +363,7 @@ void ContactsBox::createGroup() {
if (_saveRequestId) return;
auto users = _inner->selectedInputs();
if (users.isEmpty() || (users.size() == 1 && users.at(0).type() == mtpc_inputUserSelf)) {
if (users.empty() || (users.size() == 1 && users.at(0).type() == mtpc_inputUserSelf)) {
_select->entity()->setInnerFocus();
return;
}
@ -396,15 +396,16 @@ void ContactsBox::getAdminsDone(const MTPmessages_ChatFull &result) {
closeBox();
return;
}
ChatData::Admins curadmins = _inner->chat()->admins;
QVector<UserData*> newadmins = _inner->selected(), appoint;
if (!newadmins.isEmpty()) {
auto curadmins = _inner->chat()->admins;
auto newadmins = _inner->selected();
auto appoint = decltype(newadmins)();
if (!newadmins.empty()) {
appoint.reserve(newadmins.size());
for (int32 i = 0, l = newadmins.size(); i < l; ++i) {
ChatData::Admins::iterator c = curadmins.find(newadmins.at(i));
for (auto &user : newadmins) {
auto c = curadmins.find(user);
if (c == curadmins.cend()) {
if (newadmins.at(i)->id != peerFromUser(_inner->chat()->creator)) {
appoint.push_back(newadmins.at(i));
if (user->id != peerFromUser(_inner->chat()->creator)) {
appoint.push_back(user);
}
} else {
curadmins.erase(c);
@ -413,10 +414,10 @@ void ContactsBox::getAdminsDone(const MTPmessages_ChatFull &result) {
}
_saveRequestId = 0;
for_const (UserData *user, curadmins) {
for_const (auto user, curadmins) {
MTP::send(MTPmessages_EditChatAdmin(_inner->chat()->inputChat, user->inputUser, MTP_boolFalse()), rpcDone(&ContactsBox::removeAdminDone, user), rpcFail(&ContactsBox::editAdminFail), 0, 10);
}
for_const (UserData *user, appoint) {
for_const (auto user, appoint) {
MTP::send(MTPmessages_EditChatAdmin(_inner->chat()->inputChat, user->inputUser, MTP_boolTrue()), rpcDone(&ContactsBox::setAdminDone, user), rpcFail(&ContactsBox::editAdminFail), 0, 10);
}
MTP::sendAnything();
@ -427,7 +428,7 @@ void ContactsBox::getAdminsDone(const MTPmessages_ChatFull &result) {
}
}
void ContactsBox::setAdminDone(UserData *user, const MTPBool &result) {
void ContactsBox::setAdminDone(gsl::not_null<UserData*> user, const MTPBool &result) {
if (mtpIsTrue(result)) {
if (_inner->chat()->noParticipantInfo()) {
App::api()->requestFullPeer(_inner->chat());
@ -442,7 +443,7 @@ void ContactsBox::setAdminDone(UserData *user, const MTPBool &result) {
}
}
void ContactsBox::removeAdminDone(UserData *user, const MTPBool &result) {
void ContactsBox::removeAdminDone(gsl::not_null<UserData*> user, const MTPBool &result) {
if (mtpIsTrue(result)) {
_inner->chat()->admins.remove(user);
}
@ -610,7 +611,7 @@ ContactsBox::Inner::Inner(QWidget *parent, UserData *bot) : TWidget(parent)
addDialogsToList([](PeerData *peer) {
if (peer->isChat() && peer->asChat()->canEdit()) {
return true;
} else if (peer->isMegagroup() && peer->asChannel()->canAddMembers()) {
} else if (peer->isMegagroup()) {
return true;
}
return false;
@ -719,10 +720,10 @@ void ContactsBox::Inner::addBot() {
} else if (!info->startGroupToken.isEmpty()) {
MTP::send(MTPmessages_StartBot(_bot->inputUser, _addToPeer->input, MTP_long(rand_value<uint64>()), MTP_string(info->startGroupToken)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, { _bot, _addToPeer }));
} else {
App::main()->addParticipants(_addToPeer, QVector<UserData*>(1, _bot));
App::main()->addParticipants(_addToPeer, std::vector<gsl::not_null<UserData*>>(1, _bot));
}
} else {
App::main()->addParticipants(_addToPeer, QVector<UserData*>(1, _bot));
App::main()->addParticipants(_addToPeer, std::vector<gsl::not_null<UserData*>>(1, _bot));
}
Ui::hideLayer();
Ui::showPeerHistory(_addToPeer, ShowAtUnreadMsgId);
@ -742,21 +743,8 @@ void ContactsBox::Inner::addAdminDone(MTPChannelAdminRights rights, const MTPUpd
if (req != _addAdminRequestId) return;
_addAdminRequestId = 0;
if (_addAdmin && _channel && _channel->isMegagroup()) {
Notify::PeerUpdate update(_channel);
if (_channel->mgInfo->lastParticipants.indexOf(_addAdmin) < 0) {
_channel->mgInfo->lastParticipants.push_front(_addAdmin);
update.flags |= Notify::PeerUpdate::Flag::MembersChanged;
}
_channel->mgInfo->lastAdmins.insert(_addAdmin, rights);
update.flags |= Notify::PeerUpdate::Flag::AdminsChanged;
if (_addAdmin->botInfo) {
_channel->mgInfo->bots.insert(_addAdmin);
if (_channel->mgInfo->botStatus != 0 && _channel->mgInfo->botStatus < 2) {
_channel->mgInfo->botStatus = 2;
}
}
Notify::peerUpdatedDelayed(update);
if (_addAdmin && _channel) {
_channel->applyEditAdmin(_addAdmin, rights);
}
if (_addAdminBox) _addAdminBox->closeBox();
emit adminAdded();
@ -1336,117 +1324,197 @@ void ContactsBox::Inner::setSearchedPressed(int pressed) {
_searchedPressed = pressed;
}
void ContactsBox::Inner::chooseParticipant() {
if (_saving) return;
bool addingAdmin = (_channel && _membersFilter == MembersFilter::Admins);
if (!addingAdmin && usingMultiSelect()) {
_time = unixtime();
if (_filter.isEmpty()) {
if (_searchedSelected >= 0 && _searchedSelected < _byUsername.size()) {
auto data = d_byUsername[_searchedSelected];
auto peer = _byUsername[_searchedSelected];
if (data->disabledChecked) return;
void ContactsBox::Inner::changeMultiSelectCheckState() {
_time = unixtime();
if (_filter.isEmpty()) {
if (_searchedSelected >= 0 && _searchedSelected < _byUsername.size()) {
auto data = d_byUsername[_searchedSelected];
auto peer = _byUsername[_searchedSelected];
if (data->disabledChecked) return;
changeCheckState(data, peer);
} else if (_selected) {
auto data = contactData(_selected);
auto peer = _selected->history()->peer;
if (data->disabledChecked) return;
changeCheckState(data, peer);
} else if (_selected) {
auto data = contactData(_selected);
auto peer = _selected->history()->peer;
if (data->disabledChecked) return;
changeCheckState(_selected);
}
} else {
if (_searchedSelected >= 0 && _searchedSelected < _byUsernameFiltered.size()) {
auto data = d_byUsernameFiltered[_searchedSelected];
auto peer = _byUsernameFiltered[_searchedSelected];
if (data->disabledChecked) return;
int i = 0, l = d_byUsername.size();
for (; i < l; ++i) {
if (d_byUsername[i] == data) {
break;
}
}
if (i == l) {
d_byUsername.push_back(data);
_byUsername.push_back(peer);
for (i = 0, l = _byUsernameDatas.size(); i < l;) {
if (_byUsernameDatas[i] == data) {
_byUsernameDatas.removeAt(i);
--l;
} else {
++i;
}
}
}
changeCheckState(data, peer);
} else if (_filteredSelected >= 0 && _filteredSelected < _filtered.size()) {
auto data = contactData(_filtered[_filteredSelected]);
auto peer = _filtered[_filteredSelected]->history()->peer;
if (data->disabledChecked) return;
changeCheckState(data, peer);
}
changeCheckState(_selected);
}
} else {
PeerData *peer = 0;
if (_filter.isEmpty()) {
if (_searchedSelected >= 0 && _searchedSelected < _byUsername.size()) {
peer = _byUsername[_searchedSelected];
} else if (_selected) {
peer = _selected->history()->peer;
}
} else {
if (_searchedSelected >= 0 && _searchedSelected < _byUsernameFiltered.size()) {
peer = _byUsernameFiltered[_searchedSelected];
} else {
if (_filteredSelected < 0 || _filteredSelected >= _filtered.size()) return;
peer = _filtered[_filteredSelected]->history()->peer;
}
}
if (peer) {
if (addingAdmin) {
_addAdmin = peer->asUser();
if (_addAdminRequestId) {
MTP::cancel(_addAdminRequestId);
_addAdminRequestId = 0;
if (_searchedSelected >= 0 && _searchedSelected < _byUsernameFiltered.size()) {
auto data = d_byUsernameFiltered[_searchedSelected];
auto peer = _byUsernameFiltered[_searchedSelected];
if (data->disabledChecked) return;
int i = 0, l = d_byUsername.size();
for (; i < l; ++i) {
if (d_byUsername[i] == data) {
break;
}
if (_addAdminBox) _addAdminBox->deleteLater();
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<UserData*, MTPChannelAdminRights>()).value(_addAdmin, MTP_channelAdminRights(MTP_flags(defaultRights)));
_addAdminBox = Ui::show(Box<EditAdminBox>(_channel, _addAdmin, currentRights, base::lambda_guarded(this, [this](const MTPChannelAdminRights &rights) {
if (_addAdminRequestId) return;
_addAdminRequestId = MTP::send(MTPchannels_EditAdmin(_channel->inputChannel, _addAdmin->inputUser, rights), rpcDone(&Inner::addAdminDone, rights), rpcFail(&Inner::addAdminFail));
})), KeepOtherLayers);
} else if (sharingBotGame()) {
_addToPeer = peer;
auto confirmText = [peer] {
if (peer->isUser()) {
return lng_bot_sure_share_game(lt_user, App::peerName(peer));
}
return lng_bot_sure_share_game_group(lt_group, peer->name);
};
Ui::show(Box<ConfirmBox>(confirmText(), base::lambda_guarded(this, [this] {
addBot();
})), KeepOtherLayers);
} else if (bot() && (peer->isChat() || peer->isMegagroup())) {
_addToPeer = peer;
Ui::show(Box<ConfirmBox>(lng_bot_sure_invite(lt_group, peer->name), base::lambda_guarded(this, [this] {
addBot();
})), KeepOtherLayers);
} else {
Ui::hideSettingsAndLayer(true);
App::main()->choosePeer(peer->id, ShowAtUnreadMsgId);
}
if (i == l) {
d_byUsername.push_back(data);
_byUsername.push_back(peer);
for (i = 0, l = _byUsernameDatas.size(); i < l;) {
if (_byUsernameDatas[i] == data) {
_byUsernameDatas.removeAt(i);
--l;
} else {
++i;
}
}
}
changeCheckState(data, peer);
} else if (_filteredSelected >= 0 && _filteredSelected < _filtered.size()) {
auto data = contactData(_filtered[_filteredSelected]);
auto peer = _filtered[_filteredSelected]->history()->peer;
if (data->disabledChecked) return;
changeCheckState(data, peer);
}
}
}
PeerData *ContactsBox::Inner::selectedPeer() const {
if (_filter.isEmpty()) {
if (_searchedSelected >= 0 && _searchedSelected < _byUsername.size()) {
return _byUsername[_searchedSelected];
} else if (_selected) {
return _selected->history()->peer;
}
} else {
if (_searchedSelected >= 0 && _searchedSelected < _byUsernameFiltered.size()) {
return _byUsernameFiltered[_searchedSelected];
} else if (_filteredSelected >= 0 && _filteredSelected < _filtered.size()) {
return _filtered[_filteredSelected]->history()->peer;
}
}
return nullptr;
}
void ContactsBox::Inner::chooseParticipant() {
if (_saving) {
return;
}
if (usingMultiSelect()) {
changeMultiSelectCheckState();
} else {
if (_channel && _membersFilter == MembersFilter::Admins) {
addSelectedAsChannelAdmin();
} else if (sharingBotGame()) {
shareBotGameToSelected();
} else if (bot()) {
addBotToSelectedGroup();
} else if (auto peer = selectedPeer()) {
Ui::hideSettingsAndLayer(true);
App::main()->choosePeer(peer->id, ShowAtUnreadMsgId);
}
}
update();
}
void ContactsBox::Inner::addSelectedAsChannelAdmin() {
auto peer = selectedPeer();
if (!peer) {
return;
}
_addAdmin = peer->asUser();
t_assert(_addAdmin != nullptr);
if (_addAdminRequestId) {
MTP::cancel(_addAdminRequestId);
_addAdminRequestId = 0;
}
if (_addAdminBox) _addAdminBox->deleteLater();
auto showBox = [this](auto &&currentRights) {
_addAdminBox = Ui::show(Box<EditAdminBox>(_channel, _addAdmin, currentRights, base::lambda_guarded(this, [this](const MTPChannelAdminRights &rights) {
if (_addAdminRequestId) return;
_addAdminRequestId = MTP::send(MTPchannels_EditAdmin(_channel->inputChannel, _addAdmin->inputUser, rights), rpcDone(&Inner::addAdminDone, rights), rpcFail(&Inner::addAdminFail));
})), KeepOtherLayers);
};
auto loadedRights = [this]() -> const MegagroupInfo::Admin * {
if (_channel->isMegagroup()) {
auto it = _channel->mgInfo->lastAdmins.constFind(_addAdmin);
if (it != _channel->mgInfo->lastAdmins.cend()) {
return &it.value();
}
}
return nullptr;
};
if (auto rights = loadedRights()) {
if (rights->canEdit) {
showBox(rights->rights);
} else {
Ui::show(Box<InformBox>(lang(lng_error_cant_edit_admin)), KeepOtherLayers);
}
} else {
// We don't have current rights yet.
_addAdminRequestId = MTP::send(MTPchannels_GetParticipant(_channel->inputChannel, _addAdmin->inputUser), ::rpcDone(base::lambda_guarded(this, [this, showBox](const MTPchannels_ChannelParticipant &result) {
Expects(result.type() == mtpc_channels_channelParticipant);
auto &participant = result.c_channels_channelParticipant();
App::feedUsers(participant.vusers);
_addAdminRequestId = 0;
if (participant.vparticipant.type() == mtpc_channelParticipantAdmin) {
if (participant.vparticipant.c_channelParticipantAdmin().is_can_edit()) {
showBox(participant.vparticipant.c_channelParticipantAdmin().vadmin_rights);
} else {
Ui::show(Box<InformBox>(lang(lng_error_cant_edit_admin)), KeepOtherLayers);
}
} else {
showBox(EditAdminBox::DefaultRights(_channel));
}
})), ::rpcFail(base::lambda_guarded(this, [this](const RPCError &error) {
if (MTP::isDefaultHandledError(error)) {
return false;
}
_addAdminRequestId = 0;
return true;
})));
}
}
void ContactsBox::Inner::shareBotGameToSelected() {
_addToPeer = selectedPeer();
if (!_addToPeer) {
return;
}
auto confirmText = [this] {
if (_addToPeer->isUser()) {
return lng_bot_sure_share_game(lt_user, App::peerName(_addToPeer));
}
return lng_bot_sure_share_game_group(lt_group, _addToPeer->name);
};
Ui::show(Box<ConfirmBox>(confirmText(), base::lambda_guarded(this, [this] {
addBot();
})), KeepOtherLayers);
}
void ContactsBox::Inner::addBotToSelectedGroup() {
_addToPeer = selectedPeer();
if (!_addToPeer) {
return;
}
if (auto megagroup = _addToPeer->asMegagroup()) {
if (!megagroup->canAddMembers()) {
Ui::show(Box<InformBox>(lang(lng_error_cant_add_member)), KeepOtherLayers);
return;
}
}
if (_addToPeer->isChat() || _addToPeer->isMegagroup()) {
Ui::show(Box<ConfirmBox>(lng_bot_sure_invite(lt_group, _addToPeer->name), base::lambda_guarded(this, [this] {
addBot();
})), KeepOtherLayers);
}
}
void ContactsBox::Inner::changeCheckState(Dialogs::Row *row) {
changeCheckState(contactData(row), row->history()->peer);
}
@ -1974,8 +2042,8 @@ void ContactsBox::Inner::selectSkipPage(int32 h, int32 dir) {
selectSkip(points * dir);
}
QVector<UserData*> ContactsBox::Inner::selected() {
QVector<UserData*> result;
std::vector<gsl::not_null<UserData*>> ContactsBox::Inner::selected() {
std::vector<gsl::not_null<UserData*>> result;
if (!usingMultiSelect()) {
return result;
}
@ -1987,13 +2055,17 @@ QVector<UserData*> ContactsBox::Inner::selected() {
}
result.reserve(_contactsData.size());
for (auto i = _contactsData.cbegin(), e = _contactsData.cend(); i != e; ++i) {
if (i.value()->checkbox->checked() && i.key()->isUser()) {
result.push_back(i.key()->asUser());
if (i.value()->checkbox->checked()) {
if (auto user = i.key()->asUser()) {
result.push_back(user);
}
}
}
for (int i = 0, l = _byUsername.size(); i < l; ++i) {
if (d_byUsername[i]->checkbox->checked() && _byUsername[i]->isUser()) {
result.push_back(_byUsername[i]->asUser());
if (d_byUsername[i]->checkbox->checked()) {
if (auto user = _byUsername[i]->asUser()) {
result.push_back(user);
}
}
}
return result;

View File

@ -105,8 +105,8 @@ private:
void saveAdminsDone(const MTPUpdates &result);
void saveSelectedAdmins();
void getAdminsDone(const MTPmessages_ChatFull &result);
void setAdminDone(UserData *user, const MTPBool &result);
void removeAdminDone(UserData *user, const MTPBool &result);
void setAdminDone(gsl::not_null<UserData*> user, const MTPBool &result);
void removeAdminDone(gsl::not_null<UserData*> user, const MTPBool &result);
bool saveAdminsFail(const RPCError &error);
bool editAdminFail(const RPCError &error);
@ -163,7 +163,7 @@ public:
void selectSkip(int32 dir);
void selectSkipPage(int32 h, int32 dir);
QVector<UserData*> selected();
std::vector<gsl::not_null<UserData*>> selected();
QVector<MTPInputUser> selectedInputs();
bool allAdmins() const;
void setAllAdminsChangedCallback(base::lambda<void()> allAdminsChangedCallback) {
@ -268,9 +268,14 @@ private:
template <typename FilterCallback>
void addDialogsToList(FilterCallback callback);
PeerData *selectedPeer() const;
bool usingMultiSelect() const {
return (_chat != nullptr) || (_creating != CreatingGroupNone && (!_channel || _membersFilter != MembersFilter::Admins));
}
void changeMultiSelectCheckState();
void addSelectedAsChannelAdmin();
void shareBotGameToSelected();
void addBotToSelectedGroup();
base::lambda<void(PeerData *peer, bool selected)> _peerSelectedChangedCallback;

View File

@ -23,16 +23,81 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "lang/lang_keys.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/buttons.h"
#include "styles/style_boxes.h"
#include "boxes/calendar_box.h"
EditParticipantBox::EditParticipantBox(QWidget*, gsl::not_null<ChannelData*> channel, gsl::not_null<UserData*> user) : BoxContent()
, _channel(channel)
, _user(user) {
namespace {
constexpr auto kMaxRestrictDelayDays = 366;
template <typename CheckboxesMap, typename DependenciesMap>
void ApplyDependencies(CheckboxesMap &checkboxes, DependenciesMap &dependencies, QPointer<Ui::Checkbox> changed) {
auto checkAndApply = [&checkboxes](auto &&current, auto dependency, bool isChecked) {
for (auto &&checkbox : checkboxes) {
if ((checkbox.first & dependency) && (checkbox.second->checked() == isChecked)) {
current->setChecked(isChecked);
return true;
}
}
return false;
};
auto applySomeDependency = [&checkboxes, &dependencies, &changed, checkAndApply] {
auto result = false;
for (auto &&entry : checkboxes) {
if (entry.second == changed) {
continue;
}
auto isChecked = entry.second->checked();
for (auto &&dependency : dependencies) {
if (entry.first & (isChecked ? dependency.first : dependency.second)) {
if (checkAndApply(entry.second, (isChecked ? dependency.second : dependency.first), !isChecked)) {
result = true;
break;
}
}
}
}
return result;
};
while (true) {
if (!applySomeDependency()) {
break;
}
};
}
void EditParticipantBox::resizeToContent() {
auto newWidth = st::boxWideWidth;
auto newHeight = 0;
} // namespace
class EditParticipantBox::Inner : public TWidget {
public:
Inner(QWidget *parent, gsl::not_null<ChannelData*> channel, gsl::not_null<UserData*> user) : TWidget(parent)
, _channel(channel)
, _user(user) {
}
template <typename Widget>
QPointer<Widget> addControl(object_ptr<Widget> row) {
row->setParent(this);
_rows.push_back(std::move(row));
return static_cast<Widget*>(_rows.back().data());
}
protected:
int resizeGetHeight(int newWidth) override;
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
private:
gsl::not_null<ChannelData*> _channel;
gsl::not_null<UserData*> _user;
std::vector<object_ptr<TWidget>> _rows;
};
int EditParticipantBox::Inner::resizeGetHeight(int newWidth) {
auto newHeight = st::contactsPhotoSize + st::contactsPadding.bottom();
auto rowWidth = newWidth - st::boxPadding.left() - st::boxPadding.right();
for (auto &&row : _rows) {
row->resizeToNaturalWidth(rowWidth);
@ -41,50 +106,111 @@ void EditParticipantBox::resizeToContent() {
if (!_rows.empty()) {
newHeight += (_rows.size() - 1) * st::boxLittleSkip;
}
setDimensions(st::boxWideWidth, newHeight);
return newHeight;
}
void EditParticipantBox::resizeEvent(QResizeEvent *e) {
auto top = 0;
void EditParticipantBox::Inner::resizeEvent(QResizeEvent *e) {
auto top = st::contactsPhotoSize + st::contactsPadding.bottom();
for (auto &&row : _rows) {
row->moveToLeft(st::boxPadding.left(), top);
top += row->heightNoMargins() + st::boxLittleSkip;
}
}
void EditParticipantBox::paintEvent(QPaintEvent *e) {
void EditParticipantBox::Inner::paintEvent(QPaintEvent *e) {
Painter p(this);
p.fillRect(e->rect(), st::boxBg);
_user->paintUserpicLeft(p, st::boxPadding.left(), 0, width(), st::contactsPhotoSize);
p.setPen(st::contactsNameFg);
auto namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
auto namew = width() - namex - st::contactsPadding.right();
_user->nameText.drawLeftElided(p, namex, st::contactsNameTop, namew, width());
auto statusText = [this] {
if (_user->botInfo) {
auto isAdmin = _channel->mgInfo ? _channel->mgInfo->lastAdmins.contains(_user) : false;
auto seesAllMessages = (_user->botInfo->readsAllHistory || isAdmin);
return lang(seesAllMessages ? lng_status_bot_reads_all : lng_status_bot_not_reads_all);
}
return App::onlineText(_user->onlineTill, unixtime());
};
p.setFont(st::contactsStatusFont);
p.setPen(st::contactsStatusFg);
p.drawTextLeft(namex, st::contactsStatusTop, width(), statusText());
}
EditParticipantBox::EditParticipantBox(QWidget*, gsl::not_null<ChannelData*> channel, gsl::not_null<UserData*> user) : BoxContent()
, _channel(channel)
, _user(user) {
}
void EditParticipantBox::prepare() {
_inner = setInnerWidget(object_ptr<Inner>(this, _channel, _user));
}
template <typename Widget>
QPointer<Widget> EditParticipantBox::addControl(object_ptr<Widget> row) {
Expects(_inner != nullptr);
return _inner->addControl(std::move(row));
}
void EditParticipantBox::resizeToContent() {
_inner->resizeToWidth(st::boxWideWidth);
setDimensions(_inner->width(), _inner->height());
}
EditAdminBox::EditAdminBox(QWidget*, gsl::not_null<ChannelData*> channel, gsl::not_null<UserData*> user, const MTPChannelAdminRights &rights, base::lambda<void(MTPChannelAdminRights)> callback) : EditParticipantBox(nullptr, channel, user)
, _rights(rights) {
, _rights(rights)
, _saveCallback(std::move(callback)) {
auto dependency = [this](Flag dependent, Flag dependency) {
_dependencies.push_back(std::make_pair(dependent, dependency));
};
dependency(Flag::f_invite_link, Flag::f_invite_users); // invite_link <-> invite_users
dependency(Flag::f_invite_users, Flag::f_invite_link);
}
MTPChannelAdminRights EditAdminBox::DefaultRights(gsl::not_null<ChannelData*> channel) {
auto defaultRights = channel->isMegagroup()
? (Flag::f_change_info | Flag::f_delete_messages | Flag::f_ban_users | Flag::f_invite_users | Flag::f_invite_link | Flag::f_pin_messages)
: (Flag::f_change_info | Flag::f_post_messages | Flag::f_edit_messages | Flag::f_delete_messages);
return MTP_channelAdminRights(MTP_flags(defaultRights));
}
void EditAdminBox::prepare() {
EditParticipantBox::prepare();
setTitle(langFactory(lng_rights_edit_admin));
addControl(object_ptr<Ui::FlatLabel>(this, lang(lng_rights_edit_admin_header), Ui::FlatLabel::InitType::Simple, st::boxLabel));
auto addCheckbox = [this](Flag flag, const QString &text) {
if (!channel()->amCreator()) {
if (!(channel()->adminRights().vflags.v & flag)) {
return; // Don't add options that we don't have ourselves.
}
}
auto checked = (_rights.c_channelAdminRights().vflags.v & flag) != 0;
auto control = addControl(object_ptr<Ui::Checkbox>(this, text, checked, st::defaultBoxCheckbox));
connect(control, &Ui::Checkbox::changed, this, [this, control] {
applyDependencies(control);
}, Qt::QueuedConnection);
_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_delete_messages, lang(lng_rights_group_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_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_delete_messages, lang(lng_rights_channel_delete));
addCheckbox(Flag::f_add_admins, lang(lng_rights_add_admins));
}
@ -96,9 +222,34 @@ void EditAdminBox::prepare() {
});
refreshAboutAddAdminsText();
addButton(langFactory(lng_settings_save), [this] {
if (!_saveCallback) {
return;
}
auto newFlags = MTPDchannelAdminRights::Flags(0);
for (auto &&checkbox : _checkboxes) {
if (checkbox.second->checked()) {
newFlags |= checkbox.first;
} else {
newFlags &= ~checkbox.first;
}
}
_saveCallback(MTP_channelAdminRights(MTP_flags(newFlags)));
});
addButton(langFactory(lng_cancel), [this] { closeBox(); });
applyDependencies(nullptr);
for (auto &&checkbox : _checkboxes) {
checkbox.second->finishAnimations();
}
resizeToContent();
}
void EditAdminBox::applyDependencies(QPointer<Ui::Checkbox> changed) {
ApplyDependencies(_checkboxes, _dependencies, changed);
}
void EditAdminBox::refreshAboutAddAdminsText() {
auto addAdmins = _checkboxes.find(Flag::f_add_admins);
t_assert(addAdmins != _checkboxes.end());
@ -107,23 +258,105 @@ void EditAdminBox::refreshAboutAddAdminsText() {
resizeToContent();
}
EditRestrictedBox::EditRestrictedBox(QWidget*, gsl::not_null<ChannelData*> channel, gsl::not_null<UserData*> user, const MTPChannelBannedRights &rights, base::lambda<void(MTPChannelBannedRights)> callback) : EditParticipantBox(nullptr, channel, user) {
EditRestrictedBox::EditRestrictedBox(QWidget*, gsl::not_null<ChannelData*> channel, gsl::not_null<UserData*> user, const MTPChannelBannedRights &rights, base::lambda<void(MTPChannelBannedRights)> callback) : EditParticipantBox(nullptr, channel, user)
, _rights(rights)
, _until(rights.c_channelBannedRights().vuntil_date.v)
, _saveCallback(std::move(callback)) {
auto dependency = [this](Flag dependent, Flag dependency) {
_dependencies.push_back(std::make_pair(dependent, dependency));
};
dependency(Flag::f_send_gifs, Flag::f_send_stickers); // stickers <-> gifs
dependency(Flag::f_send_stickers, Flag::f_send_gifs);
dependency(Flag::f_send_games, Flag::f_send_stickers); // stickers <-> games
dependency(Flag::f_send_stickers, Flag::f_send_games);
dependency(Flag::f_send_inline, Flag::f_send_stickers); // stickers <-> inline
dependency(Flag::f_send_stickers, Flag::f_send_inline);
dependency(Flag::f_send_stickers, Flag::f_send_media); // stickers -> send_media
dependency(Flag::f_embed_links, Flag::f_send_media); // embed_links -> send_media
dependency(Flag::f_send_media, Flag::f_send_messages); // send_media- > send_messages
dependency(Flag::f_send_messages, Flag::f_view_messages); // send_messages -> view_messages
}
void EditRestrictedBox::prepare() {
EditParticipantBox::prepare();
setTitle(langFactory(lng_rights_user_restrictions));
addControl(object_ptr<Ui::FlatLabel>(this, lang(lng_rights_edit_admin_header), Ui::FlatLabel::InitType::Simple, st::boxLabel));
addControl(object_ptr<Ui::FlatLabel>(this, lang(lng_rights_user_restrictions_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 addCheckbox = [this](Flags flags, const QString &text) {
auto checked = (_rights.c_channelBannedRights().vflags.v & flags) == 0;
auto control = addControl(object_ptr<Ui::Checkbox>(this, text, checked, st::defaultBoxCheckbox));
_checkboxes.emplace(flag, control);
connect(control, &Ui::Checkbox::changed, this, [this, control] {
applyDependencies(control);
}, Qt::QueuedConnection);
_checkboxes.emplace(flags, 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_send_stickers | Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline, lang(lng_rights_chat_send_stickers));
addCheckbox(Flag::f_embed_links, lang(lng_rights_chat_send_links));
_restrictUntil = addControl(object_ptr<Ui::LinkButton>(this, QString(), st::boxLinkButton));
_restrictUntil->setClickedCallback([this] { showRestrictUntil(); });
setRestrictUntil(_until);
//addControl(object_ptr<Ui::LinkButton>(this, lang(lng_rights_chat_banned_block), st::boxLinkButton));
addButton(langFactory(lng_settings_save), [this] {
if (!_saveCallback) {
return;
}
auto newFlags = MTPDchannelBannedRights::Flags(0);
for (auto &&checkbox : _checkboxes) {
if (checkbox.second->checked()) {
newFlags &= ~checkbox.first;
} else {
newFlags |= checkbox.first;
}
}
_saveCallback(MTP_channelBannedRights(MTP_flags(newFlags), MTP_int(_until)));
});
addButton(langFactory(lng_cancel), [this] { closeBox(); });
applyDependencies(nullptr);
for (auto &&checkbox : _checkboxes) {
checkbox.second->finishAnimations();
}
resizeToContent();
}
void EditRestrictedBox::applyDependencies(QPointer<Ui::Checkbox> changed) {
ApplyDependencies(_checkboxes, _dependencies, changed);
}
MTPChannelBannedRights EditRestrictedBox::DefaultRights(gsl::not_null<ChannelData*> channel) {
auto defaultRights = Flag::f_send_messages | Flag::f_send_media | Flag::f_embed_links | Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline;
return MTP_channelBannedRights(MTP_flags(defaultRights), MTP_int(0));
}
void EditRestrictedBox::showRestrictUntil() {
auto tomorrow = QDate::currentDate().addDays(1);
auto highlighted = isUntilForever() ? tomorrow : date(_until).date();
auto month = highlighted;
_restrictUntilBox = Ui::show(Box<CalendarBox>(month, highlighted, [this](const QDate &date) { setRestrictUntil(static_cast<int>(QDateTime(date).toTime_t())); }), KeepOtherLayers);
_restrictUntilBox->setMaxDate(QDate::currentDate().addDays(kMaxRestrictDelayDays));
_restrictUntilBox->setMinDate(tomorrow);
_restrictUntilBox->addLeftButton(langFactory(lng_rights_chat_banned_forever), [this] { setRestrictUntil(0); });
}
void EditRestrictedBox::setRestrictUntil(int32 until) {
_until = until;
if (_restrictUntilBox) {
_restrictUntilBox->closeBox();
}
auto untilText = [this] {
if (isUntilForever()) {
return lang(lng_rights_chat_banned_forever);
}
return langDayOfMonthFull(date(_until).date());
};
_restrictUntil->setText(lng_rights_chat_banned_until(lt_when, untilText()));
}

View File

@ -28,15 +28,16 @@ class LinkButton;
class Checkbox;
} // namespace Ui
class CalendarBox;
class EditParticipantBox : public BoxContent {
public:
EditParticipantBox(QWidget*, gsl::not_null<ChannelData*> channel, gsl::not_null<UserData*> user);
protected:
void resizeToContent();
void prepare() override;
void resizeEvent(QResizeEvent *e) override;
void paintEvent(QPaintEvent *e) override;
void resizeToContent();
gsl::not_null<UserData*> user() const {
return _user;
@ -46,16 +47,14 @@ protected:
}
template <typename Widget>
QPointer<Widget> addControl(object_ptr<Widget> row) {
_rows.push_back(std::move(row));
return static_cast<Widget*>(_rows.back().data());
}
QPointer<Widget> addControl(object_ptr<Widget> row);
private:
gsl::not_null<UserData*> _user;
gsl::not_null<ChannelData*> _channel;
std::vector<object_ptr<TWidget>> _rows;
class Inner;
QPointer<Inner> _inner;
};
@ -63,33 +62,58 @@ class EditAdminBox : public EditParticipantBox {
public:
EditAdminBox(QWidget*, gsl::not_null<ChannelData*> channel, gsl::not_null<UserData*> user, const MTPChannelAdminRights &rights, base::lambda<void(MTPChannelAdminRights)> callback);
static MTPChannelAdminRights DefaultRights(gsl::not_null<ChannelData*> channel);
protected:
void prepare() override;
private:
using Flag = MTPDchannelAdminRights::Flag;
using Flags = MTPDchannelAdminRights::Flags;
void applyDependencies(QPointer<Ui::Checkbox> changed);
void refreshAboutAddAdminsText();
MTPChannelAdminRights _rights;
std::vector<std::pair<Flag, Flag>> _dependencies;
base::lambda<void(MTPChannelAdminRights)> _saveCallback;
std::map<Flag, QPointer<Ui::Checkbox>> _checkboxes;
std::map<Flags, QPointer<Ui::Checkbox>> _checkboxes;
QPointer<Ui::FlatLabel> _aboutAddAdmins;
};
// Restricted box works with flags in the opposite way.
// If some flag is set in the rights then the checkbox is unchecked.
class EditRestrictedBox : public EditParticipantBox {
public:
EditRestrictedBox(QWidget*, gsl::not_null<ChannelData*> channel, gsl::not_null<UserData*> user, const MTPChannelBannedRights &rights, base::lambda<void(MTPChannelBannedRights)> callback);
static MTPChannelBannedRights DefaultRights(gsl::not_null<ChannelData*> channel);
static constexpr auto kRestrictUntilForever = TimeId(INT_MAX);
protected:
void prepare() override;
private:
using Flag = MTPDchannelBannedRights::Flag;
using Flags = MTPDchannelBannedRights::Flags;
void applyDependencies(QPointer<Ui::Checkbox> changed);
void showRestrictUntil();
void setRestrictUntil(int32 until);
bool isUntilForever() {
return (_until <= 0) || (_until == kRestrictUntilForever);
}
MTPChannelBannedRights _rights;
int32 _until = 0;
std::vector<std::pair<Flag, Flag>> _dependencies;
base::lambda<void(MTPChannelBannedRights)> _saveCallback;
std::map<Flag, QPointer<Ui::Checkbox>> _checkboxes;
std::map<Flags, QPointer<Ui::Checkbox>> _checkboxes;
QPointer<Ui::LinkButton> _restrictUntil;
QPointer<CalendarBox> _restrictUntilBox;
};

View File

@ -27,6 +27,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "mainwindow.h"
#include "boxes/contacts_box.h"
#include "boxes/confirm_box.h"
#include "boxes/edit_participant_box.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/scroll_area.h"
#include "ui/effects/ripple_animation.h"
@ -79,9 +80,13 @@ void MembersBox::prepare() {
_inner = setInnerWidget(object_ptr<Inner>(this, _channel, _filter), st::boxLayerScroll);
setDimensions(st::boxWideWidth, st::boxMaxListHeight);
addButton(langFactory(lng_close), [this] { closeBox(); });
if (_channel->amCreator() && (_channel->membersCount() < (_channel->isMegagroup() ? Global::MegagroupSizeMax() : Global::ChatSizeMax()) || (!_channel->isMegagroup() && !_channel->isPublic()) || _filter == MembersFilter::Admins)) {
addLeftButton(langFactory((_filter == MembersFilter::Admins) ? lng_channel_add_admin : lng_channel_add_members), [this] { onAdd(); });
refreshButtons();
if (_filter == MembersFilter::Admins) {
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::ChannelRightsChanged, [this](const Notify::PeerUpdate &update) {
if (update.peer == _channel) {
refreshButtons();
}
}));
}
connect(_inner, SIGNAL(mustScrollTo(int, int)), this, SLOT(onScrollToY(int, int)));
@ -90,6 +95,18 @@ void MembersBox::prepare() {
connect(_loadTimer, SIGNAL(timeout()), _inner, SLOT(load()));
}
void MembersBox::refreshButtons() {
clearButtons();
addButton(langFactory(lng_close), [this] { closeBox(); });
if (_filter == MembersFilter::Admins) {
if (_channel->canAddAdmins()) {
addLeftButton(langFactory(lng_channel_add_admin), [this] { onAdd(); });
}
} else if (_channel->amCreator() && (_channel->membersCount() < (_channel->isMegagroup() ? Global::MegagroupSizeMax() : Global::ChatSizeMax()) || (!_channel->isMegagroup() && !_channel->isPublic()))) {
addLeftButton(langFactory(lng_channel_add_members), [this] { onAdd(); });
}
}
void MembersBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Down) {
_inner->selectSkip(1);
@ -133,11 +150,20 @@ void MembersBox::onAdminAdded() {
_loadTimer->start(kReloadChannelAdminsTimeout);
}
MembersBox::Inner::Inner(QWidget *parent, ChannelData *channel, MembersFilter filter) : TWidget(parent)
struct MembersBox::Inner::RowData {
std::unique_ptr<Ui::RippleAnimation> ripple;
int rippleRowTop = 0;
Text name;
QString online;
bool onlineColor;
bool canKick;
};
MembersBox::Inner::Inner(QWidget *parent, gsl::not_null<ChannelData*> channel, MembersFilter filter) : TWidget(parent)
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
, _channel(channel)
, _filter(filter)
, _kickText(lang(lng_profile_kick))
, _kickText(lang((filter == MembersFilter::Admins) ? lng_profile_edit_admin : lng_profile_kick))
, _kickWidth(st::normalFont->width(_kickText))
, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.right())
, _about(_aboutWidth) {
@ -168,7 +194,7 @@ void MembersBox::Inner::paintEvent(QPaintEvent *e) {
auto yFrom = r.y() - st::membersMarginTop;
auto yTo = r.y() + r.height() - st::membersMarginTop;
p.translate(0, st::membersMarginTop);
if (_rows.isEmpty()) {
if (_rows.empty()) {
p.setFont(st::noContactsFont);
p.setPen(st::noContactsColor);
p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center);
@ -179,7 +205,7 @@ void MembersBox::Inner::paintEvent(QPaintEvent *e) {
for (; from < to; ++from) {
auto selected = (_pressed >= 0) ? (from == _pressed) : (from == _selected);
auto kickSelected = (_pressed >= 0) ? (from == _kickPressed && from == _kickSelected) : (from == _kickSelected);
paintDialog(p, ms, _rows[from], data(from), selected, kickSelected);
paintDialog(p, ms, _rows[from], selected, kickSelected);
p.translate(0, _rowHeight);
}
if (to == _rows.size() && _filter == MembersFilter::Recent && (_rows.size() < _channel->membersCount() || _rows.size() >= Global::ChatSizeMax())) {
@ -213,8 +239,9 @@ void MembersBox::Inner::mousePressEvent(QMouseEvent *e) {
updateSelection();
setPressed(_selected);
_kickPressed = _kickSelected;
if (_selected >= 0 && _selected < _datas.size() && _kickSelected < 0) {
addRipple(_datas[_selected]);
if (_selected >= 0 && _selected < _rows.size() && _kickSelected < 0) {
ensureData(_rows[_selected]);
addRipple(_rows[_selected].data.get());
}
}
@ -225,18 +252,7 @@ void MembersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
if (e->button() == Qt::LeftButton) {
if (pressed == _selected && kickPressed == _kickSelected) {
if (kickPressed >= 0) {
if (!_kickRequestId) {
_kickConfirm = _rows.at(_kickSelected);
if (_kickBox) _kickBox->deleteLater();
auto text = (_filter == MembersFilter::Recent ? (_channel->isMegagroup() ? lng_profile_sure_kick : lng_profile_sure_kick_channel) : lng_profile_sure_kick_admin)(lt_user, _kickConfirm->firstName);
_kickBox = Ui::show(Box<ConfirmBox>(text, base::lambda_guarded(this, [this] {
if (_filter == MembersFilter::Recent) {
// _kickRequestId = MTP::send(MTPchannels_KickFromChannel(_channel->inputChannel, _kickConfirm->inputUser, MTP_bool(true)), rpcDone(&Inner::kickDone), rpcFail(&Inner::kickFail));
} else {
// _kickRequestId = MTP::send(MTPchannels_EditAdmin(_channel->inputChannel, _kickConfirm->inputUser, MTP_channelRoleEmpty()), rpcDone(&Inner::kickAdminDone), rpcFail(&Inner::kickFail));
}
})), KeepOtherLayers);
}
actionPressed(_rows[_kickSelected]);
} else if (pressed >= 0) {
chooseParticipant();
}
@ -244,7 +260,42 @@ void MembersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
}
}
void MembersBox::Inner::addRipple(MemberData *data) {
void MembersBox::Inner::actionPressed(Member &row) {
auto user = row.user;
if (_kickBox) _kickBox->closeBox();
if (_filter == MembersFilter::Recent) {
auto text = (_channel->isMegagroup() ? lng_profile_sure_kick : lng_profile_sure_kick_channel)(lt_user, user->firstName);
_kickBox = Ui::show(Box<ConfirmBox>(text, base::lambda_guarded(this, [this, user] {
MTP::send(MTPchannels_EditBanned(_channel->inputChannel, user->inputUser, ChannelData::KickedRestrictedRights()), ::rpcDone(base::lambda_guarded(this, [this, user](const MTPUpdates &result) {
App::main()->sentUpdatesReceived(result);
removeKicked(user);
if (_kickBox) _kickBox->closeBox();
})), rpcFail(&Inner::kickFail));
})), KeepOtherLayers);
} else {
auto currentRights = _rows[_kickSelected].adminRights;
_kickBox = Ui::show(Box<EditAdminBox>(_channel, user, currentRights, base::lambda_guarded(this, [this, user](const MTPChannelAdminRights &rights) {
if (_kickBox) _kickBox->closeBox();
MTP::send(MTPchannels_EditAdmin(_channel->inputChannel, user->inputUser, rights), ::rpcDone(base::lambda_guarded(this, [this, user, rights](const MTPUpdates &result, mtpRequestId req) {
if (App::main()) App::main()->sentUpdatesReceived(result);
_channel->applyEditAdmin(user, rights);
if (rights.c_channelAdminRights().vflags.v == 0) {
removeKicked(user);
} else {
auto it = std::find_if(_rows.begin(), _rows.end(), [this, user](auto &&row) {
return (row.user == user);
});
if (it != _rows.end()) {
it->adminRights = rights;
}
}
if (_kickBox) _kickBox->closeBox();
})), rpcFail(&Inner::kickFail));
})), KeepOtherLayers);
}
}
void MembersBox::Inner::addRipple(gsl::not_null<RowData*> data) {
auto rowTop = getSelectedRowTop();
if (!data->ripple) {
auto mask = Ui::RippleAnimation::rectMask(QSize(width(), _rowHeight));
@ -256,21 +307,26 @@ void MembersBox::Inner::addRipple(MemberData *data) {
data->ripple->add(mapFromGlobal(QCursor::pos()) - QPoint(0, rowTop));
}
void MembersBox::Inner::stopLastRipple(MemberData *data) {
void MembersBox::Inner::stopLastRipple(gsl::not_null<RowData*> data) {
if (data->ripple) {
data->ripple->lastStop();
}
}
void MembersBox::Inner::setPressed(int pressed) {
if (_pressed >= 0 && _pressed < _datas.size()) {
stopLastRipple(_datas[_pressed]);
if (_pressed >= 0 && _pressed < _rows.size()) {
if (_rows[_pressed].data) {
stopLastRipple(_rows[_pressed].data.get());
}
}
_pressed = pressed;
}
void MembersBox::Inner::paintDialog(Painter &p, TimeMs ms, PeerData *peer, MemberData *data, bool selected, bool kickSelected) {
UserData *user = peer->asUser();
void MembersBox::Inner::paintDialog(Painter &p, TimeMs ms, Member &row, bool selected, bool kickSelected) {
ensureData(row);
auto user = row.user;
auto &data = row.data;
p.fillRect(0, 0, width(), _rowHeight, selected ? st::contactsBgOver : st::contactsBg);
if (data->ripple) {
@ -279,13 +335,13 @@ void MembersBox::Inner::paintDialog(Painter &p, TimeMs ms, PeerData *peer, Membe
data->ripple.reset();
}
}
peer->paintUserpicLeft(p, st::contactsPadding.left(), st::contactsPadding.top(), width(), st::contactsPhotoSize);
user->paintUserpicLeft(p, st::contactsPadding.left(), st::contactsPadding.top(), width(), st::contactsPhotoSize);
p.setPen(st::contactsNameFg);
int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
int32 namew = width() - namex - st::contactsPadding.right() - (data->canKick ? (_kickWidth + st::contactsCheckPosition.x() * 2) : 0);
if (peer->isVerified()) {
auto namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
auto namew = width() - namex - st::contactsPadding.right() - (data->canKick ? (_kickWidth + st::contactsCheckPosition.x() * 2) : 0);
if (user->isVerified()) {
auto icon = &st::dialogsVerifiedIcon;
namew -= icon->width();
icon->paint(p, namex + qMin(data->name.maxWidth(), namew), st::contactsPadding.top() + st::contactsNameTop, width());
@ -313,7 +369,7 @@ void MembersBox::Inner::selectSkip(int32 dir) {
}
cur += dir;
if (cur <= 0) {
_selected = _rows.isEmpty() ? -1 : 0;
_selected = _rows.empty() ? -1 : 0;
} else if (cur >= _rows.size()) {
_selected = -1;
} else {
@ -324,7 +380,7 @@ void MembersBox::Inner::selectSkip(int32 dir) {
_selected = -1;
}
} else {
if (!_rows.isEmpty()) {
if (!_rows.empty()) {
if (_selected < 0) _selected = _rows.size() - 1;
}
}
@ -341,9 +397,14 @@ void MembersBox::Inner::selectSkipPage(int32 h, int32 dir) {
selectSkip(points * dir);
}
MembersBox::Inner::MemberData::MemberData() = default;
MembersBox::Inner::Member::Member(gsl::not_null<UserData*> user) : user(user) {
}
MembersBox::Inner::MemberData::~MemberData() = default;
MembersBox::Inner::Member::Member(Member &&other) = default;
MembersBox::Inner::Member &MembersBox::Inner::Member::operator=(Member &&other) = default;
MembersBox::Inner::Member::~Member() = default;
void MembersBox::Inner::loadProfilePhotos() {
if (_visibleTop >= _visibleBottom) return;
@ -355,7 +416,7 @@ void MembersBox::Inner::loadProfilePhotos() {
if (yTo < 0) return;
if (yFrom < 0) yFrom = 0;
if (!_rows.isEmpty()) {
if (!_rows.empty()) {
int32 from = yFrom / _rowHeight;
if (from < 0) from = 0;
if (from < _rows.size()) {
@ -363,7 +424,7 @@ void MembersBox::Inner::loadProfilePhotos() {
if (to > _rows.size()) to = _rows.size();
for (; from < to; ++from) {
_rows[from]->loadUserpic();
_rows[from].user->loadUserpic();
}
}
}
@ -371,14 +432,14 @@ void MembersBox::Inner::loadProfilePhotos() {
void MembersBox::Inner::chooseParticipant() {
if (_selected < 0 || _selected >= _rows.size()) return;
if (auto peer = _rows[_selected]) {
if (auto peer = _rows[_selected].user) {
Ui::hideLayer();
Ui::showPeerProfile(peer);
}
}
void MembersBox::Inner::refresh() {
if (_rows.isEmpty()) {
if (_rows.empty()) {
resize(width(), st::membersMarginTop + st::noContactsHeight + st::membersMarginBottom);
_aboutHeight = 0;
} else {
@ -402,10 +463,8 @@ MembersFilter MembersBox::Inner::filter() const {
MembersAlreadyIn MembersBox::Inner::already() const {
MembersAlreadyIn result;
for_const (auto peer, _rows) {
if (peer->isUser()) {
result.insert(peer->asUser());
}
for_const (auto &&row, _rows) {
result.insert(row.user);
}
return result;
}
@ -423,34 +482,27 @@ void MembersBox::Inner::clearSel() {
updateSelection();
}
MembersBox::Inner::MemberData *MembersBox::Inner::data(int32 index) {
if (MemberData *result = _datas.at(index)) {
return result;
void MembersBox::Inner::ensureData(Member &row) {
if (row.data) {
return;
}
MemberData *result = _datas[index] = new MemberData();
result->name.setText(st::contactsNameStyle, _rows[index]->name, _textNameOptions);
int32 t = unixtime();
result->online = App::onlineText(_rows[index], t);// lng_mediaview_date_time(lt_date, _dates[index].date().toString(qsl("dd.MM.yy")), lt_time, _dates[index].time().toString(cTimeFormat()));
result->onlineColor = App::onlineColorUse(_rows[index], t);
row.data = std::make_unique<RowData>();
row.data->name.setText(st::contactsNameStyle, row.user->name, _textNameOptions);
auto now = unixtime();
row.data->online = App::onlineText(row.user, now);// lng_mediaview_date_time(lt_date, _dates[index].date().toString(qsl("dd.MM.yy")), lt_time, _dates[index].time().toString(cTimeFormat()));
row.data->onlineColor = App::onlineColorUse(row.user, now);
if (_filter == MembersFilter::Recent) {
result->canKick = _channel->canBanMembers() ? (_roles[index] == MemberRole::None) : false;
row.data->canKick = _channel->canBanMembers() ? (row.role == MemberRole::None) : false;
} else if (_filter == MembersFilter::Admins) {
result->canKick = _channel->amCreator() ? (_roles[index] == MemberRole::Admin) : false;
row.data->canKick = _channel->amCreator() ? (row.role == MemberRole::Admin) : row.adminCanEdit;
} else {
result->canKick = false;
row.data->canKick = false;
}
return result;
}
void MembersBox::Inner::clear() {
for (int32 i = 0, l = _datas.size(); i < l; ++i) {
delete _datas.at(i);
}
_datas.clear();
_rows.clear();
_dates.clear();
_roles.clear();
if (_kickBox) _kickBox->deleteLater();
if (_kickBox) _kickBox->closeBox();
clearSel();
}
@ -461,12 +513,15 @@ MembersBox::Inner::~Inner() {
void MembersBox::Inner::updateSelection() {
if (!_mouseSelection) return;
QPoint p(mapFromGlobal(_lastMousePos));
auto p = mapFromGlobal(_lastMousePos);
p.setY(p.y() - st::membersMarginTop);
bool in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePos));
auto in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePos));
auto selected = (in && p.y() >= 0 && p.y() < _rows.size() * _rowHeight) ? (p.y() / _rowHeight) : -1;
auto kickSelected = selected;
if (selected >= 0 && (!data(selected)->canKick || !QRect(width() - _kickWidth - st::contactsPadding.right() - st::contactsCheckPosition.x(), selected * _rowHeight + st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, _kickWidth, st::normalFont->height).contains(p))) {
if (selected >= 0) {
ensureData(_rows[selected]);
}
if (selected >= 0 && (!_rows[selected].data->canKick || !QRect(width() - _kickWidth - st::contactsPadding.right() - st::contactsCheckPosition.x(), selected * _rowHeight + st::contactsPadding.top() + (st::contactsPhotoSize - st::normalFont->height) / 2, _kickWidth, st::normalFont->height).contains(p))) {
kickSelected = -1;
}
if (_selected != selected || _kickSelected != kickSelected) {
@ -501,14 +556,14 @@ void MembersBox::Inner::updateSelectedRow() {
}
void MembersBox::Inner::onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) {
for (int32 i = 0, l = _rows.size(); i < l; ++i) {
if (_rows.at(i) == peer) {
if (_datas.at(i)) {
_datas.at(i)->name.setText(st::contactsNameStyle, peer->name, _textNameOptions);
for (auto i= 0, l = int(_rows.size()); i != l; ++i) {
auto &row = _rows[i];
if (row.user == peer) {
if (row.data) {
row.data->name.setText(st::contactsNameStyle, peer->name, _textNameOptions);
update(0, st::membersMarginTop + i * _rowHeight, width(), _rowHeight);
} else {
break;
}
break;
}
}
}
@ -522,9 +577,6 @@ void MembersBox::Inner::membersReceived(const MTPchannels_ChannelParticipants &r
auto &d = result.c_channels_channelParticipants();
auto &v = d.vparticipants.v;
_rows.reserve(v.size());
_datas.reserve(v.size());
_dates.reserve(v.size());
_roles.reserve(v.size());
if (_filter == MembersFilter::Recent && _channel->membersCount() < d.vcount.v) {
_channel->setMembersCount(d.vcount.v);
@ -535,11 +587,15 @@ void MembersBox::Inner::membersReceived(const MTPchannels_ChannelParticipants &r
}
App::feedUsers(d.vusers);
auto emptyRights = MTP_channelAdminRights(MTP_flags(0));
for (QVector<MTPChannelParticipant>::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) {
int32 userId = 0, addedTime = 0;
auto emptyAdminRights = MTP_channelAdminRights(MTP_flags(0));
auto emptyRestrictedRights = MTP_channelBannedRights(MTP_flags(0), MTP_int(0));
for (auto i = v.cbegin(), e = v.cend(); i != e; ++i) {
auto userId = UserId(0);
auto addedTime = TimeId(0);
auto role = MemberRole::None;
auto rights = emptyRights;
auto adminCanEdit = false;
auto adminRights = emptyAdminRights;
auto restrictedRights = emptyRestrictedRights;
switch (i->type()) {
case mtpc_channelParticipant:
userId = i->c_channelParticipant().vuser_id.v;
@ -554,7 +610,8 @@ 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;
adminRights = i->c_channelParticipantAdmin().vadmin_rights;
adminCanEdit = i->c_channelParticipantAdmin().is_can_edit();
break;
case mtpc_channelParticipantCreator:
userId = i->c_channelParticipantCreator().vuser_id.v;
@ -564,34 +621,42 @@ void MembersBox::Inner::membersReceived(const MTPchannels_ChannelParticipants &r
case mtpc_channelParticipantBanned:
userId = i->c_channelParticipantBanned().vuser_id.v;
addedTime = i->c_channelParticipantBanned().vdate.v;
role = MemberRole::Kicked;
restrictedRights = i->c_channelParticipantBanned().vbanned_rights;
role = MemberRole::Restricted;
}
if (auto user = App::userLoaded(userId)) {
_rows.push_back(user);
_dates.push_back(date(addedTime));
_roles.push_back(role);
_adminRights.push_back(rights);
_datas.push_back(nullptr);
auto row = Member(user);
row.adminCanEdit = adminCanEdit;
row.adminRights = adminRights;
row.restrictedRights = restrictedRights;
row.date = date(addedTime);
row.role = role;
_rows.push_back(std::move(row));
if (role == MemberRole::Creator && _channel->mgInfo) {
_channel->mgInfo->creator = user;
}
}
}
// update admins if we got all of them
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[i] == MemberRole::Admin) {
_channel->mgInfo->lastAdmins.insert(_rows[i], _adminRights[i]);
for (auto &&row : _rows) {
if (row.role == MemberRole::Admin) {
_channel->mgInfo->lastAdmins.insert(row.user, MegagroupInfo::Admin { row.adminRights, row.adminCanEdit });
}
}
Notify::peerUpdatedDelayed(_channel, Notify::PeerUpdate::Flag::AdminsChanged);
}
if (_rows.isEmpty()) {
_rows.push_back(App::self());
_dates.push_back(date(MTP_int(_channel->date)));
_roles.push_back(MemberRole::Self);
_datas.push_back(nullptr);
if (_rows.empty()) {
auto row = Member(App::self());
row.date = date(MTP_int(_channel->date));
row.role = MemberRole::Self;
row.adminRights = _channel->adminRightsBoxed();
row.restrictedRights = _channel->restrictedRightsBoxed();
_rows.push_back(std::move(row));
}
clearSel();
@ -608,22 +673,7 @@ bool MembersBox::Inner::membersFailed(const RPCError &error, mtpRequestId req) {
return true;
}
void MembersBox::Inner::kickDone(const MTPUpdates &result, mtpRequestId req) {
App::main()->sentUpdatesReceived(result);
if (_kickRequestId != req) return;
removeKicked();
if (_kickBox) _kickBox->closeBox();
}
void MembersBox::Inner::kickAdminDone(const MTPUpdates &result, mtpRequestId req) {
if (_kickRequestId != req) return;
if (App::main()) App::main()->sentUpdatesReceived(result);
removeKicked();
if (_kickBox) _kickBox->closeBox();
}
bool MembersBox::Inner::kickFail(const RPCError &error, mtpRequestId req) {
bool MembersBox::Inner::kickFail(const RPCError &error) {
if (MTP::isDefaultHandledError(error)) return false;
if (_kickBox) _kickBox->closeBox();
@ -631,15 +681,12 @@ bool MembersBox::Inner::kickFail(const RPCError &error, mtpRequestId req) {
return true;
}
void MembersBox::Inner::removeKicked() {
_kickRequestId = 0;
int32 index = _rows.indexOf(_kickConfirm);
if (index >= 0) {
_rows.removeAt(index);
delete _datas.at(index);
_datas.removeAt(index);
_dates.removeAt(index);
_roles.removeAt(index);
void MembersBox::Inner::removeKicked(UserData *kicked) {
auto it = std::find_if(_rows.begin(), _rows.end(), [this, kicked](auto &&row) {
return (row.user == kicked);
});
if (it != _rows.end()) {
_rows.erase(it);
clearSel();
if (_filter == MembersFilter::Recent && _channel->membersCount() > 1) {
_channel->setMembersCount(_channel->membersCount() - 1);
@ -650,5 +697,4 @@ void MembersBox::Inner::removeKicked() {
}
refresh();
}
_kickConfirm = 0;
}

View File

@ -68,6 +68,7 @@ protected:
private:
void onAdd();
void refreshButtons();
ChannelData *_channel = nullptr;
MembersFilter _filter = MembersFilter::Recent;
@ -86,13 +87,11 @@ class MembersBox::Inner : public TWidget, public RPCSender, private base::Subscr
Q_OBJECT
public:
Inner(QWidget *parent, ChannelData *channel, MembersFilter filter);
Inner(QWidget *parent, gsl::not_null<ChannelData*> channel, MembersFilter filter);
void selectSkip(int32 dir);
void selectSkipPage(int32 h, int32 dir);
void chooseParticipant();
void refresh();
ChannelData *channel() const;
@ -127,20 +126,34 @@ protected:
void mouseReleaseEvent(QMouseEvent *e) override;
private:
struct MemberData {
MemberData();
~MemberData();
std::unique_ptr<Ui::RippleAnimation> ripple;
int rippleRowTop = 0;
Text name;
QString online;
bool onlineColor;
bool canKick;
struct RowData;
enum class MemberRole {
None,
Self,
Creator,
Admin,
Restricted,
Kicked,
};
void addRipple(MemberData *data);
void stopLastRipple(MemberData *data);
struct Member {
Member(gsl::not_null<UserData*> user);
Member(Member &&other);
Member &operator=(Member &&other);
~Member();
gsl::not_null<UserData*> user;
QDateTime date;
MemberRole role = MemberRole::None;
bool adminCanEdit = false;
MTPChannelAdminRights adminRights;
MTPChannelBannedRights restrictedRights;
std::unique_ptr<RowData> data;
};
void addRipple(gsl::not_null<RowData*> data);
void stopLastRipple(gsl::not_null<RowData*> data);
void setPressed(int pressed);
void chooseParticipant();
void actionPressed(Member &row);
void updateSelection();
void loadProfilePhotos();
@ -148,17 +161,15 @@ private:
void updateRowWithTop(int rowTop);
int getSelectedRowTop() const;
void updateSelectedRow();
MemberData *data(int32 index);
void ensureData(Member &row);
void paintDialog(Painter &p, TimeMs ms, PeerData *peer, MemberData *data, bool selected, bool kickSelected);
void paintDialog(Painter &p, TimeMs ms, Member &row, bool selected, bool kickSelected);
void membersReceived(const MTPchannels_ChannelParticipants &result, mtpRequestId req);
bool membersFailed(const RPCError &error, mtpRequestId req);
void kickDone(const MTPUpdates &result, mtpRequestId req);
void kickAdminDone(const MTPUpdates &result, mtpRequestId req);
bool kickFail(const RPCError &error, mtpRequestId req);
void removeKicked();
bool kickFail(const RPCError &error);
void removeKicked(UserData *kicked);
void clear();
@ -166,7 +177,7 @@ private:
int _visibleTop = 0;
int _visibleBottom = 0;
ChannelData *_channel = nullptr;
gsl::not_null<ChannelData*> _channel;
MembersFilter _filter;
QString _kickText;
@ -179,26 +190,11 @@ private:
int _kickPressed = -1;
bool _mouseSelection = false;
UserData *_kickConfirm = nullptr;
mtpRequestId _kickRequestId = 0;
QPointer<ConfirmBox> _kickBox;
enum class MemberRole {
None,
Self,
Creator,
Admin,
Kicked,
};
QPointer<BoxContent> _kickBox;
bool _loading = true;
mtpRequestId _loadingRequestId = 0;
QVector<UserData*> _rows;
QVector<QDateTime> _dates;
QVector<MemberRole> _roles;
QVector<MTPChannelAdminRights> _adminRights;
QVector<MemberData*> _datas;
std::vector<Member> _rows;
int _aboutWidth = 0;
Text _about;

View File

@ -900,9 +900,9 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction,
if (peer->isMegagroup()) {
if (auto user = App::userLoaded(uid)) {
auto channel = peer->asChannel();
auto megagroupInfo = channel->mgInfo;
auto &megagroupInfo = channel->mgInfo;
int32 index = megagroupInfo->lastParticipants.indexOf(user);
auto index = megagroupInfo->lastParticipants.indexOf(user);
if (index >= 0) {
megagroupInfo->lastParticipants.removeAt(index);
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::MembersChanged);
@ -1117,20 +1117,24 @@ HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) {
adding->addToOverview(AddToOverviewNew);
if (adding->from()->id) {
if (adding->from()->isUser()) {
QList<UserData*> *lastAuthors = 0;
if (peer->isChat()) {
lastAuthors = &peer->asChat()->lastAuthors;
} else if (peer->isMegagroup()) {
lastAuthors = &peer->asChannel()->mgInfo->lastParticipants;
if (auto user = adding->from()->asUser()) {
auto getLastAuthors = [this]() -> QList<gsl::not_null<UserData*>>* {
if (auto chat = peer->asChat()) {
return &chat->lastAuthors;
} else if (auto channel = peer->asMegagroup()) {
return &channel->mgInfo->lastParticipants;
}
return nullptr;
};
if (auto channel = peer->asMegagroup()) {
if (adding->from()->asUser()->botInfo) {
peer->asChannel()->mgInfo->bots.insert(adding->from()->asUser());
if (peer->asChannel()->mgInfo->botStatus != 0 && peer->asChannel()->mgInfo->botStatus < 2) {
peer->asChannel()->mgInfo->botStatus = 2;
channel->mgInfo->bots.insert(adding->from()->asUser());
if (channel->mgInfo->botStatus != 0 && channel->mgInfo->botStatus < 2) {
channel->mgInfo->botStatus = 2;
}
}
}
if (lastAuthors) {
if (auto lastAuthors = getLastAuthors()) {
int prev = lastAuthors->indexOf(adding->from()->asUser());
if (prev > 0) {
lastAuthors->removeAt(prev);
@ -1146,15 +1150,17 @@ HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) {
}
}
if (adding->definesReplyKeyboard()) {
MTPDreplyKeyboardMarkup::Flags markupFlags = adding->replyKeyboardFlags();
auto markupFlags = adding->replyKeyboardFlags();
if (!(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_selective) || adding->mentionsMe()) {
OrderedSet<PeerData*> *markupSenders = 0;
if (peer->isChat()) {
markupSenders = &peer->asChat()->markupSenders;
} else if (peer->isMegagroup()) {
markupSenders = &peer->asChannel()->mgInfo->markupSenders;
}
if (markupSenders) {
auto getMarkupSenders = [this]() -> OrderedSet<gsl::not_null<PeerData*>>* {
if (auto chat = peer->asChat()) {
return &chat->markupSenders;
} else if (auto channel = peer->asMegagroup()) {
return &channel->mgInfo->markupSenders;
}
return nullptr;
};
if (auto markupSenders = getMarkupSenders()) {
markupSenders->insert(adding->from());
}
if (markupFlags & MTPDreplyKeyboardMarkup_ClientFlag::f_zero) { // zero markup means replyKeyboardHide
@ -1299,8 +1305,8 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice) {
} else if (loadedAtBottom()) { // add photos to overview and authors to lastAuthors
bool channel = isChannel();
int32 mask = 0;
QList<UserData*> *lastAuthors = nullptr;
OrderedSet<PeerData*> *markupSenders = nullptr;
QList<gsl::not_null<UserData*>> *lastAuthors = nullptr;
OrderedSet<gsl::not_null<PeerData*>> *markupSenders = nullptr;
if (peer->isChat()) {
lastAuthors = &peer->asChat()->lastAuthors;
markupSenders = &peer->asChat()->markupSenders;

View File

@ -795,11 +795,18 @@ bool HistoryItem::canEdit(const QDateTime &cur) const {
return false;
}
}
if (out() || messageToMyself) {
if (messageToMyself) {
return true;
}
if (auto channel = _history->peer->asChannel()) {
return channel->canDeleteMessages();
if (channel->canEditMessages()) {
return true;
}
if (out()) {
return !isPost() || channel->canPublish();
}
} else {
return out();
}
}
return false;
@ -814,16 +821,13 @@ bool HistoryItem::canDelete() const {
if (id == 1) {
return false;
}
if (channel->amCreator()) {
if (channel->canDeleteMessages()) {
return true;
}
if (isPost()) {
if (out()) {
return true;
}
return false;
if (out() && toHistoryMessage()) {
return isPost() ? channel->canPublish() : true;
}
return (channel->canDeleteMessages() || out());
return false;
}
bool HistoryItem::canDeleteForEveryone(const QDateTime &cur) const {
@ -857,10 +861,11 @@ bool HistoryItem::canDeleteForEveryone(const QDateTime &cur) const {
bool HistoryItem::suggestBanReport() const {
auto channel = history()->peer->asChannel();
if (!channel || !channel->canBanMembers()) {
auto fromUser = from()->asUser();
if (!channel || !fromUser || !channel->canRestrictUser(fromUser)) {
return false;
}
return !isPost() && !out() && from()->isUser() && toHistoryMessage();
return !isPost() && !out() && toHistoryMessage();
}
bool HistoryItem::suggestDeleteAllReport() const {

View File

@ -4111,7 +4111,7 @@ void HistoryWidget::updateOnlineDisplayTimer() {
ChatData *chat = _peer->asChat();
if (chat->participants.isEmpty()) return;
for (ChatData::Participants::const_iterator i = chat->participants.cbegin(), e = chat->participants.cend(); i != e; ++i) {
for (auto i = chat->participants.cbegin(), e = chat->participants.cend(); i != e; ++i) {
int32 onlineWillChangeIn = App::onlineWillChangeIn(i.key(), t);
if (onlineWillChangeIn < minIn) {
minIn = onlineWillChangeIn;

View File

@ -1226,7 +1226,7 @@ void MainWidget::clearHistory(PeerData *peer) {
MTP::send(MTPmessages_DeleteHistory(MTP_flags(flags), peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, request));
}
void MainWidget::addParticipants(PeerData *chatOrChannel, const QVector<UserData*> &users) {
void MainWidget::addParticipants(PeerData *chatOrChannel, const std::vector<gsl::not_null<UserData*>> &users) {
if (chatOrChannel->isChat()) {
auto chat = chatOrChannel->asChat();
for_const (auto user, users) {
@ -1234,8 +1234,8 @@ void MainWidget::addParticipants(PeerData *chatOrChannel, const QVector<UserData
}
} else if (chatOrChannel->isChannel()) {
QVector<MTPInputUser> inputUsers;
inputUsers.reserve(qMin(users.size(), int(MaxUsersPerInvite)));
for (QVector<UserData*>::const_iterator i = users.cbegin(), e = users.cend(); i != e; ++i) {
inputUsers.reserve(qMin(int(users.size()), int(MaxUsersPerInvite)));
for (auto i = users.cbegin(), e = users.cend(); i != e; ++i) {
inputUsers.push_back((*i)->inputUser);
if (inputUsers.size() == MaxUsersPerInvite) {
MTP::send(MTPchannels_InviteToChannel(chatOrChannel->asChannel()->inputChannel, MTP_vector<MTPInputUser>(inputUsers)), rpcDone(&MainWidget::inviteToChannelDone, chatOrChannel->asChannel()), rpcFail(&MainWidget::addParticipantsFail, chatOrChannel->asChannel()), 0, 5);

View File

@ -273,7 +273,7 @@ public:
void clearHistory(PeerData *peer);
void deleteAllFromUser(ChannelData *channel, UserData *from);
void addParticipants(PeerData *chatOrChannel, const QVector<UserData*> &users);
void addParticipants(PeerData *chatOrChannel, const std::vector<gsl::not_null<UserData*>> &users);
struct UserAndPeer {
UserData *user;
PeerData *peer;

View File

@ -34,6 +34,8 @@ struct PeerUpdate {
PeerData *peer;
enum class Flag {
None = 0x00000000U,
// Common flags
NameChanged = 0x00000001U,
UsernameChanged = 0x00000002U,
@ -66,11 +68,7 @@ struct PeerUpdate {
// For channels
ChannelAmIn = 0x00010000U,
ChannelAmEditor = 0x00020000U,
ChannelCanEditInformation = 0x00040000U,
ChannelCanAddMembers = 0x00080000U,
ChannelCanViewAdmins = 0x00100000U,
ChannelCanViewMembers = 0x00200000U,
ChannelRightsChanged = 0x00020000U,
};
Q_DECLARE_FLAGS(Flags, Flag);
Flags flags = 0;

View File

@ -31,8 +31,7 @@ namespace Profile {
using UpdateFlag = Notify::PeerUpdate::Flag;
ChannelMembersWidget::ChannelMembersWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_participants_section)) {
auto observeEvents = UpdateFlag::ChannelCanViewAdmins
| UpdateFlag::ChannelCanViewMembers
auto observeEvents = UpdateFlag::ChannelRightsChanged
| UpdateFlag::AdminsChanged
| UpdateFlag::MembersChanged;
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
@ -47,10 +46,10 @@ void ChannelMembersWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
return;
}
if (update.flags & (UpdateFlag::ChannelCanViewAdmins | UpdateFlag::AdminsChanged)) {
if (update.flags & (UpdateFlag::ChannelRightsChanged | UpdateFlag::AdminsChanged)) {
refreshAdmins();
}
if (update.flags & (UpdateFlag::ChannelCanViewMembers | UpdateFlag::MembersChanged)) {
if (update.flags & (UpdateFlag::ChannelRightsChanged | UpdateFlag::MembersChanged)) {
refreshMembers();
}
refreshVisibility();

View File

@ -67,41 +67,35 @@ GroupMembersWidget::GroupMembersWidget(QWidget *parent, PeerData *peer, TitleVis
refreshMembers();
}
void GroupMembersWidget::addAdmin(gsl::not_null<UserData*> user) {
void GroupMembersWidget::editAdmin(gsl::not_null<UserData*> user) {
auto megagroup = peer()->asMegagroup();
if (!megagroup) {
return; // not supported
}
auto currentRights = megagroup->mgInfo->lastAdmins.value(user, MTP_channelAdminRights(MTP_flags(0)));
auto defaultAdmin = MegagroupInfo::Admin { EditAdminBox::DefaultRights(megagroup) };
auto currentRights = megagroup->mgInfo->lastAdmins.value(user, defaultAdmin).rights;
Ui::show(Box<EditAdminBox>(megagroup, user, currentRights, base::lambda_guarded(this, [this, megagroup, user](const MTPChannelAdminRights &rights) {
Ui::hideLayer();
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);
megagroup->applyEditAdmin(user, rights);
})));
})));
}
void GroupMembersWidget::removeAdmin(gsl::not_null<UserData*> user) {
auto text = lng_profile_sure_kick_admin(lt_user, user->firstName);
Ui::show(Box<ConfirmBox>(text, lang(lng_box_remove), base::lambda_guarded(this, [this, user] {
void GroupMembersWidget::restrictUser(gsl::not_null<UserData*> user) {
auto megagroup = peer()->asMegagroup();
if (!megagroup) {
return; // not supported
}
auto defaultRestricted = MegagroupInfo::Restricted { EditRestrictedBox::DefaultRights(megagroup) };
auto currentRights = megagroup->mgInfo->lastRestricted.value(user, defaultRestricted).rights;
Ui::show(Box<EditRestrictedBox>(megagroup, user, currentRights, base::lambda_guarded(this, [this, megagroup, user](const MTPChannelBannedRights &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_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);
})));
}
MTP::send(MTPchannels_EditBanned(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->applyEditBanned(user, rights);
})));
})));
}
@ -163,7 +157,7 @@ void GroupMembersWidget::refreshUserOnline(UserData *user) {
void GroupMembersWidget::preloadMore() {
if (auto megagroup = peer()->asMegagroup()) {
auto megagroupInfo = megagroup->mgInfo;
auto &megagroupInfo = megagroup->mgInfo;
if (!megagroupInfo->lastParticipants.isEmpty() && megagroupInfo->lastParticipants.size() < megagroup->membersCount()) {
App::api()->requestLastParticipants(megagroup, false);
}
@ -222,16 +216,22 @@ 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, user] {
addAdmin(user);
}));
} else if (canRemoveAdmin()) {
result->addAction(lang(lng_context_remove_admin), base::lambda_guarded(this, [this, user] {
removeAdmin(user);
}));
}
if (item->hasRemoveLink) {
if (channel) {
if (channel->canEditAdmin(user)) {
auto label = lang(item->hasAdminStar ? lng_context_edit_permissions : lng_context_promote_admin);
result->addAction(label, base::lambda_guarded(this, [this, user] {
editAdmin(user);
}));
}
if (channel->canRestrictUser(user)) {
result->addAction(lang(lng_context_restrict_user), base::lambda_guarded(this, [this, user] {
restrictUser(user);
}));
result->addAction(lang(lng_context_remove_from_group), base::lambda_guarded(this, [this, selectedPeer] {
removePeer(selectedPeer);
}));
}
} else if (item->hasRemoveLink) {
result->addAction(lang(lng_context_remove_from_group), base::lambda_guarded(this, [this, selectedPeer] {
removePeer(selectedPeer);
}));
@ -280,8 +280,7 @@ void GroupMembersWidget::refreshMembers() {
fillChatMembers(chat);
refreshLimitReached();
} else if (auto megagroup = peer()->asMegagroup()) {
checkSelfAdmin(megagroup);
auto megagroupInfo = megagroup->mgInfo;
auto &megagroupInfo = megagroup->mgInfo;
if (megagroupInfo->lastParticipants.isEmpty() || megagroup->lastParticipantsCountOutdated()) {
App::api()->requestLastParticipants(megagroup);
}
@ -324,18 +323,6 @@ void GroupMembersWidget::checkSelfAdmin(ChatData *chat) {
}
}
void GroupMembersWidget::checkSelfAdmin(ChannelData *megagroup) {
if (megagroup->mgInfo->lastParticipants.isEmpty()) return;
auto amAdmin = megagroup->hasAdminRights();
auto self = App::self();
if (amAdmin && !megagroup->mgInfo->lastAdmins.contains(self)) {
megagroup->selfAdminUpdated();
} else if (!amAdmin && megagroup->mgInfo->lastAdmins.contains(self)) {
megagroup->selfAdminUpdated();
}
}
void GroupMembersWidget::sortMembers() {
if (!_sortByOnline || !itemsCount()) return;
@ -470,11 +457,14 @@ bool GroupMembersWidget::addUsersToEnd(ChannelData *megagroup) {
void GroupMembersWidget::setItemFlags(Item *item, ChannelData *megagroup) {
auto amCreatorOrAdmin = item->peer->isSelf() && (megagroup->hasAdminRights() || megagroup->amCreator());
auto isAdmin = megagroup->mgInfo->lastAdmins.contains(getMember(item)->user());
item->hasAdminStar = amCreatorOrAdmin || isAdmin;
auto adminIt = megagroup->mgInfo->lastAdmins.constFind(getMember(item)->user());
auto isAdmin = (adminIt != megagroup->mgInfo->lastAdmins.cend());
auto isCreator = megagroup->mgInfo->creator == item->peer;
auto adminCanEdit = isAdmin && adminIt->canEdit;
item->hasAdminStar = amCreatorOrAdmin || isAdmin || isCreator;
if (item->peer->isSelf()) {
item->hasRemoveLink = false;
} else if (megagroup->amCreator() || (megagroup->canBanMembers() && !item->hasAdminStar)) {
} else if (megagroup->amCreator() || (megagroup->canBanMembers() && (!item->hasAdminStar || adminCanEdit))) {
item->hasRemoveLink = true;
} else {
item->hasRemoveLink = false;

View File

@ -67,8 +67,8 @@ private:
// Observed notifications.
void notifyPeerUpdated(const Notify::PeerUpdate &update);
void addAdmin(gsl::not_null<UserData*> user);
void removeAdmin(gsl::not_null<UserData*> user);
void editAdmin(gsl::not_null<UserData*> user);
void restrictUser(gsl::not_null<UserData*> user);
void removePeer(PeerData *selectedPeer);
void refreshMembers();
void fillChatMembers(ChatData *chat);
@ -76,7 +76,6 @@ private:
void sortMembers();
void updateOnlineCount();
void checkSelfAdmin(ChatData *chat);
void checkSelfAdmin(ChannelData *megagroup);
void refreshLimitReached();
void preloadMore();

View File

@ -172,10 +172,7 @@ SettingsWidget::SettingsWidget(QWidget *parent, PeerData *peer) : BlockWidget(pa
observeEvents |= UpdateFlag::ChatCanEdit | UpdateFlag::InviteLinkChanged;
}
} else if (auto channel = peer->asChannel()) {
if (channel->amCreator()) {
observeEvents |= UpdateFlag::UsernameChanged | UpdateFlag::InviteLinkChanged;
}
observeEvents |= UpdateFlag::ChannelAmEditor | UpdateFlag::BlockedUsersChanged;
observeEvents |= UpdateFlag::ChannelRightsChanged | UpdateFlag::BlockedUsersChanged | UpdateFlag::UsernameChanged | UpdateFlag::InviteLinkChanged;
}
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) {
notifyPeerUpdated(update);
@ -195,13 +192,13 @@ void SettingsWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
if (update.flags & UpdateFlag::NotificationsEnabled) {
refreshEnableNotifications();
}
if (update.flags & (UpdateFlag::ChatCanEdit | UpdateFlag::UsernameChanged | UpdateFlag::InviteLinkChanged)) {
if (update.flags & (UpdateFlag::ChannelRightsChanged | UpdateFlag::ChatCanEdit | UpdateFlag::UsernameChanged | UpdateFlag::InviteLinkChanged)) {
refreshInviteLinkButton();
}
if (update.flags & (UpdateFlag::ChatCanEdit)) {
if (update.flags & (UpdateFlag::ChannelRightsChanged | UpdateFlag::ChatCanEdit)) {
refreshManageAdminsButton();
}
if ((update.flags & UpdateFlag::ChannelAmEditor) || (update.flags & UpdateFlag::BlockedUsersChanged)) {
if (update.flags & (UpdateFlag::ChannelRightsChanged | UpdateFlag::BlockedUsersChanged)) {
refreshManageBlockedUsersButton();
}
@ -254,7 +251,7 @@ void SettingsWidget::refreshManageAdminsButton() {
if (auto chat = peer()->asChat()) {
return (chat->amCreator() && chat->canEdit());
} else if (auto channel = peer()->asMegagroup()) {
return channel->amCreator();
return channel->hasAdminRights() || channel->amCreator();
}
return false;
};
@ -269,7 +266,7 @@ void SettingsWidget::refreshManageAdminsButton() {
void SettingsWidget::refreshManageBlockedUsersButton() {
auto hasManageBlockedUsers = [this] {
if (auto channel = peer()->asMegagroup()) {
return channel->canBanMembers() && (channel->kickedCount() > 0);
return channel->canBanMembers() && (channel->kickedCount() > 0 || channel->restrictedCount() > 0);
}
return false;
};
@ -288,7 +285,7 @@ void SettingsWidget::refreshInviteLinkButton() {
return lang(chat->inviteLink().isEmpty() ? lng_group_invite_create : lng_group_invite_create_new);
}
} else if (auto channel = peer()->asChannel()) {
if (channel->amCreator() && !channel->isPublic()) {
if (channel->canHaveInviteLink() && !channel->isPublic()) {
return lang(channel->inviteLink().isEmpty() ? lng_group_invite_create : lng_group_invite_create_new);
}
}

View File

@ -45,8 +45,7 @@ using UpdateFlag = Notify::PeerUpdate::Flag;
const auto ButtonsUpdateFlags = UpdateFlag::UserCanShareContact
| UpdateFlag::BotCanAddToGroups
| UpdateFlag::ChatCanEdit
| UpdateFlag::ChannelCanEditInformation
| UpdateFlag::ChannelCanAddMembers
| UpdateFlag::ChannelRightsChanged
| UpdateFlag::ChannelAmIn;
} // namespace
@ -437,7 +436,7 @@ void CoverWidget::setChatButtons() {
void CoverWidget::setMegagroupButtons() {
if (_peerMegagroup->amIn()) {
if (_peerMegagroup->canEditInformation()) {
if (canEditPhoto()) {
addButton(langFactory(lng_profile_set_group_photo), SLOT(onSetPhoto()));
}
} else {
@ -449,7 +448,7 @@ void CoverWidget::setMegagroupButtons() {
}
void CoverWidget::setChannelButtons() {
if (_peerChannel->amCreator()) {
if (canEditPhoto()) {
addButton(langFactory(lng_profile_set_group_photo), SLOT(onSetPhoto()));
} else if (_peerChannel->amIn()) {
addButton(langFactory(lng_profile_view_channel), SLOT(onViewChannel()));

View File

@ -38,7 +38,7 @@ using UpdateFlag = Notify::PeerUpdate::Flag;
const auto ButtonsUpdateFlags = UpdateFlag::UserCanShareContact
| UpdateFlag::UserIsContact
| UpdateFlag::ChatCanEdit
| UpdateFlag::ChannelAmEditor;
| UpdateFlag::ChannelRightsChanged;
} // namespace
@ -117,13 +117,13 @@ void FixedBar::setChatActions() {
}
void FixedBar::setMegagroupActions() {
if (_peerMegagroup->amCreator() || _peerMegagroup->canEditInformation()) {
if (_peerMegagroup->canEditInformation()) {
addRightAction(RightActionType::EditChannel, langFactory(lng_profile_edit_contact), SLOT(onEditChannel()));
}
}
void FixedBar::setChannelActions() {
if (_peerChannel->amCreator()) {
if (_peerChannel->canEditInformation()) {
addRightAction(RightActionType::EditChannel, langFactory(lng_profile_edit_contact), SLOT(onEditChannel()));
}
}

View File

@ -647,10 +647,10 @@ void ChatData::setName(const QString &newName) {
void ChatData::invalidateParticipants() {
auto wasCanEdit = canEdit();
participants = ChatData::Participants();
admins = ChatData::Admins();
participants.clear();
admins.clear();
flags &= ~MTPDchat::Flag::f_admin;
invitedByMe = ChatData::InvitedByMe();
invitedByMe.clear();
botStatus = 0;
if (wasCanEdit != canEdit()) {
Notify::peerUpdatedDelayed(this, Notify::PeerUpdate::Flag::ChatCanEdit);
@ -748,6 +748,13 @@ void ChannelData::setAdminsCount(int newAdminsCount) {
}
}
void ChannelData::setRestrictedCount(int newRestrictedCount) {
if (_restrictedCount != newRestrictedCount) {
_restrictedCount = newRestrictedCount;
Notify::peerUpdatedDelayed(this, Notify::PeerUpdate::Flag::BlockedUsersChanged);
}
}
void ChannelData::setKickedCount(int newKickedCount) {
if (_kickedCount != newKickedCount) {
_kickedCount = newKickedCount;
@ -755,29 +762,187 @@ void ChannelData::setKickedCount(int newKickedCount) {
}
}
MTPChannelBannedRights ChannelData::KickedRestrictedRights() {
using Flag = MTPDchannelBannedRights::Flag;
auto flags = Flag::f_view_messages | Flag::f_send_messages | Flag::f_send_media | Flag::f_embed_links | Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline;
return MTP_channelBannedRights(MTP_flags(flags), MTP_int(std::numeric_limits<int32>::max()));
}
void ChannelData::applyEditAdmin(gsl::not_null<UserData*> user, const MTPChannelAdminRights &rights) {
auto flags = Notify::PeerUpdate::Flag::AdminsChanged | Notify::PeerUpdate::Flag::None;
if (mgInfo) {
if (!mgInfo->lastParticipants.contains(user)) { // If rights are empty - still add participant? TODO check
mgInfo->lastParticipants.push_front(user);
setMembersCount(membersCount() + 1);
if (user->botInfo && !mgInfo->bots.contains(user)) {
mgInfo->bots.insert(user);
if (mgInfo->botStatus != 0 && mgInfo->botStatus < 2) {
mgInfo->botStatus = 2;
}
}
}
if (mgInfo->lastRestricted.contains(user)) { // If rights are empty - still remove restrictions? TODO check
mgInfo->lastRestricted.remove(user);
if (restrictedCount() > 0) {
setRestrictedCount(restrictedCount() - 1);
}
}
auto it = mgInfo->lastAdmins.find(user);
if (rights.c_channelAdminRights().vflags.v != 0) {
auto lastAdmin = MegagroupInfo::Admin { rights };
lastAdmin.canEdit = true;
if (it == mgInfo->lastAdmins.cend()) {
mgInfo->lastAdmins.insert(user, lastAdmin);
setAdminsCount(adminsCount() + 1);
} else {
it.value() = lastAdmin;
}
} else {
if (it != mgInfo->lastAdmins.cend()) {
mgInfo->lastAdmins.erase(it);
if (adminsCount() > 0) {
setAdminsCount(adminsCount() - 1);
}
}
}
}
Notify::peerUpdatedDelayed(this, flags);
}
void ChannelData::applyEditBanned(gsl::not_null<UserData*> user, const MTPChannelBannedRights &rights) {
auto flags = Notify::PeerUpdate::Flag::BlockedUsersChanged | Notify::PeerUpdate::Flag::None;
if (mgInfo) {
if (mgInfo->lastAdmins.contains(user)) { // If rights are empty - still remove admin? TODO check
mgInfo->lastAdmins.remove(user);
if (adminsCount() > 1) {
setAdminsCount(adminsCount() - 1);
} else {
flags |= Notify::PeerUpdate::Flag::AdminsChanged;
}
}
auto isKicked = (rights.c_channelBannedRights().vflags.v & MTPDchannelBannedRights::Flag::f_view_messages);
auto isRestricted = !isKicked && (rights.c_channelBannedRights().vflags.v != 0);
auto it = mgInfo->lastRestricted.find(user);
if (isRestricted) {
if (it == mgInfo->lastRestricted.cend()) {
mgInfo->lastRestricted.insert(user, MegagroupInfo::Restricted { rights });
setRestrictedCount(restrictedCount() + 1);
} else {
it->rights = rights;
}
} else {
if (it != mgInfo->lastRestricted.cend()) {
mgInfo->lastRestricted.erase(it);
if (restrictedCount() > 0) {
setRestrictedCount(restrictedCount() - 1);
}
}
if (isKicked) {
auto i = mgInfo->lastParticipants.indexOf(user);
if (i >= 0) {
mgInfo->lastParticipants.removeAt(i);
}
if (membersCount() > 1) {
setMembersCount(membersCount() - 1);
} else {
mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsCountOutdated;
mgInfo->lastParticipantsCount = 0;
}
setKickedCount(kickedCount() + 1);
if (mgInfo->bots.contains(user)) {
mgInfo->bots.remove(user);
if (mgInfo->bots.isEmpty() && mgInfo->botStatus > 0) {
mgInfo->botStatus = -1;
}
}
flags |= Notify::PeerUpdate::Flag::MembersChanged;
}
}
}
Notify::peerUpdatedDelayed(this, flags);
}
void ChannelData::flagsUpdated() {
if (isMegagroup()) {
if (!mgInfo) {
mgInfo = new MegagroupInfo();
mgInfo = std::make_unique<MegagroupInfo>();
}
} else if (mgInfo) {
delete mgInfo;
mgInfo = nullptr;
}
}
void ChannelData::selfAdminUpdated() {
bool ChannelData::canNotEditLastAdmin(gsl::not_null<UserData*> user) const {
if (mgInfo) {
auto i = mgInfo->lastAdmins.constFind(user);
if (i != mgInfo->lastAdmins.cend()) {
return !i->canEdit;
}
return (user == mgInfo->creator);
}
return false;
}
bool ChannelData::canEditAdmin(gsl::not_null<UserData*> user) const {
if (user->isSelf()) {
return false;
} else if (amCreator()) {
return true;
} else if (canNotEditLastAdmin(user)) {
return false;
}
return adminRights().is_add_admins();
}
bool ChannelData::canRestrictUser(gsl::not_null<UserData*> user) const {
if (user->isSelf()) {
return false;
} else if (amCreator()) {
return true;
} else if (canNotEditLastAdmin(user)) {
return false;
}
return adminRights().is_ban_users();
}
void ChannelData::setAdminRights(const MTPChannelAdminRights &rights) {
if (rights.c_channelAdminRights().vflags.v == _adminRights.c_channelAdminRights().vflags.v) {
return;
}
_adminRights = rights;
if (isMegagroup()) {
if (hasAdminRights()) {
mgInfo->lastAdmins.insert(App::self(), _adminRights);
if (!amCreator()) {
auto me = MegagroupInfo::Admin { _adminRights };
me.canEdit = false;
mgInfo->lastAdmins.insert(App::self(), me);
}
mgInfo->lastRestricted.remove(App::self());
} else {
mgInfo->lastAdmins.remove(App::self());
}
}
Notify::peerUpdatedDelayed(this, UpdateFlag::ChannelRightsChanged | UpdateFlag::AdminsChanged | UpdateFlag::BlockedUsersChanged);
}
ChannelData::~ChannelData() {
delete mgInfo;
void ChannelData::setRestrictedRights(const MTPChannelBannedRights &rights) {
if (rights.c_channelBannedRights().vflags.v == _restrictedRights.c_channelBannedRights().vflags.v
&& rights.c_channelBannedRights().vuntil_date.v == _restrictedRights.c_channelBannedRights().vuntil_date.v) {
return;
}
_restrictedRights = rights;
if (isMegagroup()) {
if (hasRestrictedRights()) {
if (!amCreator()) {
auto me = MegagroupInfo::Restricted { _restrictedRights };
mgInfo->lastRestricted.insert(App::self(), me);
}
mgInfo->lastAdmins.remove(App::self());
} else {
mgInfo->lastRestricted.remove(App::self());
}
}
Notify::peerUpdatedDelayed(this, UpdateFlag::ChannelRightsChanged | UpdateFlag::AdminsChanged | UpdateFlag::BlockedUsersChanged);
}
uint64 PtsWaiter::ptsKey(PtsSkippedQueue queue) {

View File

@ -619,16 +619,11 @@ public:
bool isMigrated() const {
return flags & MTPDchat::Flag::f_migrated_to;
}
typedef QMap<UserData*, int> Participants;
Participants participants;
typedef OrderedSet<UserData*> InvitedByMe;
InvitedByMe invitedByMe;
typedef OrderedSet<UserData*> Admins;
Admins admins;
typedef QList<UserData*> LastAuthors;
LastAuthors lastAuthors;
typedef OrderedSet<PeerData*> MarkupSenders;
MarkupSenders markupSenders;
QMap<gsl::not_null<UserData*>, int> participants;
OrderedSet<gsl::not_null<UserData*>> invitedByMe;
OrderedSet<gsl::not_null<UserData*>> admins;
QList<gsl::not_null<UserData*>> lastAuthors;
OrderedSet<gsl::not_null<PeerData*>> markupSenders;
int botStatus = 0; // -1 - no bots, 0 - unknown, 1 - one bot, that sees all history, 2 - other
// ImagePtr photoFull;
@ -705,14 +700,26 @@ private:
};
struct MegagroupInfo {
typedef QList<UserData*> LastParticipants;
LastParticipants lastParticipants;
QMap<UserData*, MTPChannelAdminRights> lastAdmins;
typedef OrderedSet<PeerData*> MarkupSenders;
MarkupSenders markupSenders;
typedef OrderedSet<UserData*> Bots;
Bots bots;
struct Admin {
explicit Admin(MTPChannelAdminRights rights) : rights(rights) {
}
Admin(MTPChannelAdminRights rights, bool canEdit) : rights(rights), canEdit(canEdit) {
}
MTPChannelAdminRights rights;
bool canEdit = false;
};
struct Restricted {
explicit Restricted(MTPChannelBannedRights rights) : rights(rights) {
}
MTPChannelBannedRights rights;
};
QList<gsl::not_null<UserData*>> lastParticipants;
QMap<gsl::not_null<UserData*>, Admin> lastAdmins;
QMap<gsl::not_null<UserData*>, Restricted> lastRestricted;
OrderedSet<gsl::not_null<PeerData*>> markupSenders;
OrderedSet<gsl::not_null<UserData*>> bots;
UserData *creator = nullptr; // nullptr means unknown
int botStatus = 0; // -1 - no bots, 0 - unknown, 1 - one bot, that sees all history, 2 - other
MsgId pinnedMsgId = 0;
bool joinedMessageFound = false;
@ -764,6 +771,11 @@ public:
}
void setAdminsCount(int newAdminsCount);
int restrictedCount() const {
return _restrictedCount;
}
void setRestrictedCount(int newRestrictedCount);
int kickedCount() const {
return _kickedCount;
}
@ -788,11 +800,15 @@ public:
return flags & MTPDchannel::Flag::f_verified;
}
static MTPChannelBannedRights KickedRestrictedRights();
void applyEditAdmin(gsl::not_null<UserData*> user, const MTPChannelAdminRights &rights);
void applyEditBanned(gsl::not_null<UserData*> user, const MTPChannelBannedRights &rights);
int32 date = 0;
int version = 0;
MTPDchannel::Flags flags = { 0 };
MTPDchannelFull::Flags flagsFull = { 0 };
MegagroupInfo *mgInfo = nullptr;
std::unique_ptr<MegagroupInfo> mgInfo;
bool lastParticipantsCountOutdated() const {
if (!mgInfo || !(mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsCountOutdated)) {
return false;
@ -804,7 +820,6 @@ public:
return true;
}
void flagsUpdated();
void selfAdminUpdated();
bool isMegagroup() const {
return flags & MTPDchannel::Flag::f_megagroup;
}
@ -817,39 +832,44 @@ public:
bool amCreator() const {
return flags & MTPDchannel::Flag::f_creator;
}
bool amEditor() const {
return hasAdminRights();
const MTPChannelAdminRights &adminRightsBoxed() const {
return _adminRights;
}
const MTPDchannelAdminRights &adminRights() const {
return _adminRights.c_channelAdminRights();
}
void setAdminRights(const MTPChannelAdminRights &rights) {
_adminRights = rights;
}
void setAdminRights(const MTPChannelAdminRights &rights);
bool hasAdminRights() const {
return (adminRights().vflags.v != 0);
}
const MTPDchannelBannedRights &bannedRights() const {
return _bannedRights.c_channelBannedRights();
const MTPChannelBannedRights &restrictedRightsBoxed() const {
return _restrictedRights;
}
void setBannedRights(const MTPChannelBannedRights &rights) {
_bannedRights = rights;
const MTPDchannelBannedRights &restrictedRights() const {
return _restrictedRights.c_channelBannedRights();
}
bool hasBannedRights() const {
return (bannedRights().vflags.v != 0);
void setRestrictedRights(const MTPChannelBannedRights &rights);
bool hasRestrictedRights() const {
return (restrictedRights().vflags.v != 0);
}
bool hasBannedRights(int32 now) const {
return hasBannedRights() && (bannedRights().vuntil_date.v > now);
bool hasRestrictedRights(int32 now) const {
return hasRestrictedRights() && (restrictedRights().vuntil_date.v > now);
}
bool canBanMembers() const {
return adminRights().is_ban_users() || amCreator();
}
bool canEditMessages() const {
return adminRights().is_edit_messages() || amCreator();
}
bool canDeleteMessages() const {
return adminRights().is_delete_messages() || amCreator();
}
bool canAddMembers() const {
return adminRights().is_invite_users() || amCreator() || (amIn() && (flags & MTPDchannel::Flag::f_democracy));
}
bool canAddAdmins() const {
return adminRights().is_add_admins() || amCreator();
}
bool canPinMessages() const {
return adminRights().is_pin_messages() || amCreator();
}
@ -857,7 +877,7 @@ public:
return adminRights().is_post_messages() || amCreator();
}
bool canWrite() const {
return amIn() && (canPublish() || !isBroadcast());
return amIn() && (canPublish() || (!isBroadcast() && !restrictedRights().is_send_messages()));
}
bool canViewMembers() const {
return flagsFull & MTPDchannelFull::Flag::f_can_view_participants;
@ -875,11 +895,16 @@ public:
constexpr auto kDeleteChannelMembersLimit = 1000;
return amCreator() && (membersCount() <= kDeleteChannelMembersLimit);
}
bool canEditAdmin(gsl::not_null<UserData*> user) const;
bool canRestrictUser(gsl::not_null<UserData*> user) const;
void setInviteLink(const QString &newInviteLink);
QString inviteLink() const {
return _inviteLink;
}
bool canHaveInviteLink() const {
return adminRights().is_invite_link() || amCreator();
}
int32 inviter = 0; // > 0 - user who invited me to channel, < 0 - not in channel
QDateTime inviteDate;
@ -930,19 +955,20 @@ public:
_restrictionReason = reason;
}
~ChannelData();
private:
bool canNotEditLastAdmin(gsl::not_null<UserData*> user) const;
PtsWaiter _ptsWaiter;
TimeMs _lastFullUpdate = 0;
bool _isForbidden = true;
int _membersCount = 1;
int _adminsCount = 1;
int _restrictedCount = 0;
int _kickedCount = 0;
MTPChannelAdminRights _adminRights = MTP_channelAdminRights(MTP_flags(0));
MTPChannelBannedRights _bannedRights = MTP_channelBannedRights(MTP_flags(0), MTP_int(0));
MTPChannelBannedRights _restrictedRights = MTP_channelBannedRights(MTP_flags(0), MTP_int(0));
QString _restrictionReason;
QString _about;