2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-08-31 06:26:18 +00:00

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

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

@@ -0,0 +1,247 @@
/*
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 <rpl/variable.h>
#include "boxes/peer_list_box.h"
#include "mtproto/sender.h"
#include "base/timer.h"
#include "base/weak_ptr.h"
#include "info/profile/info_profile_members_controllers.h"
namespace Window {
class Navigation;
} // namespace Window
Fn<void(
const MTPChatAdminRights &oldRights,
const MTPChatAdminRights &newRights)> SaveAdminCallback(
not_null<ChannelData*> channel,
not_null<UserData*> user,
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
, private base::Subscriber
, private MTP::Sender
, public base::has_weak_ptr {
public:
enum class Role {
Profile,
Members,
Admins,
Restricted,
Kicked,
};
static void Start(
not_null<Window::Navigation*> navigation,
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;
std::map<not_null<UserData*>, MTPChatBannedRights> restrictedRights;
std::set<not_null<UserData*>> kicked;
std::map<not_null<UserData*>, not_null<UserData*>> restrictedBy;
std::set<not_null<UserData*>> external;
std::set<not_null<UserData*>> infoNotLoaded;
UserData *creator = nullptr;
};
ParticipantsBoxController(
not_null<Window::Navigation*> navigation,
not_null<PeerData*> peer,
Role role);
void prepare() override;
void rowClicked(not_null<PeerListRow*> row) override;
void rowActionClicked(not_null<PeerListRow*> row) override;
base::unique_qptr<Ui::PopupMenu> rowContextMenu(
QWidget *parent,
not_null<PeerListRow*> row) override;
void loadMoreRows() override;
void peerListSearchAddRow(not_null<PeerData*> peer) override;
std::unique_ptr<PeerListRow> createSearchRow(
not_null<PeerData*> peer) override;
std::unique_ptr<PeerListRow> createRestoredRow(
not_null<PeerData*> peer) override;
std::unique_ptr<PeerListState> saveState() const override;
void restoreState(std::unique_ptr<PeerListState> state) override;
// Callback(not_null<UserData*>)
template <typename Callback>
static void HandleParticipant(
const MTPChannelParticipant &participant,
Role role,
not_null<Additional*> additional,
Callback callback);
rpl::producer<int> onlineCountValue() const override;
protected:
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 {
using SearchStateBase = PeerListSearchController::SavedStateBase;
std::unique_ptr<SearchStateBase> searchState;
int offset = 0;
bool allLoaded = false;
bool wasLoading = false;
Additional additional;
rpl::lifetime lifetime;
};
static std::unique_ptr<PeerListSearchController> CreateSearchController(
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 setupListChangeViewers();
void showAdmin(not_null<UserData*> user);
void editAdminDone(
not_null<UserData*> user,
const MTPChatAdminRights &rights);
void showRestricted(not_null<UserData*> user);
void editRestrictedDone(
not_null<UserData*> user,
const MTPChatBannedRights &rights);
void removeKicked(not_null<PeerListRow*> row, not_null<UserData*> user);
void kickMember(not_null<UserData*> user);
void kickMemberSure(not_null<UserData*> user);
void removeAdmin(not_null<UserData*> user);
void removeAdminSure(not_null<UserData*> user);
bool appendRow(not_null<UserData*> user);
bool prependRow(not_null<UserData*> user);
bool removeRow(not_null<UserData*> user);
void refreshCustomStatus(not_null<PeerListRow*> row) const;
bool feedMegagroupLastParticipants();
void refreshOnlineCount();
Type computeType(not_null<UserData*> user) const;
void recomputeTypeFor(not_null<UserData*> user);
bool canEditAdmin(not_null<UserData*> user) const;
bool canRestrictUser(not_null<UserData*> user) const;
bool canEditAdminByRights(not_null<UserData*> user) const;
not_null<Window::Navigation*> _navigation;
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;
};
// Members, banned and restricted users server side search.
class ParticipantsBoxSearchController
: public PeerListSearchController
, private MTP::Sender {
public:
using Role = ParticipantsBoxController::Role;
using Additional = ParticipantsBoxController::Additional;
ParticipantsBoxSearchController(
not_null<ChannelData*> channel,
Role role,
not_null<Additional*> additional);
void searchQuery(const QString &query) override;
bool isLoading() override;
bool loadMoreRows() override;
std::unique_ptr<SavedStateBase> saveState() const override;
void restoreState(std::unique_ptr<SavedStateBase> state) override;
private:
struct SavedState : SavedStateBase {
QString query;
int offset = 0;
bool allLoaded = false;
bool wasLoading = false;
};
struct CacheEntry {
MTPchannels_ChannelParticipants result;
int requestedCount = 0;
};
struct Query {
QString text;
int offset = 0;
};
void searchOnServer();
bool searchInCache();
void searchDone(
mtpRequestId requestId,
const MTPchannels_ChannelParticipants &result,
int requestedCount);
not_null<ChannelData*> _channel;
Role _role = Role::Restricted;
not_null<Additional*> _additional;
base::Timer _timer;
QString _query;
mtpRequestId _requestId = 0;
int _offset = 0;
bool _allLoaded = false;
std::map<QString, CacheEntry> _cache;
std::map<mtpRequestId, Query> _queries;
};

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;