Add 'X' and admin star in group info members.

This commit is contained in:
John Preston 2017-11-07 21:53:00 +04:00
parent 5f0ba48309
commit 1871425b2d
12 changed files with 381 additions and 52 deletions

View file

@ -379,6 +379,18 @@ void PeerListRow::invalidatePixmapsCache() {
}
}
int PeerListRow::nameIconWidth() const {
return _peer->isVerified() ? st::dialogsVerifiedIcon.width() : 0;
}
void PeerListRow::paintNameIcon(
Painter &p,
int x,
int y,
int outerWidth) {
st::dialogsVerifiedIcon.paint(p, x, y, outerWidth);
}
void PeerListRow::paintStatusText(
Painter &p,
const style::PeerListItem &st,
@ -997,7 +1009,7 @@ TimeMs PeerListContent::paintRow(Painter &p, TimeMs ms, RowIndex index) {
auto row = getRow(index);
Assert(row != nullptr);
row->lazyInitialize(_st.item);
auto refreshStatusAt = row->refreshStatusTime();
if (refreshStatusAt >= 0 && ms >= refreshStatusAt) {
row->refreshStatus();
@ -1029,28 +1041,44 @@ TimeMs PeerListContent::paintRow(Painter &p, TimeMs ms, RowIndex index) {
p.setPen(st::contactsNameFg);
auto skipRight = _st.item.photoPosition.x();
auto actionSize = row->actionSize();
auto actionMargins = actionSize.isEmpty() ? QMargins() : row->actionMargins();
auto &name = row->name();
auto namex = _st.item.namePosition.x();
auto namew = width() - namex - _st.item.photoPosition.x();
auto namew = width() - namex - skipRight;
if (!actionSize.isEmpty()) {
namew -= actionMargins.left() + actionSize.width() + actionMargins.right();
namew -= actionMargins.left()
+ actionSize.width()
+ actionMargins.right()
- skipRight;
}
auto statusw = namew;
if (row->needsVerifiedIcon()) {
auto icon = &st::dialogsVerifiedIcon;
namew -= icon->width();
icon->paint(p, namex + qMin(name.maxWidth(), namew), _st.item.namePosition.y(), width());
if (auto iconWidth = row->nameIconWidth()) {
namew -= iconWidth;
row->paintNameIcon(
p,
namex + qMin(name.maxWidth(), namew),
_st.item.namePosition.y(),
width());
}
auto nameCheckedRatio = row->disabled() ? 0. : row->checkedRatio();
p.setPen(anim::pen(st::contactsNameFg, st::contactsNameCheckedFg, nameCheckedRatio));
name.drawLeftElided(p, namex, _st.item.namePosition.y(), namew, width());
if (!actionSize.isEmpty()) {
auto actionLeft = width() - _st.item.photoPosition.x() - actionMargins.right() - actionSize.width();
auto actionLeft = width()
- actionMargins.right()
- actionSize.width();
auto actionTop = actionMargins.top();
row->paintAction(p, ms, actionLeft, actionTop, width(), actionSelected);
row->paintAction(
p,
ms,
actionLeft,
actionTop,
width(),
selected,
actionSelected);
}
p.setFont(st::contactsStatusFont);
@ -1377,7 +1405,7 @@ QRect PeerListContent::getActionRect(not_null<PeerListRow*> row, RowIndex index)
return QRect();
}
auto actionMargins = row->actionMargins();
auto actionRight = _st.item.photoPosition.x() + actionMargins.right();
auto actionRight = actionMargins.right();
auto actionTop = actionMargins.top();
auto actionLeft = width() - actionRight - actionSize.width();
auto rowTop = getRowTop(index);

View file

@ -86,9 +86,12 @@ public:
virtual ~PeerListRow();
// Box interface.
virtual bool needsVerifiedIcon() const {
return _peer->isVerified();
}
virtual int nameIconWidth() const;
virtual void paintNameIcon(
Painter &p,
int x,
int y,
int outerWidth);
virtual QSize actionSize() const {
return QSize();
}
@ -99,7 +102,14 @@ public:
}
virtual void stopLastActionRipple() {
}
virtual void paintAction(Painter &p, TimeMs ms, int x, int y, int outerWidth, bool actionSelected) {
virtual void paintAction(
Painter &p,
TimeMs ms,
int x,
int y,
int outerWidth,
bool selected,
bool actionSelected) {
}
void refreshName(const style::PeerListItem &st);

View file

@ -128,10 +128,21 @@ QSize PeerListRowWithLink::actionSize() const {
}
QMargins PeerListRowWithLink::actionMargins() const {
return QMargins(st::contactsCheckPosition.x(), (st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom() - st::normalFont->height) / 2, st::contactsCheckPosition.x(), 0);
return QMargins(
st::contactsCheckPosition.x(),
(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom() - st::normalFont->height) / 2,
st::defaultPeerListItem.photoPosition.x() + st::contactsCheckPosition.x(),
0);
}
void PeerListRowWithLink::paintAction(Painter &p, TimeMs ms, int x, int y, int outerWidth, bool actionSelected) {
void PeerListRowWithLink::paintAction(
Painter &p,
TimeMs ms,
int x,
int y,
int outerWidth,
bool selected,
bool actionSelected) {
p.setFont(actionSelected ? st::linkOverFont : st::linkFont);
p.setPen(actionSelected ? st::defaultLinkButton.overColor : st::defaultLinkButton.color);
p.drawTextLeft(x, y, outerWidth, _action, _actionWidth);

View file

@ -53,7 +53,14 @@ private:
void refreshActionLink();
QSize actionSize() const override;
QMargins actionMargins() const override;
void paintAction(Painter &p, TimeMs ms, int x, int y, int outerWidth, bool actionSelected) override;
void paintAction(
Painter &p,
TimeMs ms,
int x,
int y,
int outerWidth,
bool selected,
bool actionSelected) override;
QString _action;
int _actionWidth = 0;

View file

@ -90,16 +90,27 @@ public:
void addActionRipple(QPoint point, base::lambda<void()> updateCallback) override;
void stopLastActionRipple() override;
bool needsVerifiedIcon() const override {
return false;
int nameIconWidth() const override {
return 0;
}
QSize actionSize() const override {
return peer()->isUser() ? QSize(st::callReDial.width, st::callReDial.height) : QSize();
}
QMargins actionMargins() const override {
return QMargins(0, 0, 0, 0);
return QMargins(
0,
0,
st::defaultPeerListItem.photoPosition.x(),
0);
}
void paintAction(Painter &p, TimeMs ms, int x, int y, int outerWidth, bool actionSelected) override;
void paintAction(
Painter &p,
TimeMs ms,
int x,
int y,
int outerWidth,
bool selected,
bool actionSelected) override;
private:
void refreshStatus();
@ -138,7 +149,14 @@ void BoxController::Row::paintStatusText(Painter &p, const style::PeerListItem &
PeerListRow::paintStatusText(p, st, x, y, availableWidth, outerWidth, selected);
}
void BoxController::Row::paintAction(Painter &p, TimeMs ms, int x, int y, int outerWidth, bool actionSelected) {
void BoxController::Row::paintAction(
Painter &p,
TimeMs ms,
int x,
int y,
int outerWidth,
bool selected,
bool actionSelected) {
auto size = actionSize();
if (_actionRipple) {
_actionRipple->paint(p, x + st::callReDial.rippleAreaPosition.x(), y + st::callReDial.rippleAreaPosition.y(), outerWidth, ms);

View file

@ -928,7 +928,8 @@ void ChannelData::setRestrictionReason(const QString &text) {
}
}
bool ChannelData::canNotEditLastAdmin(not_null<UserData*> user) const {
bool ChannelData::canEditLastAdmin(not_null<UserData*> user) const {
// Duplicated in ParticipantsBoxController::canEditAdmin :(
if (mgInfo) {
auto i = mgInfo->lastAdmins.constFind(user);
if (i != mgInfo->lastAdmins.cend()) {
@ -940,22 +941,24 @@ bool ChannelData::canNotEditLastAdmin(not_null<UserData*> user) const {
}
bool ChannelData::canEditAdmin(not_null<UserData*> user) const {
// Duplicated in ParticipantsBoxController::canEditAdmin :(
if (user->isSelf()) {
return false;
} else if (amCreator()) {
return true;
} else if (canNotEditLastAdmin(user)) {
} else if (!canEditLastAdmin(user)) {
return false;
}
return adminRights() & AdminRight::f_add_admins;
}
bool ChannelData::canRestrictUser(not_null<UserData*> user) const {
// Duplicated in ParticipantsBoxController::canRestrictUser :(
if (user->isSelf()) {
return false;
} else if (amCreator()) {
return true;
} else if (canNotEditLastAdmin(user)) {
} else if (!canEditLastAdmin(user)) {
return false;
}
return adminRights() & AdminRight::f_ban_users;

View file

@ -1096,7 +1096,7 @@ private:
void flagsUpdated(MTPDchannel::Flags diff);
void fullFlagsUpdated(MTPDchannelFull::Flags diff);
bool canNotEditLastAdmin(not_null<UserData*> user) const;
bool canEditLastAdmin(not_null<UserData*> user) const;
Flags _flags = Flags(MTPDchannel_ClientFlag::f_forbidden | 0);
FullFlags _fullFlags;

View file

@ -478,6 +478,27 @@ infoMembersCancelSearch: CrossButton {
}
infoMembersSearchTop: 15px;
infoMembersCreatorIcon: icon {{
"profile_admin_star",
profileAdminStartFg,
point(4px, 3px)
}};
infoMembersAdminIcon: icon {{
"profile_admin_star",
profileOtherAdminStarFg,
point(4px, 3px)
}};
infoMembersRemoveIcon: icon {{
"simple_close",
menuIconFg
}};
infoMembersRemoveIconOver: icon {{
"simple_close",
menuIconFgOver
}};
infoMembersAdminIconMarigns: margins(10px, 18px, 10px, 10px);
infoMembersRemoveIconMargins: margins(10px, 12px, 12px, 10px);
infoMediaHeaderStyle: TextStyle(semiboldTextStyle) {
}
infoMediaHeaderHeight: 28px;

View file

@ -31,6 +31,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "observer_peer.h"
#include "boxes/confirm_box.h"
#include "window/window_controller.h"
#include "styles/style_info.h"
namespace Info {
namespace Profile {
@ -49,6 +50,7 @@ public:
void prepare() override;
void rowClicked(not_null<PeerListRow*> row) override;
void rowActionClicked(not_null<PeerListRow*> row) override;
Ui::PopupMenu *rowContextMenu(
not_null<PeerListRow*> row) override;
@ -63,15 +65,20 @@ public:
void restoreState(std::unique_ptr<PeerListState> state) override;
private:
using Rights = MemberListRow::Rights;
using Type = MemberListRow::Type;
struct SavedState : SavedStateBase {
rpl::lifetime lifetime;
};
void rebuildRows();
void rebuildRowTypes();
void refreshOnlineCount();
std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user);
std::unique_ptr<PeerListRow> createRow(
not_null<UserData*> user);
void sortByOnline();
void sortByOnlineDelayed();
void removeMember(not_null<UserData*> user);
Type computeType(not_null<UserData*> user);
not_null<Window::Controller*> _window;
not_null<ChatData*> _chat;
@ -101,12 +108,18 @@ void ChatMembersController::prepare() {
}
using UpdateFlag = Notify::PeerUpdate::Flag;
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(
UpdateFlag::MembersChanged | UpdateFlag::UserOnlineChanged,
UpdateFlag::MembersChanged
| UpdateFlag::UserOnlineChanged
| UpdateFlag::AdminsChanged,
[this](const Notify::PeerUpdate &update) {
if (update.flags & UpdateFlag::MembersChanged) {
if (update.peer == _chat) {
rebuildRows();
}
} else if (update.flags & UpdateFlag::AdminsChanged) {
if (update.peer == _chat) {
rebuildRowTypes();
}
} else if (update.flags & UpdateFlag::UserOnlineChanged) {
if (auto row = delegate()->peerListFindRow(
update.peer->id)) {
@ -187,6 +200,16 @@ void ChatMembersController::rebuildRows() {
delegate()->peerListRefreshRows();
}
void ChatMembersController::rebuildRowTypes() {
auto count = delegate()->peerListFullRowsCount();
for (auto i = 0; i != count; ++i) {
auto row = static_cast<MemberListRow*>(
delegate()->peerListRowAt(i).get());
row->setType(computeType(row->user()));
}
delegate()->peerListRefreshRows();
}
void ChatMembersController::refreshOnlineCount() {
auto now = unixtime();
auto left = 0, right = delegate()->peerListFullRowsCount();
@ -212,29 +235,53 @@ std::unique_ptr<PeerListRow> ChatMembersController::createRestoredRow(
std::unique_ptr<PeerListRow> ChatMembersController::createRow(
not_null<UserData*> user) {
return std::make_unique<PeerListRow>(user);
return std::make_unique<MemberListRow>(user, computeType(user));
}
auto ChatMembersController::computeType(
not_null<UserData*> user) -> Type {
auto isCreator = (peerFromUser(_chat->creator) == user->id);
auto isAdmin = _chat->adminsEnabled()
&& _chat->admins.contains(user);
auto canRemove = [&] {
if (user->isSelf()) {
return false;
} else if (_chat->amCreator()) {
return true;
} else if (isAdmin || isCreator) {
return false;
} else if (_chat->amAdmin()) {
return true;
} else if (_chat->invitedByMe.contains(user)) {
return true;
}
return false;
}();
auto result = Type();
result.rights = isCreator
? Rights::Creator
: isAdmin
? Rights::Admin
: Rights::Normal;
result.canRemove = canRemove;
return result;
}
void ChatMembersController::rowClicked(not_null<PeerListRow*> row) {
_window->showPeerInfo(row->peer());
}
void ChatMembersController::rowActionClicked(
not_null<PeerListRow*> row) {
removeMember(row->peer()->asUser());
}
Ui::PopupMenu *ChatMembersController::rowContextMenu(
not_null<PeerListRow*> row) {
Expects(row->peer()->isUser());
auto user = row->peer()->asUser();
auto isCreator = (peerFromUser(_chat->creator) == user->id);
auto isAdmin = _chat->adminsEnabled() && _chat->admins.contains(user);
auto canRemoveMember = (user->id == Auth().userPeerId())
? false
: _chat->amCreator()
? true
: (_chat->amAdmin() && !isCreator && !isAdmin)
? true
: (_chat->invitedByMe.contains(user) && !isCreator && !isAdmin)
? true
: false;
auto my = static_cast<MemberListRow*>(row.get());
auto user = my->user();
auto canRemoveMember = my->canRemove();
auto result = new Ui::PopupMenu(nullptr);
result->addAction(
@ -267,6 +314,64 @@ void ChatMembersController::removeMember(not_null<UserData*> user) {
} // namespace
MemberListRow::MemberListRow(
not_null<UserData*> user,
Type type)
: PeerListRow(user)
, _type(type) {
}
void MemberListRow::setType(Type type) {
_type = type;
}
QSize MemberListRow::actionSize() const {
return canRemove()
? QRect(
QPoint(),
st::infoMembersRemoveIcon.size()).marginsAdded(
st::infoMembersRemoveIconMargins).size()
: QSize();
}
void MemberListRow::paintAction(
Painter &p,
TimeMs ms,
int x,
int y,
int outerWidth,
bool selected,
bool actionSelected) {
if (_type.canRemove && selected) {
x += st::infoMembersRemoveIconMargins.left();
y += st::infoMembersRemoveIconMargins.top();
(actionSelected
? st::infoMembersRemoveIconOver
: st::infoMembersRemoveIcon).paint(p, x, y, outerWidth);
}
}
int MemberListRow::nameIconWidth() const {
return (_type.rights == Rights::Admin)
? st::infoMembersAdminIcon.width()
: (_type.rights == Rights::Creator)
? st::infoMembersCreatorIcon.width()
: 0;
}
void MemberListRow::paintNameIcon(
Painter &p,
int x,
int y,
int outerWidth) {
auto icon = [&] {
return (_type.rights == Rights::Admin)
? &st::infoMembersAdminIcon
: &st::infoMembersCreatorIcon;
}();
icon->paint(p, x, y, outerWidth);
}
std::unique_ptr<PeerListController> CreateMembersController(
not_null<Window::Controller*> window,
not_null<PeerData*> peer) {

View file

@ -20,7 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/
#pragma once
class PeerListController;
#include "boxes/peer_list_box.h"
namespace Window {
class Controller;
@ -29,6 +29,49 @@ class Controller;
namespace Info {
namespace Profile {
class MemberListRow final : public PeerListRow {
public:
enum class Rights {
Normal,
Admin,
Creator,
};
struct Type {
Rights rights;
bool canRemove = false;
};
MemberListRow(not_null<UserData*> user, Type type);
void setType(Type type);
QSize actionSize() const override;
void paintAction(
Painter &p,
TimeMs ms,
int x,
int y,
int outerWidth,
bool selected,
bool actionSelected) override;
int nameIconWidth() const override;
void paintNameIcon(
Painter &p,
int x,
int y,
int outerWidth) override;
not_null<UserData*> user() const {
return peer()->asUser();
}
bool canRemove() const {
return _type.canRemove;
}
private:
Type _type;
};
std::unique_ptr<PeerListController> CreateMembersController(
not_null<Window::Controller*> window,
not_null<PeerData*> peer);

View file

@ -545,6 +545,38 @@ void ParticipantsBoxController::rowActionClicked(not_null<PeerListRow*> row) {
}
}
bool ParticipantsBoxController::canEditAdminByRights(
not_null<UserData*> user) const {
if (_additional.adminCanEdit.find(user) != _additional.adminCanEdit.cend()) {
return true;
}
return (user != _additional.creator);
}
bool ParticipantsBoxController::canEditAdmin(
not_null<UserData*> user) const {
if (user->isSelf()) {
return false;
} else if (_channel->amCreator()) {
return true;
} else if (!canEditAdminByRights(user)) {
return false;
}
return _channel->adminRights() & ChannelAdminRight::f_add_admins;
}
bool ParticipantsBoxController::canRestrictUser(
not_null<UserData*> user) const {
if (user->isSelf()) {
return false;
} else if (_channel->amCreator()) {
return true;
} else if (!canEditAdminByRights(user)) {
return false;
}
return _channel->adminRights() & ChannelAdminRight::f_ban_users;
}
Ui::PopupMenu *ParticipantsBoxController::rowContextMenu(
not_null<PeerListRow*> row) {
Expects(row->peer()->isUser());
@ -558,7 +590,7 @@ Ui::PopupMenu *ParticipantsBoxController::rowContextMenu(
weak->_window->showPeerInfo(user);
}
});
if (_channel->canEditAdmin(user)) {
if (canEditAdmin(user)) {
auto it = _additional.adminRights.find(user);
auto isCreator = (user == _additional.creator);
auto notAdmin = !isCreator && (it == _additional.adminRights.cend());
@ -573,7 +605,7 @@ Ui::PopupMenu *ParticipantsBoxController::rowContextMenu(
}
});
}
if (_channel->canRestrictUser(user)) {
if (canRestrictUser(user)) {
result->addAction(
lang(lng_context_restrict_user),
[weak = base::make_weak_unique(this), user]{
@ -617,7 +649,9 @@ void ParticipantsBoxController::showAdmin(not_null<UserData*> user) {
_editBox = Ui::show(std::move(box), LayerOption::KeepOther);
}
void ParticipantsBoxController::editAdminDone(not_null<UserData*> user, const MTPChannelAdminRights &rights) {
void ParticipantsBoxController::editAdminDone(
not_null<UserData*> user,
const MTPChannelAdminRights &rights) {
if (_editBox) {
_editBox->closeBox();
}
@ -646,6 +680,7 @@ void ParticipantsBoxController::editAdminDone(not_null<UserData*> user, const MT
removeRow(user);
}
}
recomputeTypeFor(user);
delegate()->peerListRefreshRows();
}
@ -714,6 +749,7 @@ void ParticipantsBoxController::editRestrictedDone(not_null<UserData*> user, con
}
}
}
recomputeTypeFor(user);
delegate()->peerListRefreshRows();
}
@ -750,6 +786,7 @@ void ParticipantsBoxController::removeKicked(not_null<PeerListRow*> row, not_nul
bool ParticipantsBoxController::appendRow(not_null<UserData*> user) {
if (delegate()->peerListFindRow(user->id)) {
recomputeTypeFor(user);
return false;
}
delegate()->peerListAppendRow(createRow(user));
@ -761,6 +798,7 @@ bool ParticipantsBoxController::appendRow(not_null<UserData*> user) {
bool ParticipantsBoxController::prependRow(not_null<UserData*> user) {
if (auto row = delegate()->peerListFindRow(user->id)) {
recomputeTypeFor(user);
refreshCustomStatus(row);
if (_role == Role::Admins) {
// Perhaps we've added a new admin from search.
@ -792,7 +830,11 @@ bool ParticipantsBoxController::removeRow(not_null<UserData*> user) {
return false;
}
std::unique_ptr<PeerListRow> ParticipantsBoxController::createRow(not_null<UserData*> user) const {
std::unique_ptr<PeerListRow> ParticipantsBoxController::createRow(
not_null<UserData*> user) const {
if (_role == Role::Profile) {
return std::make_unique<Row>(user, computeType(user));
}
auto row = std::make_unique<PeerListRowWithLink>(user);
refreshCustomStatus(row.get());
if (_role == Role::Restricted || (_role == Role::Admins && _additional.adminCanEdit.find(user) != _additional.adminCanEdit.cend())) {
@ -809,6 +851,31 @@ std::unique_ptr<PeerListRow> ParticipantsBoxController::createRow(not_null<UserD
return std::move(row);
}
auto ParticipantsBoxController::computeType(
not_null<UserData*> user) const -> Type {
auto isCreator = (user == _additional.creator);
auto isAdmin = (_additional.adminRights.find(user) != _additional.adminRights.cend());
auto result = Type();
result.rights = isCreator
? Rights::Creator
: isAdmin
? Rights::Admin
: Rights::Normal;
result.canRemove = canRestrictUser(user);
return result;
}
void ParticipantsBoxController::recomputeTypeFor(
not_null<UserData*> user) {
if (_role != Role::Profile) {
return;
}
if (auto row = delegate()->peerListFindRow(user->id)) {
static_cast<Row*>(row)->setType(computeType(user));
}
}
void ParticipantsBoxController::refreshCustomStatus(not_null<PeerListRow*> row) const {
auto user = row->peer()->asUser();
if (_role == Role::Admins) {
@ -1209,7 +1276,9 @@ void AddParticipantBoxController::showAdmin(not_null<UserData*> user, bool sure)
_editBox = Ui::show(std::move(box), LayerOption::KeepOther);
}
void AddParticipantBoxController::editAdminDone(not_null<UserData*> user, const MTPChannelAdminRights &rights) {
void AddParticipantBoxController::editAdminDone(
not_null<UserData*> user,
const MTPChannelAdminRights &rights) {
if (_editBox) _editBox->closeBox();
_additional.restrictedRights.erase(user);
_additional.restrictedBy.erase(user);
@ -1291,7 +1360,9 @@ void AddParticipantBoxController::restrictUserSure(not_null<UserData*> user, con
}));
}
void AddParticipantBoxController::editRestrictedDone(not_null<UserData*> user, const MTPChannelBannedRights &rights) {
void AddParticipantBoxController::editRestrictedDone(
not_null<UserData*> user,
const MTPChannelBannedRights &rights) {
if (_editBox) _editBox->closeBox();
_additional.adminRights.erase(user);
_additional.adminCanEdit.erase(user);
@ -1380,7 +1451,10 @@ std::unique_ptr<PeerListRow> AddParticipantBoxController::createRow(not_null<Use
}
template <typename Callback>
void AddParticipantBoxController::HandleParticipant(const MTPChannelParticipant &participant, not_null<Additional*> additional, Callback callback) {
void AddParticipantBoxController::HandleParticipant(
const MTPChannelParticipant &participant,
not_null<Additional*> additional,
Callback callback) {
switch (participant.type()) {
case mtpc_channelParticipantAdmin: {
auto &admin = participant.c_channelParticipantAdmin();

View file

@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "mtproto/sender.h"
#include "base/timer.h"
#include "base/weak_unique_ptr.h"
#include "info/profile/info_profile_members_controllers.h"
namespace Window {
class Controller;
@ -102,6 +103,9 @@ 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 {
std::unique_ptr<PeerListSearchController::SavedStateBase> searchState;
int offset = 0;
@ -110,7 +114,7 @@ private:
Additional additional;
rpl::lifetime lifetime;
};
static std::unique_ptr<PeerListSearchController> CreateSearchController(
not_null<ChannelData*> channel,
Role role,
@ -133,6 +137,11 @@ private:
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::Controller*> _window;
not_null<ChannelData*> _channel;