Support legacy groups in participant boxes.

This commit is contained in:
John Preston 2019-01-10 10:26:08 +04:00
parent 18c6be0d3b
commit a605c110a8
39 changed files with 3064 additions and 2649 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -811,6 +811,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_report_thanks" = "Thank you! Your report will be reviewed by our team very soon.";
"lng_channel_add_members" = "Add members";
"lng_channel_add_users" = "Add users";
"lng_channel_add_banned" = "Ban user";
"lng_channel_add_restricted" = "Restrict user";
"lng_channel_admins" = "Administrators";
@ -1510,6 +1511,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_restricted_send_stickers" = "The admins of this group restricted you from posting stickers here.";
"lng_restricted_send_gifs" = "The admins of this group restricted you from posting GIFs here.";
"lng_restricted_send_inline" = "The admins of this group restricted you from posting inline content here.";
"lng_restricted_send_polls" = "The admins of this group restricted you from posting polls here.";
"lng_restricted_list_title" = "Restricted users";
"lng_banned_list_title" = "Banned users";

View File

@ -3683,119 +3683,6 @@ void ApiWrap::addChatParticipants(
}
}
void ApiWrap::cancelEditChatAdmins(not_null<ChatData*> chat) {
_chatAdminsEnabledRequests.take(
chat
) | requestCanceller();
_chatAdminsSaveRequests.take(
chat
) | [&](auto &&requests) {
ranges::for_each(std::move(requests), requestCanceller());
};
_chatAdminsToSave.remove(chat);
}
void ApiWrap::editChatAdmins(
not_null<ChatData*> chat,
bool adminsEnabled,
base::flat_set<not_null<UserData*>> &&admins) {
cancelEditChatAdmins(chat);
if (adminsEnabled) {
_chatAdminsToSave.emplace(chat, std::move(admins));
}
// #TODO groups
//auto requestId = request(MTPmessages_ToggleChatAdmins(chat->inputChat, MTP_bool(adminsEnabled))).done([this, chat](const MTPUpdates &updates) {
// _chatAdminsEnabledRequests.remove(chat);
// applyUpdates(updates);
// saveChatAdmins(chat);
//}).fail([this, chat](const RPCError &error) {
// _chatAdminsEnabledRequests.remove(chat);
// if (error.type() == qstr("CHAT_NOT_MODIFIED")) {
// saveChatAdmins(chat);
// }
//}).send();
//_chatAdminsEnabledRequests.emplace(chat, requestId);
}
void ApiWrap::saveChatAdmins(not_null<ChatData*> chat) {
if (!_chatAdminsToSave.contains(chat)) {
return;
}
auto requestId = request(MTPmessages_GetFullChat(chat->inputChat)).done([this, chat](const MTPmessages_ChatFull &result) {
_chatAdminsEnabledRequests.remove(chat);
processFullPeer(chat, result);
sendSaveChatAdminsRequests(chat);
}).fail([this, chat](const RPCError &error) {
_chatAdminsEnabledRequests.remove(chat);
_chatAdminsToSave.remove(chat);
}).send();
_chatAdminsEnabledRequests.emplace(chat, requestId);
}
void ApiWrap::sendSaveChatAdminsRequests(not_null<ChatData*> chat) {
auto editOne = [this, chat](not_null<UserData*> user, bool admin) {
auto requestId = request(MTPmessages_EditChatAdmin(
chat->inputChat,
user->inputUser,
MTP_bool(admin)))
.done([this, chat, user, admin](
const MTPBool &result,
mtpRequestId requestId) {
_chatAdminsSaveRequests[chat].remove(requestId);
if (_chatAdminsSaveRequests[chat].empty()) {
_chatAdminsSaveRequests.remove(chat);
Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::AdminsChanged);
}
if (mtpIsTrue(result)) {
if (admin) {
if (chat->noParticipantInfo()) {
requestFullPeer(chat);
} else {
chat->admins.insert(user);
}
} else {
chat->admins.remove(user);
}
}
}).fail([this, chat](
const RPCError &error,
mtpRequestId requestId) {
_chatAdminsSaveRequests[chat].remove(requestId);
if (_chatAdminsSaveRequests[chat].empty()) {
_chatAdminsSaveRequests.remove(chat);
}
chat->invalidateParticipants();
if (error.type() == qstr("USER_RESTRICTED")) {
Ui::show(Box<InformBox>(lang(lng_cant_do_this)));
}
}).afterDelay(kSmallDelayMs).send();
_chatAdminsSaveRequests[chat].insert(requestId);
};
auto appointOne = [&](auto user) { editOne(user, true); };
auto removeOne = [&](auto user) { editOne(user, false); };
auto admins = _chatAdminsToSave.take(chat);
Assert(!!admins);
auto toRemove = chat->admins;
auto toAppoint = std::vector<not_null<UserData*>>();
if (!admins->empty()) {
toAppoint.reserve(admins->size());
for (auto user : *admins) {
if (!toRemove.remove(user) && user->id != peerFromUser(chat->creator)) {
toAppoint.push_back(user);
}
}
}
ranges::for_each(toRemove, removeOne);
ranges::for_each(toAppoint, appointOne);
requestSendDelayed();
}
void ApiWrap::requestSharedMediaCount(
not_null<PeerData*> peer,
Storage::SharedMediaType type) {

View File

@ -66,7 +66,7 @@ inline int32 CountHash(IntRange &&range) {
} // namespace Api
class ApiWrap : private MTP::Sender, private base::Subscriber {
class ApiWrap : public MTP::Sender, private base::Subscriber {
public:
ApiWrap(not_null<AuthSession*> session);
@ -221,12 +221,9 @@ public:
void jumpToDate(Dialogs::Key chat, const QDate &date);
void preloadEnoughUnreadMentions(not_null<History*> history);
void checkForUnreadMentions(const base::flat_set<MsgId> &possiblyReadMentions, ChannelData *channel = nullptr);
void editChatAdmins(
not_null<ChatData*> chat,
bool adminsEnabled,
base::flat_set<not_null<UserData*>> &&admins);
void checkForUnreadMentions(
const base::flat_set<MsgId> &possiblyReadMentions,
ChannelData *channel = nullptr);
using SliceType = Data::LoadDirection;
void requestSharedMedia(
@ -490,9 +487,6 @@ private:
void requestSavedGifs(TimeId now);
void readFeaturedSets();
void cancelEditChatAdmins(not_null<ChatData*> chat);
void saveChatAdmins(not_null<ChatData*> chat);
void sendSaveChatAdminsRequests(not_null<ChatData*> chat);
void refreshChannelAdmins(
not_null<ChannelData*> channel,
const QVector<MTPChannelParticipant> &participants);
@ -673,16 +667,6 @@ private:
base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests;
base::flat_map<
not_null<ChatData*>,
mtpRequestId> _chatAdminsEnabledRequests;
base::flat_map<
not_null<ChatData*>,
base::flat_set<not_null<UserData*>>> _chatAdminsToSave;
base::flat_map<
not_null<ChatData*>,
base::flat_set<mtpRequestId>> _chatAdminsSaveRequests;
base::flat_map<std::tuple<
not_null<PeerData*>,
SharedMediaType,

View File

@ -16,9 +16,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/confirm_box.h"
#include "boxes/photo_crop_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/add_participants_box.h"
#include "boxes/peers/edit_participant_box.h"
#include "boxes/peers/edit_participants_box.h"
#include "core/file_utilities.h"
#include "profile/profile_channel_controllers.h"
#include "chat_helpers/emoji_suggestions_widget.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/buttons.h"
@ -91,7 +92,7 @@ void ShowAddParticipantsError(
(*weak)->closeBox();
}
};
const auto saveCallback = Profile::SaveAdminCallback(
const auto saveCallback = SaveAdminCallback(
channel,
user,
[=](auto&&...) { close(); },

View File

@ -25,26 +25,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
base::flat_set<not_null<UserData*>> GetAlreadyInFromPeer(PeerData *peer) {
if (!peer) {
return {};
}
if (auto chat = peer->asChat()) {
auto participants = (
chat->participants
) | ranges::view::transform([](auto &&pair) -> not_null<UserData*> {
return pair.first;
});
return { participants.begin(), participants.end() };
} else if (auto channel = peer->asChannel()) {
if (channel->isMegagroup()) {
auto &participants = channel->mgInfo->lastParticipants;
return { participants.cbegin(), participants.cend() };
}
}
return {};
}
void ShareBotGame(not_null<UserData*> bot, not_null<PeerData*> chat) {
const auto history = App::historyLoaded(chat);
const auto randomId = rand_value<uint64>();
@ -83,25 +63,6 @@ void AddBotToGroup(not_null<UserData*> bot, not_null<PeerData*> chat) {
Ui::showPeerHistory(chat, ShowAtUnreadMsgId);
}
bool InviteSelectedUsers(
not_null<PeerListBox*> box,
not_null<PeerData*> chat) {
const auto rows = box->peerListCollectSelectedRows();
const auto users = ranges::view::all(
rows
) | ranges::view::transform([](not_null<PeerData*> peer) {
Expects(peer->isUser());
Expects(!peer->isSelf());
return not_null<UserData*>(peer->asUser());
}) | ranges::to_vector;
if (users.empty()) {
return false;
}
Auth().api().addChatParticipants(chat, users);
return true;
}
} // namespace
// Not used for now.
@ -421,142 +382,6 @@ std::unique_ptr<PeerListRow> ContactsBoxController::createRow(not_null<UserData*
return std::make_unique<PeerListRow>(user);
}
AddParticipantsBoxController::AddParticipantsBoxController(PeerData *peer)
: ContactsBoxController(std::make_unique<PeerListGlobalSearchController>())
, _peer(peer)
, _alreadyIn(GetAlreadyInFromPeer(peer)) {
}
AddParticipantsBoxController::AddParticipantsBoxController(
not_null<ChannelData*> channel,
base::flat_set<not_null<UserData*>> &&alreadyIn)
: ContactsBoxController(std::make_unique<PeerListGlobalSearchController>())
, _peer(channel)
, _alreadyIn(std::move(alreadyIn)) {
}
void AddParticipantsBoxController::rowClicked(not_null<PeerListRow*> row) {
auto count = fullCount();
auto limit = (_peer && _peer->isMegagroup()) ? Global::MegagroupSizeMax() : Global::ChatSizeMax();
if (count < limit || row->checked()) {
delegate()->peerListSetRowChecked(row, !row->checked());
updateTitle();
} else if (auto channel = _peer ? _peer->asChannel() : nullptr) {
if (!_peer->isMegagroup()) {
Ui::show(
Box<MaxInviteBox>(_peer->asChannel()),
LayerOption::KeepOther);
}
} else if (count >= Global::ChatSizeMax() && count < Global::MegagroupSizeMax()) {
Ui::show(
Box<InformBox>(lng_profile_add_more_after_upgrade(lt_count, Global::MegagroupSizeMax())),
LayerOption::KeepOther);
}
}
void AddParticipantsBoxController::itemDeselectedHook(not_null<PeerData*> peer) {
updateTitle();
}
void AddParticipantsBoxController::prepareViewHook() {
updateTitle();
}
int AddParticipantsBoxController::alreadyInCount() const {
if (!_peer) {
return 1; // self
}
if (auto chat = _peer->asChat()) {
return qMax(chat->count, 1);
} else if (auto channel = _peer->asChannel()) {
return qMax(channel->membersCount(), int(_alreadyIn.size()));
}
Unexpected("User in AddParticipantsBoxController::alreadyInCount");
}
bool AddParticipantsBoxController::isAlreadyIn(not_null<UserData*> user) const {
if (!_peer) {
return false;
}
if (auto chat = _peer->asChat()) {
return chat->participants.contains(user);
} else if (auto channel = _peer->asChannel()) {
return _alreadyIn.contains(user)
|| (channel->isMegagroup() && base::contains(channel->mgInfo->lastParticipants, user));
}
Unexpected("User in AddParticipantsBoxController::isAlreadyIn");
}
int AddParticipantsBoxController::fullCount() const {
return alreadyInCount() + delegate()->peerListSelectedRowsCount();
}
std::unique_ptr<PeerListRow> AddParticipantsBoxController::createRow(not_null<UserData*> user) {
if (user->isSelf()) {
return nullptr;
}
auto result = std::make_unique<PeerListRow>(user);
if (isAlreadyIn(user)) {
result->setDisabledState(PeerListRow::State::DisabledChecked);
}
return result;
}
void AddParticipantsBoxController::updateTitle() {
auto additional = (_peer && _peer->isChannel() && !_peer->isMegagroup())
? QString() :
QString("%1 / %2").arg(fullCount()).arg(Global::MegagroupSizeMax());
delegate()->peerListSetTitle(langFactory(lng_profile_add_participant));
delegate()->peerListSetAdditionalTitle([additional] { return additional; });
}
void AddParticipantsBoxController::Start(not_null<ChatData*> chat) {
auto initBox = [=](not_null<PeerListBox*> box) {
box->addButton(langFactory(lng_participant_invite), [=] {
if (InviteSelectedUsers(box, chat)) {
Ui::showPeerHistory(chat, ShowAtTheEndMsgId);
}
});
box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); });
};
Ui::show(Box<PeerListBox>(std::make_unique<AddParticipantsBoxController>(chat), std::move(initBox)));
}
void AddParticipantsBoxController::Start(
not_null<ChannelData*> channel,
base::flat_set<not_null<UserData*>> &&alreadyIn,
bool justCreated) {
auto initBox = [channel, justCreated](not_null<PeerListBox*> box) {
auto subscription = std::make_shared<rpl::lifetime>();
box->addButton(langFactory(lng_participant_invite), [=, copy = subscription] {
if (InviteSelectedUsers(box, channel)) {
if (channel->isMegagroup()) {
Ui::showPeerHistory(channel, ShowAtTheEndMsgId);
} else {
box->closeBox();
}
}
});
box->addButton(langFactory(justCreated ? lng_create_group_skip : lng_cancel), [box] { box->closeBox(); });
if (justCreated) {
box->boxClosing() | rpl::start_with_next([=] {
Ui::showPeerHistory(channel, ShowAtTheEndMsgId);
}, *subscription);
}
};
Ui::show(Box<PeerListBox>(std::make_unique<AddParticipantsBoxController>(channel, std::move(alreadyIn)), std::move(initBox)));
}
void AddParticipantsBoxController::Start(
not_null<ChannelData*> channel,
base::flat_set<not_null<UserData*>> &&alreadyIn) {
Start(channel, std::move(alreadyIn), false);
}
void AddParticipantsBoxController::Start(not_null<ChannelData*> channel) {
Start(channel, {}, true);
}
void AddBotToGroupBoxController::Start(not_null<UserData*> bot) {
auto initBox = [=](not_null<PeerListBox*> box) {
box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); });

View File

@ -136,45 +136,6 @@ private:
};
class AddParticipantsBoxController : public ContactsBoxController {
public:
static void Start(not_null<ChatData*> chat);
static void Start(not_null<ChannelData*> channel);
static void Start(
not_null<ChannelData*> channel,
base::flat_set<not_null<UserData*>> &&alreadyIn);
AddParticipantsBoxController(PeerData *peer);
AddParticipantsBoxController(
not_null<ChannelData*> channel,
base::flat_set<not_null<UserData*>> &&alreadyIn);
using ContactsBoxController::ContactsBoxController;
void rowClicked(not_null<PeerListRow*> row) override;
void itemDeselectedHook(not_null<PeerData*> peer) override;
protected:
void prepareViewHook() override;
std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user) override;
private:
static void Start(
not_null<ChannelData*> channel,
base::flat_set<not_null<UserData*>> &&alreadyIn,
bool justCreated);
int alreadyInCount() const;
bool isAlreadyIn(not_null<UserData*> user) const;
int fullCount() const;
void updateTitle();
bool inviteSelectedUsers(not_null<PeerData*> chat) const;
PeerData *_peer = nullptr;
base::flat_set<not_null<UserData*>> _alreadyIn;
};
class AddBotToGroupBoxController
: public ChatsListBoxController
, public base::has_weak_ptr {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,183 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/edit_participants_box.h"
class AddParticipantsBoxController : public ContactsBoxController {
public:
static void Start(not_null<ChatData*> chat);
static void Start(not_null<ChannelData*> channel);
static void Start(
not_null<ChannelData*> channel,
base::flat_set<not_null<UserData*>> &&alreadyIn);
AddParticipantsBoxController(PeerData *peer);
AddParticipantsBoxController(
not_null<ChannelData*> channel,
base::flat_set<not_null<UserData*>> &&alreadyIn);
using ContactsBoxController::ContactsBoxController;
void rowClicked(not_null<PeerListRow*> row) override;
void itemDeselectedHook(not_null<PeerData*> peer) override;
protected:
void prepareViewHook() override;
std::unique_ptr<PeerListRow> createRow(
not_null<UserData*> user) override;
private:
static void Start(
not_null<ChannelData*> channel,
base::flat_set<not_null<UserData*>> &&alreadyIn,
bool justCreated);
int alreadyInCount() const;
bool isAlreadyIn(not_null<UserData*> user) const;
int fullCount() const;
void updateTitle();
bool inviteSelectedUsers(not_null<PeerData*> chat) const;
PeerData *_peer = nullptr;
base::flat_set<not_null<UserData*>> _alreadyIn;
};
// Adding an admin, banned or restricted user from channel members
// with search + contacts search + global search.
class AddSpecialBoxController
: public PeerListController
, private base::Subscriber
, private MTP::Sender
, public base::has_weak_ptr {
public:
using Role = ParticipantsBoxController::Role;
using Additional = ParticipantsBoxController::Additional;
using AdminDoneCallback = Fn<void(
not_null<UserData*> user,
const MTPChatAdminRights &adminRights)>;
using BannedDoneCallback = Fn<void(
not_null<UserData*> user,
const MTPChatBannedRights &bannedRights)>;
AddSpecialBoxController(
not_null<PeerData*> peer,
Role role,
AdminDoneCallback adminDoneCallback,
BannedDoneCallback bannedDoneCallback);
void prepare() override;
void rowClicked(not_null<PeerListRow*> row) override;
void loadMoreRows() override;
std::unique_ptr<PeerListRow> createSearchRow(
not_null<PeerData*> peer) override;
// Callback(not_null<UserData*>)
template <typename Callback>
static void HandleParticipant(
const MTPChannelParticipant &participant,
not_null<Additional*> additional,
Callback callback);
private:
template <typename Callback>
bool checkInfoLoaded(not_null<UserData*> user, Callback callback);
void prepareChatRows(not_null<ChatData*> chat);
void rebuildChatRows(not_null<ChatData*> chat);
void showAdmin(not_null<UserData*> user, bool sure = false);
void editAdminDone(
not_null<UserData*> user,
const MTPChatAdminRights &rights);
void showRestricted(not_null<UserData*> user, bool sure = false);
void editRestrictedDone(
not_null<UserData*> user,
const MTPChatBannedRights &rights);
void kickUser(not_null<UserData*> user, bool sure = false);
void restrictUserSure(
not_null<UserData*> user,
const MTPChatBannedRights &oldRights,
const MTPChatBannedRights &newRights);
bool appendRow(not_null<UserData*> user);
bool prependRow(not_null<UserData*> user);
std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user) const;
not_null<PeerData*> _peer;
Role _role = Role::Admins;
int _offset = 0;
mtpRequestId _loadRequestId = 0;
bool _allLoaded = false;
Additional _additional;
std::unique_ptr<ParticipantsOnlineSorter> _onlineSorter;
QPointer<BoxContent> _editBox;
AdminDoneCallback _adminDoneCallback;
BannedDoneCallback _bannedDoneCallback;
};
// Finds chat/channel members, then contacts, then global search results.
class AddSpecialBoxSearchController
: public PeerListSearchController
, private MTP::Sender {
public:
using Role = ParticipantsBoxController::Role;
using Additional = ParticipantsBoxController::Additional;
AddSpecialBoxSearchController(
not_null<PeerData*> peer,
not_null<Additional*> additional);
void searchQuery(const QString &query) override;
bool isLoading() override;
bool loadMoreRows() override;
private:
struct CacheEntry {
MTPchannels_ChannelParticipants result;
int requestedCount = 0;
};
struct Query {
QString text;
int offset = 0;
};
void searchOnServer();
bool searchParticipantsInCache();
void searchParticipantsDone(
mtpRequestId requestId,
const MTPchannels_ChannelParticipants &result,
int requestedCount);
bool searchGlobalInCache();
void searchGlobalDone(
mtpRequestId requestId,
const MTPcontacts_Found &result);
void requestParticipants();
void addChatMembers();
void addChatsContacts();
void requestGlobal();
not_null<PeerData*> _peer;
not_null<Additional*> _additional;
base::Timer _timer;
QString _query;
mtpRequestId _requestId = 0;
int _offset = 0;
bool _participantsLoaded = false;
bool _chatsContactsAdded = false;
bool _globalLoaded = false;
std::map<QString, CacheEntry> _participantsCache;
std::map<mtpRequestId, Query> _participantsQueries;
std::map<QString, MTPcontacts_Found> _globalCache;
std::map<mtpRequestId, QString> _globalQueries;
};

View File

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peers/edit_peer_permissions_box.h"
#include "data/data_peer_values.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
#include "styles/style_boxes.h"
@ -34,7 +35,7 @@ class EditParticipantBox::Inner : public Ui::RpWidget {
public:
Inner(
QWidget *parent,
not_null<ChannelData*> channel,
not_null<PeerData*> peer,
not_null<UserData*> user,
bool hasAdminRights);
@ -46,7 +47,7 @@ protected:
void paintEvent(QPaintEvent *e) override;
private:
not_null<ChannelData*> _channel;
not_null<PeerData*> _peer;
not_null<UserData*> _user;
object_ptr<Ui::UserpicButton> _userPhoto;
Text _userName;
@ -57,11 +58,11 @@ private:
EditParticipantBox::Inner::Inner(
QWidget *parent,
not_null<ChannelData*> channel,
not_null<PeerData*> peer,
not_null<UserData*> user,
bool hasAdminRights)
: RpWidget(parent)
, _channel(channel)
, _peer(peer)
, _user(user)
, _userPhoto(
this,
@ -138,10 +139,10 @@ void EditParticipantBox::Inner::paintEvent(QPaintEvent *e) {
EditParticipantBox::EditParticipantBox(
QWidget*,
not_null<ChannelData*> channel,
not_null<PeerData*> peer,
not_null<UserData*> user,
bool hasAdminRights)
: _channel(channel)
: _peer(peer)
, _user(user)
, _hasAdminRights(hasAdminRights) {
}
@ -149,7 +150,7 @@ EditParticipantBox::EditParticipantBox(
void EditParticipantBox::prepare() {
_inner = setInnerWidget(object_ptr<Inner>(
this,
_channel,
_peer,
_user,
hasAdminRights()));
setDimensionsToContent(st::boxWideWidth, _inner);
@ -166,19 +167,21 @@ Widget *EditParticipantBox::addControl(
EditAdminBox::EditAdminBox(
QWidget*,
not_null<ChannelData*> channel,
not_null<PeerData*> peer,
not_null<UserData*> user,
const MTPChatAdminRights &rights)
: EditParticipantBox(
nullptr,
channel,
peer,
user,
(rights.c_chatAdminRights().vflags.v != 0))
, _oldRights(rights) {
}
MTPChatAdminRights EditAdminBox::Defaults(not_null<ChannelData*> channel) {
const auto defaultRights = channel->isMegagroup()
MTPChatAdminRights EditAdminBox::Defaults(not_null<PeerData*> peer) {
const auto defaultRights = peer->isChat()
? ChatData::DefaultAdminRights()
: peer->isMegagroup()
? (Flag::f_change_info
| Flag::f_delete_messages
| Flag::f_ban_users
@ -206,26 +209,32 @@ void EditAdminBox::prepare() {
object_ptr<BoxContentDivider>(this),
st::rightsDividerMargin);
const auto prepareRights = hadRights ? _oldRights : Defaults(channel());
const auto chat = peer()->asChat();
const auto channel = peer()->asChannel();
const auto prepareRights = hadRights ? _oldRights : Defaults(peer());
const auto filterByMyRights = canSave()
&& !hadRights
&& !channel()->amCreator();
&& channel
&& !channel->amCreator();
const auto prepareFlags = prepareRights.c_chatAdminRights().vflags.v
& (filterByMyRights ? channel()->adminRights() : ~Flag(0));
& (filterByMyRights ? channel->adminRights() : ~Flag(0));
const auto disabledFlags = canSave()
? (channel()->amCreator()
? ((!channel || channel->amCreator())
? Flags(0)
: ~channel()->adminRights())
: ~channel->adminRights())
: ~Flags(0);
const auto anyoneCanAddMembers = chat
? chat->anyoneCanAddMembers()
: channel->anyoneCanAddMembers();
auto [checkboxes, getChecked, changes] = CreateEditAdminRights(
this,
lng_rights_edit_admin_header,
prepareFlags,
disabledFlags,
channel()->isMegagroup(),
channel()->anyoneCanAddMembers());
peer()->isChat() || peer()->isMegagroup(),
anyoneCanAddMembers);
addControl(std::move(checkboxes), QMargins());
_aboutAddAdmins = addControl(
@ -248,9 +257,9 @@ void EditAdminBox::prepare() {
return;
}
const auto newFlags = value()
& (channel()->amCreator()
& ((!channel || channel->amCreator())
? ~Flags(0)
: channel()->adminRights());
: channel->adminRights());
_saveCallback(
_oldRights,
MTP_chatAdminRights(MTP_flags(newFlags)));
@ -274,11 +283,11 @@ void EditAdminBox::refreshAboutAddAdminsText(bool canAddAdmins) {
EditRestrictedBox::EditRestrictedBox(
QWidget*,
not_null<ChannelData*> channel,
not_null<PeerData*> peer,
not_null<UserData*> user,
bool hasAdminRights,
const MTPChatBannedRights &rights)
: EditParticipantBox(nullptr, channel, user, hasAdminRights)
: EditParticipantBox(nullptr, peer, user, hasAdminRights)
, _oldRights(rights) {
}
@ -291,19 +300,24 @@ void EditRestrictedBox::prepare() {
object_ptr<BoxContentDivider>(this),
st::rightsDividerMargin);
const auto chat = peer()->asChat();
const auto channel = peer()->asChannel();
const auto defaultRestrictions = chat
? chat->defaultRestrictions()
: channel->defaultRestrictions();
const auto prepareRights = (_oldRights.c_chatBannedRights().vflags.v
? _oldRights
: Defaults(channel()));
: Defaults(peer()));
const auto prepareFlags = prepareRights.c_chatBannedRights().vflags.v
| (channel()->defaultRestrictions()
| (channel()->isPublic()
? (Flag::f_change_info | Flag::f_pin_messages)
: Flags(0)));
| defaultRestrictions
| ((channel && channel->isPublic())
? (Flag::f_change_info | Flag::f_pin_messages)
: Flags(0));
const auto disabledFlags = canSave()
? (channel()->defaultRestrictions()
| (channel()->isPublic()
? (defaultRestrictions
| ((channel && channel->isPublic())
? (Flag::f_change_info | Flag::f_pin_messages)
: Flags(0))) // #TODO groups
: Flags(0)))
: ~Flags(0);
auto [checkboxes, getRestrictions, changes] = CreateEditRestrictions(
@ -348,8 +362,7 @@ void EditRestrictedBox::prepare() {
}
}
MTPChatBannedRights EditRestrictedBox::Defaults(
not_null<ChannelData*> channel) {
MTPChatBannedRights EditRestrictedBox::Defaults(not_null<PeerData*> peer) {
return MTP_chatBannedRights(MTP_flags(0), MTP_int(0));
}

View File

@ -24,7 +24,7 @@ class EditParticipantBox : public BoxContent {
public:
EditParticipantBox(
QWidget*,
not_null<ChannelData*> channel,
not_null<PeerData*> peer,
not_null<UserData*> user,
bool hasAdminRights);
@ -34,8 +34,8 @@ protected:
not_null<UserData*> user() const {
return _user;
}
not_null<ChannelData*> channel() const {
return _channel;
not_null<PeerData*> peer() const {
return _peer;
}
template <typename Widget>
@ -46,7 +46,7 @@ protected:
}
private:
not_null<ChannelData*> _channel;
not_null<PeerData*> _peer;
not_null<UserData*> _user;
bool _hasAdminRights = false;
@ -59,7 +59,7 @@ class EditAdminBox : public EditParticipantBox {
public:
EditAdminBox(
QWidget*,
not_null<ChannelData*> channel,
not_null<PeerData*> peer,
not_null<UserData*> user,
const MTPChatAdminRights &rights);
@ -75,7 +75,7 @@ private:
using Flag = MTPDchatAdminRights::Flag;
using Flags = MTPDchatAdminRights::Flags;
static MTPChatAdminRights Defaults(not_null<ChannelData*> channel);
static MTPChatAdminRights Defaults(not_null<PeerData*> peer);
bool canSave() const {
return !!_saveCallback;
@ -96,7 +96,7 @@ class EditRestrictedBox : public EditParticipantBox {
public:
EditRestrictedBox(
QWidget*,
not_null<ChannelData*> channel,
not_null<PeerData*> peer,
not_null<UserData*> user,
bool hasAdminRights,
const MTPChatBannedRights &rights);
@ -113,7 +113,7 @@ private:
using Flag = MTPDchatBannedRights::Flag;
using Flags = MTPDchatBannedRights::Flags;
static MTPChatBannedRights Defaults(not_null<ChannelData*> channel);
static MTPChatBannedRights Defaults(not_null<PeerData*> peer);
bool canSave() const {
return !!_saveCallback;
@ -121,7 +121,6 @@ private:
void showRestrictUntil();
void setRestrictUntil(TimeId until);
bool isUntilForever() const;
void clearVariants();
void createUntilGroup();
void createUntilVariants();
TimeId getRealUntilValue() const;

File diff suppressed because it is too large Load Diff

View File

@ -18,8 +18,6 @@ namespace Window {
class Navigation;
} // namespace Window
namespace Profile {
Fn<void(
const MTPChatAdminRights &oldRights,
const MTPChatAdminRights &newRights)> SaveAdminCallback(
@ -28,6 +26,34 @@ Fn<void(
Fn<void(const MTPChatAdminRights &newRights)> onDone,
Fn<void()> onFail);
Fn<void(
const MTPChatBannedRights &oldRights,
const MTPChatBannedRights &newRights)> SaveRestrictedCallback(
not_null<ChannelData*> channel,
not_null<UserData*> user,
Fn<void(const MTPChatBannedRights &newRights)> onDone,
Fn<void()> onFail);
class ParticipantsOnlineSorter : private base::Subscriber {
public:
ParticipantsOnlineSorter(
not_null<PeerData*> peer,
not_null<PeerListDelegate*> delegate);
void sort();
rpl::producer<int> onlineCountValue() const;
private:
void sortDelayed();
void refreshOnlineCount();
not_null<PeerData*> _peer;
not_null<PeerListDelegate*> _delegate;
base::Timer _sortByOnlineTimer;
rpl::variable<int> _onlineCount = 0;
};
// Viewing admins, banned or restricted users list with search.
class ParticipantsBoxController
: public PeerListController
@ -44,10 +70,12 @@ public:
};
static void Start(
not_null<Window::Navigation*> navigation,
not_null<ChannelData*> channel,
not_null<PeerData*> peer,
Role role);
struct Additional {
void fillCreator(not_null<PeerData*> peer);
std::map<not_null<UserData*>, MTPChatAdminRights> adminRights;
std::set<not_null<UserData*>> adminCanEdit;
std::map<not_null<UserData*>, not_null<UserData*>> adminPromotedBy;
@ -61,11 +89,9 @@ public:
ParticipantsBoxController(
not_null<Window::Navigation*> navigation,
not_null<ChannelData*> channel,
not_null<PeerData*> peer,
Role role);
void addNewItem();
void prepare() override;
void rowClicked(not_null<PeerListRow*> row) override;
void rowActionClicked(not_null<PeerListRow*> row) override;
@ -94,14 +120,16 @@ public:
rpl::producer<int> onlineCountValue() const override;
protected:
virtual std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user) const;
virtual std::unique_ptr<PeerListRow> createRow(
not_null<UserData*> user) const;
private:
using Row = Info::Profile::MemberListRow;
using Type = Row::Type;
using Rights = Row::Rights;
struct SavedState : SavedStateBase {
std::unique_ptr<PeerListSearchController::SavedStateBase> searchState;
using SearchStateBase = PeerListSearchController::SavedStateBase;
std::unique_ptr<SearchStateBase> searchState;
int offset = 0;
bool allLoaded = false;
bool wasLoading = false;
@ -110,15 +138,19 @@ private:
};
static std::unique_ptr<PeerListSearchController> CreateSearchController(
not_null<ChannelData*> channel,
not_null<PeerData*> peer,
Role role,
not_null<Additional*> additional);
void prepareChatRows(not_null<ChatData*> chat);
void rebuildChatRows(not_null<ChatData*> chat);
void rebuildRowTypes();
void addNewItem();
void addNewParticipants();
void setNonEmptyDescription();
void setupSortByOnline();
void setupListChangeViewers();
void sortByOnlineDelayed();
void sortByOnline();
void showAdmin(not_null<UserData*> user);
void editAdminDone(
not_null<UserData*> user,
@ -145,18 +177,16 @@ private:
bool canEditAdminByRights(not_null<UserData*> user) const;
not_null<Window::Navigation*> _navigation;
not_null<ChannelData*> _channel;
not_null<PeerData*> _peer;
Role _role = Role::Admins;
int _offset = 0;
mtpRequestId _loadRequestId = 0;
bool _allLoaded = false;
Additional _additional;
std::unique_ptr<ParticipantsOnlineSorter> _onlineSorter;
QPointer<BoxContent> _editBox;
QPointer<PeerListBox> _addBox;
base::Timer _sortByOnlineTimer;
rpl::variable<int> _onlineCount = 0;
};
// Members, banned and restricted users server side search.
@ -167,7 +197,10 @@ public:
using Role = ParticipantsBoxController::Role;
using Additional = ParticipantsBoxController::Additional;
ParticipantsBoxSearchController(not_null<ChannelData*> channel, Role role, not_null<Additional*> additional);
ParticipantsBoxSearchController(
not_null<ChannelData*> channel,
Role role,
not_null<Additional*> additional);
void searchQuery(const QString &query) override;
bool isLoading() override;
@ -212,99 +245,3 @@ private:
std::map<mtpRequestId, Query> _queries;
};
// Adding an admin, banned or restricted user from channel members with search + contacts search + global search.
class AddParticipantBoxController : public PeerListController, private base::Subscriber, private MTP::Sender, public base::has_weak_ptr {
public:
using Role = ParticipantsBoxController::Role;
using Additional = ParticipantsBoxController::Additional;
using AdminDoneCallback = Fn<void(not_null<UserData*> user, const MTPChatAdminRights &adminRights)>;
using BannedDoneCallback = Fn<void(not_null<UserData*> user, const MTPChatBannedRights &bannedRights)>;
AddParticipantBoxController(not_null<ChannelData*> channel, Role role, AdminDoneCallback adminDoneCallback, BannedDoneCallback bannedDoneCallback);
void prepare() override;
void rowClicked(not_null<PeerListRow*> row) override;
void loadMoreRows() override;
std::unique_ptr<PeerListRow> createSearchRow(not_null<PeerData*> peer) override;
// Callback(not_null<UserData*>)
template <typename Callback>
static void HandleParticipant(const MTPChannelParticipant &participant, not_null<Additional*> additional, Callback callback);
private:
template <typename Callback>
bool checkInfoLoaded(not_null<UserData*> user, Callback callback);
void showAdmin(not_null<UserData*> user, bool sure = false);
void editAdminDone(not_null<UserData*> user, const MTPChatAdminRights &rights);
void showRestricted(not_null<UserData*> user, bool sure = false);
void editRestrictedDone(not_null<UserData*> user, const MTPChatBannedRights &rights);
void kickUser(not_null<UserData*> user, bool sure = false);
void restrictUserSure(not_null<UserData*> user, const MTPChatBannedRights &oldRights, const MTPChatBannedRights &newRights);
bool appendRow(not_null<UserData*> user);
bool prependRow(not_null<UserData*> user);
std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user) const;
not_null<ChannelData*> _channel;
Role _role = Role::Admins;
int _offset = 0;
mtpRequestId _loadRequestId = 0;
bool _allLoaded = false;
Additional _additional;
QPointer<BoxContent> _editBox;
AdminDoneCallback _adminDoneCallback;
BannedDoneCallback _bannedDoneCallback;
};
// Finds channel members, then contacts, then global search results.
class AddParticipantBoxSearchController : public PeerListSearchController, private MTP::Sender {
public:
using Role = ParticipantsBoxController::Role;
using Additional = ParticipantsBoxController::Additional;
AddParticipantBoxSearchController(not_null<ChannelData*> channel, not_null<Additional*> additional);
void searchQuery(const QString &query) override;
bool isLoading() override;
bool loadMoreRows() override;
private:
struct CacheEntry {
MTPchannels_ChannelParticipants result;
int requestedCount = 0;
};
struct Query {
QString text;
int offset = 0;
};
void searchOnServer();
bool searchParticipantsInCache();
void searchParticipantsDone(mtpRequestId requestId, const MTPchannels_ChannelParticipants &result, int requestedCount);
bool searchGlobalInCache();
void searchGlobalDone(mtpRequestId requestId, const MTPcontacts_Found &result);
void requestParticipants();
void addChatsContacts();
void requestGlobal();
not_null<ChannelData*> _channel;
not_null<Additional*> _additional;
base::Timer _timer;
QString _query;
mtpRequestId _requestId = 0;
int _offset = 0;
bool _participantsLoaded = false;
bool _chatsContactsAdded = false;
bool _globalLoaded = false;
std::map<QString, CacheEntry> _participantsCache;
std::map<mtpRequestId, Query> _participantsQueries;
std::map<QString, MTPcontacts_Found> _globalCache;
std::map<mtpRequestId, QString> _globalQueries;
};
} // namespace Profile

View File

@ -16,7 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/profile/info_profile_button.h"
#include "info/profile/info_profile_icon.h"
#include "info/profile/info_profile_values.h"
#include "profile/profile_channel_controllers.h"
#include "boxes/peers/edit_participants_box.h"
#include "boxes/peers/manage_peer_box.h"
#include "window/window_controller.h"
#include "mainwindow.h"
@ -271,9 +271,7 @@ void EditPeerPermissionsBox::prepare() {
inner->add(std::move(checkboxes));
if (const auto channel = _peer->asChannel()) {
addBannedButtons(inner, channel);
}
addBannedButtons(inner);
_value = getRestrictions;
_save = addButton(langFactory(lng_settings_save));
@ -283,41 +281,40 @@ void EditPeerPermissionsBox::prepare() {
}
void EditPeerPermissionsBox::addBannedButtons(
not_null<Ui::VerticalLayout*> container,
not_null<ChannelData*> channel) {
using Profile::ParticipantsBoxController;
not_null<Ui::VerticalLayout*> container) {
container->add(
object_ptr<BoxContentDivider>(container),
{ 0, st::infoProfileSkip, 0, st::infoProfileSkip });
const auto navigation = App::wnd()->controller();
const auto channel = _peer->asChannel();
ManagePeerBox::CreateButton(
container,
Lang::Viewer(lng_manage_peer_exceptions),
Info::Profile::RestrictedCountValue(channel)
| ToPositiveNumberString(),
(channel
? Info::Profile::RestrictedCountValue(channel)
: rpl::single(0)) | ToPositiveNumberString(),
[=] {
ParticipantsBoxController::Start(
navigation,
channel,
_peer,
ParticipantsBoxController::Role::Restricted);
},
st::peerPermissionsButton,
st::infoIconRestrictedUsers);
ManagePeerBox::CreateButton(
container,
Lang::Viewer(lng_manage_peer_removed_users),
Info::Profile::KickedCountValue(channel)
| ToPositiveNumberString(),
[=] {
ParticipantsBoxController::Start(
navigation,
channel,
ParticipantsBoxController::Role::Kicked);
},
st::peerPermissionsButton,
st::infoIconBlacklist);
st::peerPermissionsButton);
if (channel) {
ManagePeerBox::CreateButton(
container,
Lang::Viewer(lng_manage_peer_removed_users),
Info::Profile::KickedCountValue(channel)
| ToPositiveNumberString(),
[=] {
ParticipantsBoxController::Start(
navigation,
_peer,
ParticipantsBoxController::Role::Kicked);
},
st::peerPermissionsButton);
}
}
template <typename Flags, typename FlagLabelPairs>

View File

@ -27,9 +27,7 @@ protected:
void prepare() override;
private:
void addBannedButtons(
not_null<Ui::VerticalLayout*> container,
not_null<ChannelData*> channel);
void addBannedButtons(not_null<Ui::VerticalLayout*> container);
not_null<PeerData*> _peer;
Ui::RoundButton *_save = nullptr;

View File

@ -11,11 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "boxes/peers/edit_peer_info_box.h"
#include "boxes/peers/edit_peer_permissions_box.h"
#include "boxes/peers/edit_participants_box.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/widgets/labels.h"
#include "history/admin_log/history_admin_log_section.h"
#include "window/window_controller.h"
#include "profile/profile_channel_controllers.h"
#include "info/profile/info_profile_button.h"
#include "info/profile/info_profile_icon.h"
#include "info/profile/info_profile_values.h"
@ -52,7 +52,7 @@ Info::Profile::Button *AddButton(
rpl::single(QString()),
std::move(callback),
st::managePeerButton,
icon);
&icon);
}
void AddButtonWithCount(
@ -67,7 +67,7 @@ void AddButtonWithCount(
std::move(count),
std::move(callback),
st::managePeerButton,
icon);
&icon);
}
bool HasRecentActions(not_null<ChannelData*> channel) {
@ -139,10 +139,10 @@ void FillManageChatBox(
Info::Profile::AdminsCountValue(chat)
| ToPositiveNumberString(),
[=] {
//ParticipantsBoxController::Start(
// navigation,
// channel,
// ParticipantsBoxController::Role::Admins);
ParticipantsBoxController::Start(
navigation,
chat,
ParticipantsBoxController::Role::Admins);
},
st::infoIconAdministrators);
AddButtonWithCount(
@ -151,10 +151,10 @@ void FillManageChatBox(
Info::Profile::MembersCountValue(chat)
| ToPositiveNumberString(),
[=] {
//ParticipantsBoxController::Start(
// navigation,
// channel,
// ParticipantsBoxController::Role::Members);
ParticipantsBoxController::Start(
navigation,
chat,
ParticipantsBoxController::Role::Members);
},
st::infoIconMembers);
}
@ -164,8 +164,6 @@ void FillManageChannelBox(
not_null<Window::Navigation*> navigation,
not_null<ChannelData*> channel,
not_null<Ui::VerticalLayout*> content) {
using Profile::ParticipantsBoxController;
auto isGroup = channel->isMegagroup();
if (HasEditInfoBox(channel)) {
AddButton(
@ -272,17 +270,19 @@ Info::Profile::Button *ManagePeerBox::CreateButton(
rpl::producer<QString> &&count,
Fn<void()> callback,
const style::InfoProfileCountButton &st,
const style::icon &icon) {
const style::icon *icon) {
const auto button = parent->add(
object_ptr<Info::Profile::Button>(
parent,
std::move(text),
st.button));
button->addClickHandler(callback);
Ui::CreateChild<Info::Profile::FloatingIcon>(
button,
icon,
st.iconPosition);
if (icon) {
Ui::CreateChild<Info::Profile::FloatingIcon>(
button,
*icon,
st.iconPosition);
}
const auto label = Ui::CreateChild<Ui::FlatLabel>(
button,
std::move(count),

View File

@ -35,7 +35,7 @@ public:
rpl::producer<QString> &&count,
Fn<void()> callback,
const style::InfoProfileCountButton &st,
const style::icon &icon);
const style::icon *icon = nullptr);
protected:
void prepare() override;

View File

@ -105,12 +105,23 @@ void ChannelData::setKickedCount(int newKickedCount) {
MTPChatBannedRights ChannelData::KickedRestrictedRights() {
using Flag = MTPDchatBannedRights::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_chatBannedRights(MTP_flags(flags), MTP_int(std::numeric_limits<int32>::max()));
const 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_chatBannedRights(
MTP_flags(flags),
MTP_int(std::numeric_limits<int32>::max()));
}
void ChannelData::applyEditAdmin(not_null<UserData*> user, const MTPChatAdminRights &oldRights, const MTPChatAdminRights &newRights) {
auto flags = Notify::PeerUpdate::Flag::AdminsChanged | Notify::PeerUpdate::Flag::None;
void ChannelData::applyEditAdmin(
not_null<UserData*> user,
const MTPChatAdminRights &oldRights,
const MTPChatAdminRights &newRights) {
if (mgInfo) {
// If rights are empty - still add participant? TODO check
if (!base::contains(mgInfo->lastParticipants, user)) {
@ -167,7 +178,9 @@ void ChannelData::applyEditAdmin(not_null<UserData*> user, const MTPChatAdminRig
setAdminsCount(adminsCount() + 1);
updateFullForced();
}
Notify::peerUpdatedDelayed(this, flags);
Notify::peerUpdatedDelayed(
this,
Notify::PeerUpdate::Flag::AdminsChanged);
}
void ChannelData::applyEditBanned(not_null<UserData*> user, const MTPChatBannedRights &oldRights, const MTPChatBannedRights &newRights) {
@ -285,23 +298,22 @@ void ChannelData::setFeedPointer(Data::Feed *feed) {
}
bool ChannelData::canBanMembers() const {
return (adminRights() & AdminRight::f_ban_users)
|| amCreator();
return amCreator()
|| (adminRights() & AdminRight::f_ban_users);
}
bool ChannelData::canEditMessages() const {
return (adminRights() & AdminRight::f_edit_messages)
|| amCreator();
return amCreator()
|| (adminRights() & AdminRight::f_edit_messages);
}
bool ChannelData::canDeleteMessages() const {
return (adminRights() & AdminRight::f_delete_messages)
|| amCreator();
return amCreator()
|| (adminRights() & AdminRight::f_delete_messages);
}
bool ChannelData::anyoneCanAddMembers() const {
// #TODO groups
return false;// (flags() & MTPDchannel::Flag::f_democracy);
return !(defaultRestrictions() & Restriction::f_invite_users);
}
bool ChannelData::hiddenPreHistory() const {
@ -312,6 +324,10 @@ bool ChannelData::canAddMembers() const {
return !amRestricted(ChatRestriction::f_invite_users);
}
bool ChannelData::canSendPolls() const {
return canWrite() && !amRestricted(ChatRestriction::f_send_polls);
}
bool ChannelData::canAddAdmins() const {
return amCreator()
|| (adminRights() & AdminRight::f_add_admins);

View File

@ -246,13 +246,14 @@ public:
bool canEditUsername() const;
bool canEditPreHistoryHidden() const;
bool canAddMembers() const;
bool canAddAdmins() const;
bool canBanMembers() const;
bool canSendPolls() const;
bool anyoneCanAddMembers() const;
bool canEditMessages() const;
bool canDeleteMessages() const;
bool anyoneCanAddMembers() const;
bool hiddenPreHistory() const;
bool canAddAdmins() const;
bool canPublish() const;
bool canViewMembers() const;
bool canViewAdmins() const;

View File

@ -37,15 +37,24 @@ bool ChatData::actionsUnavailable() const {
return isDeactivated() || !amIn();
}
auto ChatData::DefaultAdminRights() -> AdminRights {
using Flag = AdminRight;
return Flag::f_change_info
| Flag::f_delete_messages
| Flag::f_ban_users
| Flag::f_invite_users
| Flag::f_pin_messages;
}
bool ChatData::canWrite() const {
// Duplicated in Data::CanWriteValue().
return !actionsUnavailable()
&& !amRestricted(ChatRestriction::f_send_messages);
&& !amRestricted(Restriction::f_send_messages);
}
bool ChatData::canEditInformation() const {
return !actionsUnavailable()
&& !amRestricted(ChatRestriction::f_change_info);
&& !amRestricted(Restriction::f_change_info);
}
bool ChatData::canEditPermissions() const {
@ -64,13 +73,45 @@ bool ChatData::canEditPreHistoryHidden() const {
bool ChatData::canAddMembers() const {
return !actionsUnavailable()
&& !amRestricted(ChatRestriction::f_invite_users);
&& !amRestricted(Restriction::f_invite_users);
}
bool ChatData::canSendPolls() const {
return !actionsUnavailable()
&& !amRestricted(Restriction::f_send_polls);
}
bool ChatData::canAddAdmins() const {
return !actionsUnavailable()
&& amCreator();
}
bool ChatData::canBanMembers() const {
return amCreator()
|| (adminRights() & AdminRight::f_ban_users);
}
bool ChatData::anyoneCanAddMembers() const {
return !(defaultRestrictions() & Restriction::f_invite_users);
}
void ChatData::setName(const QString &newName) {
updateNameDelayed(newName.isEmpty() ? name : newName, QString(), QString());
}
void ChatData::applyEditAdmin(not_null<UserData*> user, bool isAdmin) {
auto flags = Notify::PeerUpdate::Flag::AdminsChanged
| Notify::PeerUpdate::Flag::None;
if (isAdmin) {
admins.emplace(user);
} else {
admins.remove(user);
}
Notify::peerUpdatedDelayed(
this,
Notify::PeerUpdate::Flag::AdminsChanged);
}
void ChatData::invalidateParticipants() {
// #TODO groups
participants.clear();

View File

@ -121,13 +121,21 @@ public:
return flags() & MTPDchat::Flag::f_migrated_to;
}
// Like in ChatData.
static AdminRights DefaultAdminRights();
// Like in ChannelData.
bool canWrite() const;
bool canEditInformation() const;
bool canEditPermissions() const;
bool canEditUsername() const;
bool canEditPreHistoryHidden() const;
bool canAddMembers() const;
bool canAddAdmins() const;
bool canBanMembers() const;
bool canSendPolls() const;
bool anyoneCanAddMembers() const;
void applyEditAdmin(not_null<UserData*> user, bool isAdmin);
void setInviteLink(const QString &newInviteLink);
QString inviteLink() const {

View File

@ -1253,6 +1253,13 @@ TextWithEntities MediaPoll::clipboardText() const {
return { text, EntitiesInText() };
}
QString MediaPoll::errorTextForForward(not_null<PeerData*> peer) const {
if (peer->amRestricted(ChatRestriction::f_send_polls)) {
return lang(lng_restricted_send_polls);
}
return QString();
}
bool MediaPoll::updateInlineResultMedia(const MTPMessageMedia &media) {
return false;
}

View File

@ -389,6 +389,7 @@ public:
QString notificationText() const override;
QString pinnedTextSubstring() const override;
TextWithEntities clipboardText() const override;
QString errorTextForForward(not_null<PeerData*> peer) const override;
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
bool updateSentMedia(const MTPMessageMedia &media) override;

View File

@ -435,14 +435,15 @@ void PeerData::fillNames() {
PeerData::~PeerData() = default;
void PeerData::updateFull() {
if (!_lastFullUpdate || getms(true) > _lastFullUpdate + kUpdateFullPeerTimeout) {
if (!_lastFullUpdate
|| getms(true) > _lastFullUpdate + kUpdateFullPeerTimeout) {
updateFullForced();
}
}
void PeerData::updateFullForced() {
session().api().requestFullPeer(this);
if (auto channel = asChannel()) {
if (const auto channel = asChannel()) {
if (!channel->amCreator() && !channel->inviter) {
session().api().requestSelfParticipant(channel);
}

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "data/data_peer_values.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
#include "observer_peer.h"

View File

@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "boxes/peer_list_box.h"
#include "profile/profile_channel_controllers.h"
#include "boxes/peers/edit_participants_box.h"
namespace Dialogs {
@ -38,7 +38,7 @@ private:
};
class ChannelSearchFromController : public Profile::ParticipantsBoxController {
class ChannelSearchFromController : public ParticipantsBoxController {
public:
ChannelSearchFromController(
not_null<Window::Navigation*> navigation,

View File

@ -26,10 +26,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "messenger.h"
#include "boxes/peer_list_box.h"
#include "boxes/peers/edit_participants_box.h"
#include "window/window_controller.h"
#include "window/window_slide_animation.h"
#include "window/window_connecting_widget.h"
#include "profile/profile_channel_controllers.h"
#include "storage/storage_media_prepare.h"
#include "storage/localstorage.h"
#include "data/data_session.h"

View File

@ -213,7 +213,7 @@ QString GenerateBannedChangeText(
{ Flag::f_send_media, lng_admin_log_banned_send_media },
{ Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_inline | Flag::f_send_games, lng_admin_log_banned_send_stickers },
{ Flag::f_embed_links, lng_admin_log_banned_embed_links },
{ Flag::f_send_media, lng_admin_log_banned_send_polls },
{ Flag::f_send_polls, lng_admin_log_banned_send_polls },
{ Flag::f_change_info, lng_admin_log_admin_change_info },
{ Flag::f_invite_users, lng_admin_log_admin_invite_users },
{ Flag::f_pin_messages, lng_admin_log_admin_pin_messages },

View File

@ -361,7 +361,6 @@ infoIconMediaRound: icon {{ "info_media_round", infoIconFg }};
infoIconRecentActions: icon {{ "info_recent_actions", infoIconFg }};
infoIconAdministrators: icon {{ "info_administrators", infoIconFg }};
infoIconBlacklist: icon {{ "info_blacklist", infoIconFg }};
infoIconRestrictedUsers: icon {{ "info_restricted_users", infoIconFg }};
infoIconPermissions: icon {{ "info_permissions", infoIconFg }};
infoInformationIconPosition: point(25px, 12px);
infoNotificationsIconPosition: point(20px, 5px);
@ -592,7 +591,7 @@ managePeerButton: InfoProfileCountButton {
}
peerPermissionsButton: InfoProfileCountButton(managePeerButton) {
button: InfoProfileButton(infoProfileButton) {
padding: margins(67px, 12px, 67px, 10px);
padding: margins(24px, 12px, 24px, 10px);
}
iconPosition: point(24px, 5px);
}

View File

@ -26,7 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/search_field_controller.h"
#include "lang/lang_keys.h"
#include "boxes/confirm_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/add_participants_box.h"
#include "window/window_controller.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
@ -323,11 +323,7 @@ void Members::updateHeaderControlsGeometry(int newWidth) {
void Members::addMember() {
if (const auto chat = _peer->asChat()) {
if (chat->count >= Global::ChatSizeMax() && chat->amCreator()) {
// #TODO convert and add inside AddParticipantsBoxController?
} else {
AddParticipantsBoxController::Start(chat);
}
AddParticipantsBoxController::Start(chat);
} else if (const auto channel = _peer->asChannel()) {
const auto state = _listController->saveState();
const auto users = ranges::view::all(

View File

@ -19,10 +19,6 @@ struct ScrollToRequest;
class AbstractButton;
} // namespace Ui
namespace Profile {
class ParticipantsBoxController;
} // namespace Profile
namespace Info {
class Controller;

View File

@ -9,13 +9,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <rpl/variable.h>
#include "base/weak_ptr.h"
#include "profile/profile_channel_controllers.h"
#include "boxes/peers/edit_participants_box.h"
#include "ui/widgets/popup_menu.h"
#include "lang/lang_keys.h"
#include "apiwrap.h"
#include "auth_session.h"
#include "mainwidget.h"
#include "observer_peer.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
#include "boxes/confirm_box.h"
@ -378,17 +379,15 @@ void MemberListRow::paintNameIcon(
std::unique_ptr<PeerListController> CreateMembersController(
not_null<Window::Navigation*> navigation,
not_null<PeerData*> peer) {
if (auto chat = peer->asChat()) {
if (const auto chat = peer->asChat()) {
return std::make_unique<ChatMembersController>(
navigation,
chat);
} else if (auto channel = peer->asChannel()) {
using ChannelMembersController
= ::Profile::ParticipantsBoxController;
return std::make_unique<ChannelMembersController>(
} else if (const auto channel = peer->asChannel()) {
return std::make_unique<ParticipantsBoxController>(
navigation,
channel,
ChannelMembersController::Role::Profile);
ParticipantsBoxController::Role::Profile);
}
Unexpected("Peer type in CreateMembersController()");
}

View File

@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/labels.h"
#include "boxes/confirm_box.h"
#include "boxes/peers/edit_participant_box.h"
#include "profile/profile_channel_controllers.h"
#include "boxes/peers/edit_participants_box.h"
#include "ui/widgets/popup_menu.h"
#include "data/data_peer_values.h"
#include "data/data_channel.h"
@ -68,51 +68,6 @@ GroupMembersWidget::GroupMembersWidget(
refreshMembers();
}
void GroupMembersWidget::editAdmin(not_null<UserData*> user) {
auto megagroup = peer()->asMegagroup();
if (!megagroup) {
return; // not supported
}
auto currentRightsIt = megagroup->mgInfo->lastAdmins.find(user);
auto hasAdminRights = (currentRightsIt != megagroup->mgInfo->lastAdmins.cend());
auto currentRights = hasAdminRights ? currentRightsIt->second.rights : MTP_chatAdminRights(MTP_flags(0));
auto weak = std::make_shared<QPointer<EditAdminBox>>(nullptr);
auto box = Box<EditAdminBox>(megagroup, user, currentRights);
box->setSaveCallback(SaveAdminCallback(megagroup, user, [=](
const MTPChatAdminRights &newRights) {
if (*weak) {
(*weak)->closeBox();
}
}, [=] {
if (*weak) {
(*weak)->closeBox();
}
}));
*weak = Ui::show(std::move(box));
}
void GroupMembersWidget::restrictUser(not_null<UserData*> user) {
auto megagroup = peer()->asMegagroup();
if (!megagroup) {
return; // not supported
}
auto currentRightsIt = megagroup->mgInfo->lastRestricted.find(user);
auto currentRights = (currentRightsIt != megagroup->mgInfo->lastRestricted.end())
? currentRightsIt->second.rights
: MTP_chatBannedRights(MTP_flags(0), MTP_int(0));
auto hasAdminRights = megagroup->mgInfo->lastAdmins.find(user) != megagroup->mgInfo->lastAdmins.cend();
auto box = Box<EditRestrictedBox>(megagroup, user, hasAdminRights, currentRights);
box->setSaveCallback([megagroup, user](const MTPChatBannedRights &oldRights, const MTPChatBannedRights &newRights) {
Ui::hideLayer();
// #TODO use Auth().api().
MTP::send(MTPchannels_EditBanned(megagroup->inputChannel, user->inputUser, newRights), rpcDone([megagroup, user, oldRights, newRights](const MTPUpdates &result) {
Auth().api().applyUpdates(result);
megagroup->applyEditBanned(user, oldRights, newRights);
}));
});
Ui::show(std::move(box));
}
void GroupMembersWidget::removePeer(PeerData *selectedPeer) {
auto user = selectedPeer->asUser();
Assert(user != nullptr);

View File

@ -42,8 +42,6 @@ private:
// Observed notifications.
void notifyPeerUpdated(const Notify::PeerUpdate &update);
void editAdmin(not_null<UserData*> user);
void restrictUser(not_null<UserData*> user);
void removePeer(PeerData *selectedPeer);
void refreshMembers();
void fillChatMembers(ChatData *chat);

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/add_contact_box.h"
#include "boxes/report_box.h"
#include "boxes/create_poll_box.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/peers/add_participants_box.h"
#include "boxes/peers/manage_peer_box.h"
#include "boxes/peers/edit_peer_info_box.h"
#include "ui/toast/toast.h"
@ -368,7 +368,7 @@ void Filler::addChatActions(not_null<ChatData*> chat) {
lang(lng_profile_add_participant),
[chat] { AddChatMembers(chat); });
}
if (chat->canWrite()) {
if (chat->canSendPolls()) {
_addAction(
lang(lng_polls_create),
[=] { PeerMenuCreatePoll(chat); });
@ -410,7 +410,7 @@ void Filler::addChannelActions(not_null<ChannelData*> channel) {
lang(lng_channel_add_members),
[channel] { PeerMenuAddChannelMembers(channel); });
}
if (channel->canWrite()) {
if (channel->canSendPolls()) {
_addAction(
lang(lng_polls_create),
[=] { PeerMenuCreatePoll(channel); });

View File

@ -1,5 +1,9 @@
<(src_loc)/boxes/peers/add_participants_box.cpp
<(src_loc)/boxes/peers/add_participants_box.h
<(src_loc)/boxes/peers/edit_participant_box.cpp
<(src_loc)/boxes/peers/edit_participant_box.h
<(src_loc)/boxes/peers/edit_participants_box.cpp
<(src_loc)/boxes/peers/edit_participants_box.h
<(src_loc)/boxes/peers/edit_peer_info_box.cpp
<(src_loc)/boxes/peers/edit_peer_info_box.h
<(src_loc)/boxes/peers/edit_peer_permissions_box.cpp
@ -584,8 +588,6 @@
<(src_loc)/profile/profile_block_peer_list.h
<(src_loc)/profile/profile_block_widget.cpp
<(src_loc)/profile/profile_block_widget.h
<(src_loc)/profile/profile_channel_controllers.cpp
<(src_loc)/profile/profile_channel_controllers.h
<(src_loc)/profile/profile_cover_drop_area.cpp
<(src_loc)/profile/profile_cover_drop_area.h
<(src_loc)/settings/settings_advanced.cpp