mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 10:11:41 -05:00
Add 'X' and admin star in group info members.
This commit is contained in:
parent
5f0ba48309
commit
1871425b2d
12 changed files with 381 additions and 52 deletions
|
@ -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(
|
void PeerListRow::paintStatusText(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
const style::PeerListItem &st,
|
const style::PeerListItem &st,
|
||||||
|
@ -1029,28 +1041,44 @@ TimeMs PeerListContent::paintRow(Painter &p, TimeMs ms, RowIndex index) {
|
||||||
|
|
||||||
p.setPen(st::contactsNameFg);
|
p.setPen(st::contactsNameFg);
|
||||||
|
|
||||||
|
auto skipRight = _st.item.photoPosition.x();
|
||||||
auto actionSize = row->actionSize();
|
auto actionSize = row->actionSize();
|
||||||
auto actionMargins = actionSize.isEmpty() ? QMargins() : row->actionMargins();
|
auto actionMargins = actionSize.isEmpty() ? QMargins() : row->actionMargins();
|
||||||
auto &name = row->name();
|
auto &name = row->name();
|
||||||
auto namex = _st.item.namePosition.x();
|
auto namex = _st.item.namePosition.x();
|
||||||
auto namew = width() - namex - _st.item.photoPosition.x();
|
auto namew = width() - namex - skipRight;
|
||||||
if (!actionSize.isEmpty()) {
|
if (!actionSize.isEmpty()) {
|
||||||
namew -= actionMargins.left() + actionSize.width() + actionMargins.right();
|
namew -= actionMargins.left()
|
||||||
|
+ actionSize.width()
|
||||||
|
+ actionMargins.right()
|
||||||
|
- skipRight;
|
||||||
}
|
}
|
||||||
auto statusw = namew;
|
auto statusw = namew;
|
||||||
if (row->needsVerifiedIcon()) {
|
if (auto iconWidth = row->nameIconWidth()) {
|
||||||
auto icon = &st::dialogsVerifiedIcon;
|
namew -= iconWidth;
|
||||||
namew -= icon->width();
|
row->paintNameIcon(
|
||||||
icon->paint(p, namex + qMin(name.maxWidth(), namew), _st.item.namePosition.y(), width());
|
p,
|
||||||
|
namex + qMin(name.maxWidth(), namew),
|
||||||
|
_st.item.namePosition.y(),
|
||||||
|
width());
|
||||||
}
|
}
|
||||||
auto nameCheckedRatio = row->disabled() ? 0. : row->checkedRatio();
|
auto nameCheckedRatio = row->disabled() ? 0. : row->checkedRatio();
|
||||||
p.setPen(anim::pen(st::contactsNameFg, st::contactsNameCheckedFg, nameCheckedRatio));
|
p.setPen(anim::pen(st::contactsNameFg, st::contactsNameCheckedFg, nameCheckedRatio));
|
||||||
name.drawLeftElided(p, namex, _st.item.namePosition.y(), namew, width());
|
name.drawLeftElided(p, namex, _st.item.namePosition.y(), namew, width());
|
||||||
|
|
||||||
if (!actionSize.isEmpty()) {
|
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();
|
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);
|
p.setFont(st::contactsStatusFont);
|
||||||
|
@ -1377,7 +1405,7 @@ QRect PeerListContent::getActionRect(not_null<PeerListRow*> row, RowIndex index)
|
||||||
return QRect();
|
return QRect();
|
||||||
}
|
}
|
||||||
auto actionMargins = row->actionMargins();
|
auto actionMargins = row->actionMargins();
|
||||||
auto actionRight = _st.item.photoPosition.x() + actionMargins.right();
|
auto actionRight = actionMargins.right();
|
||||||
auto actionTop = actionMargins.top();
|
auto actionTop = actionMargins.top();
|
||||||
auto actionLeft = width() - actionRight - actionSize.width();
|
auto actionLeft = width() - actionRight - actionSize.width();
|
||||||
auto rowTop = getRowTop(index);
|
auto rowTop = getRowTop(index);
|
||||||
|
|
|
@ -86,9 +86,12 @@ public:
|
||||||
virtual ~PeerListRow();
|
virtual ~PeerListRow();
|
||||||
|
|
||||||
// Box interface.
|
// Box interface.
|
||||||
virtual bool needsVerifiedIcon() const {
|
virtual int nameIconWidth() const;
|
||||||
return _peer->isVerified();
|
virtual void paintNameIcon(
|
||||||
}
|
Painter &p,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int outerWidth);
|
||||||
virtual QSize actionSize() const {
|
virtual QSize actionSize() const {
|
||||||
return QSize();
|
return QSize();
|
||||||
}
|
}
|
||||||
|
@ -99,7 +102,14 @@ public:
|
||||||
}
|
}
|
||||||
virtual void stopLastActionRipple() {
|
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);
|
void refreshName(const style::PeerListItem &st);
|
||||||
|
|
|
@ -128,10 +128,21 @@ QSize PeerListRowWithLink::actionSize() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QMargins PeerListRowWithLink::actionMargins() 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.setFont(actionSelected ? st::linkOverFont : st::linkFont);
|
||||||
p.setPen(actionSelected ? st::defaultLinkButton.overColor : st::defaultLinkButton.color);
|
p.setPen(actionSelected ? st::defaultLinkButton.overColor : st::defaultLinkButton.color);
|
||||||
p.drawTextLeft(x, y, outerWidth, _action, _actionWidth);
|
p.drawTextLeft(x, y, outerWidth, _action, _actionWidth);
|
||||||
|
|
|
@ -53,7 +53,14 @@ private:
|
||||||
void refreshActionLink();
|
void refreshActionLink();
|
||||||
QSize actionSize() const override;
|
QSize actionSize() const override;
|
||||||
QMargins actionMargins() 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;
|
QString _action;
|
||||||
int _actionWidth = 0;
|
int _actionWidth = 0;
|
||||||
|
|
|
@ -90,16 +90,27 @@ public:
|
||||||
void addActionRipple(QPoint point, base::lambda<void()> updateCallback) override;
|
void addActionRipple(QPoint point, base::lambda<void()> updateCallback) override;
|
||||||
void stopLastActionRipple() override;
|
void stopLastActionRipple() override;
|
||||||
|
|
||||||
bool needsVerifiedIcon() const override {
|
int nameIconWidth() const override {
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
QSize actionSize() const override {
|
QSize actionSize() const override {
|
||||||
return peer()->isUser() ? QSize(st::callReDial.width, st::callReDial.height) : QSize();
|
return peer()->isUser() ? QSize(st::callReDial.width, st::callReDial.height) : QSize();
|
||||||
}
|
}
|
||||||
QMargins actionMargins() const override {
|
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:
|
private:
|
||||||
void refreshStatus();
|
void refreshStatus();
|
||||||
|
@ -138,7 +149,14 @@ void BoxController::Row::paintStatusText(Painter &p, const style::PeerListItem &
|
||||||
PeerListRow::paintStatusText(p, st, x, y, availableWidth, outerWidth, selected);
|
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();
|
auto size = actionSize();
|
||||||
if (_actionRipple) {
|
if (_actionRipple) {
|
||||||
_actionRipple->paint(p, x + st::callReDial.rippleAreaPosition.x(), y + st::callReDial.rippleAreaPosition.y(), outerWidth, ms);
|
_actionRipple->paint(p, x + st::callReDial.rippleAreaPosition.x(), y + st::callReDial.rippleAreaPosition.y(), outerWidth, ms);
|
||||||
|
|
|
@ -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) {
|
if (mgInfo) {
|
||||||
auto i = mgInfo->lastAdmins.constFind(user);
|
auto i = mgInfo->lastAdmins.constFind(user);
|
||||||
if (i != mgInfo->lastAdmins.cend()) {
|
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 {
|
bool ChannelData::canEditAdmin(not_null<UserData*> user) const {
|
||||||
|
// Duplicated in ParticipantsBoxController::canEditAdmin :(
|
||||||
if (user->isSelf()) {
|
if (user->isSelf()) {
|
||||||
return false;
|
return false;
|
||||||
} else if (amCreator()) {
|
} else if (amCreator()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (canNotEditLastAdmin(user)) {
|
} else if (!canEditLastAdmin(user)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return adminRights() & AdminRight::f_add_admins;
|
return adminRights() & AdminRight::f_add_admins;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChannelData::canRestrictUser(not_null<UserData*> user) const {
|
bool ChannelData::canRestrictUser(not_null<UserData*> user) const {
|
||||||
|
// Duplicated in ParticipantsBoxController::canRestrictUser :(
|
||||||
if (user->isSelf()) {
|
if (user->isSelf()) {
|
||||||
return false;
|
return false;
|
||||||
} else if (amCreator()) {
|
} else if (amCreator()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (canNotEditLastAdmin(user)) {
|
} else if (!canEditLastAdmin(user)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return adminRights() & AdminRight::f_ban_users;
|
return adminRights() & AdminRight::f_ban_users;
|
||||||
|
|
|
@ -1096,7 +1096,7 @@ private:
|
||||||
void flagsUpdated(MTPDchannel::Flags diff);
|
void flagsUpdated(MTPDchannel::Flags diff);
|
||||||
void fullFlagsUpdated(MTPDchannelFull::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);
|
Flags _flags = Flags(MTPDchannel_ClientFlag::f_forbidden | 0);
|
||||||
FullFlags _fullFlags;
|
FullFlags _fullFlags;
|
||||||
|
|
|
@ -478,6 +478,27 @@ infoMembersCancelSearch: CrossButton {
|
||||||
}
|
}
|
||||||
infoMembersSearchTop: 15px;
|
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) {
|
infoMediaHeaderStyle: TextStyle(semiboldTextStyle) {
|
||||||
}
|
}
|
||||||
infoMediaHeaderHeight: 28px;
|
infoMediaHeaderHeight: 28px;
|
||||||
|
|
|
@ -31,6 +31,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "observer_peer.h"
|
#include "observer_peer.h"
|
||||||
#include "boxes/confirm_box.h"
|
#include "boxes/confirm_box.h"
|
||||||
#include "window/window_controller.h"
|
#include "window/window_controller.h"
|
||||||
|
#include "styles/style_info.h"
|
||||||
|
|
||||||
namespace Info {
|
namespace Info {
|
||||||
namespace Profile {
|
namespace Profile {
|
||||||
|
@ -49,6 +50,7 @@ public:
|
||||||
|
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
void rowClicked(not_null<PeerListRow*> row) override;
|
void rowClicked(not_null<PeerListRow*> row) override;
|
||||||
|
void rowActionClicked(not_null<PeerListRow*> row) override;
|
||||||
Ui::PopupMenu *rowContextMenu(
|
Ui::PopupMenu *rowContextMenu(
|
||||||
not_null<PeerListRow*> row) override;
|
not_null<PeerListRow*> row) override;
|
||||||
|
|
||||||
|
@ -63,15 +65,20 @@ public:
|
||||||
void restoreState(std::unique_ptr<PeerListState> state) override;
|
void restoreState(std::unique_ptr<PeerListState> state) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using Rights = MemberListRow::Rights;
|
||||||
|
using Type = MemberListRow::Type;
|
||||||
struct SavedState : SavedStateBase {
|
struct SavedState : SavedStateBase {
|
||||||
rpl::lifetime lifetime;
|
rpl::lifetime lifetime;
|
||||||
};
|
};
|
||||||
void rebuildRows();
|
void rebuildRows();
|
||||||
|
void rebuildRowTypes();
|
||||||
void refreshOnlineCount();
|
void refreshOnlineCount();
|
||||||
std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user);
|
std::unique_ptr<PeerListRow> createRow(
|
||||||
|
not_null<UserData*> user);
|
||||||
void sortByOnline();
|
void sortByOnline();
|
||||||
void sortByOnlineDelayed();
|
void sortByOnlineDelayed();
|
||||||
void removeMember(not_null<UserData*> user);
|
void removeMember(not_null<UserData*> user);
|
||||||
|
Type computeType(not_null<UserData*> user);
|
||||||
|
|
||||||
not_null<Window::Controller*> _window;
|
not_null<Window::Controller*> _window;
|
||||||
not_null<ChatData*> _chat;
|
not_null<ChatData*> _chat;
|
||||||
|
@ -101,12 +108,18 @@ void ChatMembersController::prepare() {
|
||||||
}
|
}
|
||||||
using UpdateFlag = Notify::PeerUpdate::Flag;
|
using UpdateFlag = Notify::PeerUpdate::Flag;
|
||||||
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(
|
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(
|
||||||
UpdateFlag::MembersChanged | UpdateFlag::UserOnlineChanged,
|
UpdateFlag::MembersChanged
|
||||||
|
| UpdateFlag::UserOnlineChanged
|
||||||
|
| UpdateFlag::AdminsChanged,
|
||||||
[this](const Notify::PeerUpdate &update) {
|
[this](const Notify::PeerUpdate &update) {
|
||||||
if (update.flags & UpdateFlag::MembersChanged) {
|
if (update.flags & UpdateFlag::MembersChanged) {
|
||||||
if (update.peer == _chat) {
|
if (update.peer == _chat) {
|
||||||
rebuildRows();
|
rebuildRows();
|
||||||
}
|
}
|
||||||
|
} else if (update.flags & UpdateFlag::AdminsChanged) {
|
||||||
|
if (update.peer == _chat) {
|
||||||
|
rebuildRowTypes();
|
||||||
|
}
|
||||||
} else if (update.flags & UpdateFlag::UserOnlineChanged) {
|
} else if (update.flags & UpdateFlag::UserOnlineChanged) {
|
||||||
if (auto row = delegate()->peerListFindRow(
|
if (auto row = delegate()->peerListFindRow(
|
||||||
update.peer->id)) {
|
update.peer->id)) {
|
||||||
|
@ -187,6 +200,16 @@ void ChatMembersController::rebuildRows() {
|
||||||
delegate()->peerListRefreshRows();
|
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() {
|
void ChatMembersController::refreshOnlineCount() {
|
||||||
auto now = unixtime();
|
auto now = unixtime();
|
||||||
auto left = 0, right = delegate()->peerListFullRowsCount();
|
auto left = 0, right = delegate()->peerListFullRowsCount();
|
||||||
|
@ -212,29 +235,53 @@ std::unique_ptr<PeerListRow> ChatMembersController::createRestoredRow(
|
||||||
|
|
||||||
std::unique_ptr<PeerListRow> ChatMembersController::createRow(
|
std::unique_ptr<PeerListRow> ChatMembersController::createRow(
|
||||||
not_null<UserData*> user) {
|
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) {
|
void ChatMembersController::rowClicked(not_null<PeerListRow*> row) {
|
||||||
_window->showPeerInfo(row->peer());
|
_window->showPeerInfo(row->peer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatMembersController::rowActionClicked(
|
||||||
|
not_null<PeerListRow*> row) {
|
||||||
|
removeMember(row->peer()->asUser());
|
||||||
|
}
|
||||||
|
|
||||||
Ui::PopupMenu *ChatMembersController::rowContextMenu(
|
Ui::PopupMenu *ChatMembersController::rowContextMenu(
|
||||||
not_null<PeerListRow*> row) {
|
not_null<PeerListRow*> row) {
|
||||||
Expects(row->peer()->isUser());
|
auto my = static_cast<MemberListRow*>(row.get());
|
||||||
|
auto user = my->user();
|
||||||
auto user = row->peer()->asUser();
|
auto canRemoveMember = my->canRemove();
|
||||||
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 result = new Ui::PopupMenu(nullptr);
|
auto result = new Ui::PopupMenu(nullptr);
|
||||||
result->addAction(
|
result->addAction(
|
||||||
|
@ -267,6 +314,64 @@ void ChatMembersController::removeMember(not_null<UserData*> user) {
|
||||||
|
|
||||||
} // namespace
|
} // 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(
|
std::unique_ptr<PeerListController> CreateMembersController(
|
||||||
not_null<Window::Controller*> window,
|
not_null<Window::Controller*> window,
|
||||||
not_null<PeerData*> peer) {
|
not_null<PeerData*> peer) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
class PeerListController;
|
#include "boxes/peer_list_box.h"
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
class Controller;
|
class Controller;
|
||||||
|
@ -29,6 +29,49 @@ class Controller;
|
||||||
namespace Info {
|
namespace Info {
|
||||||
namespace Profile {
|
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(
|
std::unique_ptr<PeerListController> CreateMembersController(
|
||||||
not_null<Window::Controller*> window,
|
not_null<Window::Controller*> window,
|
||||||
not_null<PeerData*> peer);
|
not_null<PeerData*> peer);
|
||||||
|
|
|
@ -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(
|
Ui::PopupMenu *ParticipantsBoxController::rowContextMenu(
|
||||||
not_null<PeerListRow*> row) {
|
not_null<PeerListRow*> row) {
|
||||||
Expects(row->peer()->isUser());
|
Expects(row->peer()->isUser());
|
||||||
|
@ -558,7 +590,7 @@ Ui::PopupMenu *ParticipantsBoxController::rowContextMenu(
|
||||||
weak->_window->showPeerInfo(user);
|
weak->_window->showPeerInfo(user);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (_channel->canEditAdmin(user)) {
|
if (canEditAdmin(user)) {
|
||||||
auto it = _additional.adminRights.find(user);
|
auto it = _additional.adminRights.find(user);
|
||||||
auto isCreator = (user == _additional.creator);
|
auto isCreator = (user == _additional.creator);
|
||||||
auto notAdmin = !isCreator && (it == _additional.adminRights.cend());
|
auto notAdmin = !isCreator && (it == _additional.adminRights.cend());
|
||||||
|
@ -573,7 +605,7 @@ Ui::PopupMenu *ParticipantsBoxController::rowContextMenu(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (_channel->canRestrictUser(user)) {
|
if (canRestrictUser(user)) {
|
||||||
result->addAction(
|
result->addAction(
|
||||||
lang(lng_context_restrict_user),
|
lang(lng_context_restrict_user),
|
||||||
[weak = base::make_weak_unique(this), 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);
|
_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) {
|
if (_editBox) {
|
||||||
_editBox->closeBox();
|
_editBox->closeBox();
|
||||||
}
|
}
|
||||||
|
@ -646,6 +680,7 @@ void ParticipantsBoxController::editAdminDone(not_null<UserData*> user, const MT
|
||||||
removeRow(user);
|
removeRow(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
recomputeTypeFor(user);
|
||||||
delegate()->peerListRefreshRows();
|
delegate()->peerListRefreshRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -714,6 +749,7 @@ void ParticipantsBoxController::editRestrictedDone(not_null<UserData*> user, con
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
recomputeTypeFor(user);
|
||||||
delegate()->peerListRefreshRows();
|
delegate()->peerListRefreshRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,6 +786,7 @@ void ParticipantsBoxController::removeKicked(not_null<PeerListRow*> row, not_nul
|
||||||
|
|
||||||
bool ParticipantsBoxController::appendRow(not_null<UserData*> user) {
|
bool ParticipantsBoxController::appendRow(not_null<UserData*> user) {
|
||||||
if (delegate()->peerListFindRow(user->id)) {
|
if (delegate()->peerListFindRow(user->id)) {
|
||||||
|
recomputeTypeFor(user);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
delegate()->peerListAppendRow(createRow(user));
|
delegate()->peerListAppendRow(createRow(user));
|
||||||
|
@ -761,6 +798,7 @@ bool ParticipantsBoxController::appendRow(not_null<UserData*> user) {
|
||||||
|
|
||||||
bool ParticipantsBoxController::prependRow(not_null<UserData*> user) {
|
bool ParticipantsBoxController::prependRow(not_null<UserData*> user) {
|
||||||
if (auto row = delegate()->peerListFindRow(user->id)) {
|
if (auto row = delegate()->peerListFindRow(user->id)) {
|
||||||
|
recomputeTypeFor(user);
|
||||||
refreshCustomStatus(row);
|
refreshCustomStatus(row);
|
||||||
if (_role == Role::Admins) {
|
if (_role == Role::Admins) {
|
||||||
// Perhaps we've added a new admin from search.
|
// Perhaps we've added a new admin from search.
|
||||||
|
@ -792,7 +830,11 @@ bool ParticipantsBoxController::removeRow(not_null<UserData*> user) {
|
||||||
return false;
|
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);
|
auto row = std::make_unique<PeerListRowWithLink>(user);
|
||||||
refreshCustomStatus(row.get());
|
refreshCustomStatus(row.get());
|
||||||
if (_role == Role::Restricted || (_role == Role::Admins && _additional.adminCanEdit.find(user) != _additional.adminCanEdit.cend())) {
|
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);
|
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 {
|
void ParticipantsBoxController::refreshCustomStatus(not_null<PeerListRow*> row) const {
|
||||||
auto user = row->peer()->asUser();
|
auto user = row->peer()->asUser();
|
||||||
if (_role == Role::Admins) {
|
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);
|
_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();
|
if (_editBox) _editBox->closeBox();
|
||||||
_additional.restrictedRights.erase(user);
|
_additional.restrictedRights.erase(user);
|
||||||
_additional.restrictedBy.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();
|
if (_editBox) _editBox->closeBox();
|
||||||
_additional.adminRights.erase(user);
|
_additional.adminRights.erase(user);
|
||||||
_additional.adminCanEdit.erase(user);
|
_additional.adminCanEdit.erase(user);
|
||||||
|
@ -1380,7 +1451,10 @@ std::unique_ptr<PeerListRow> AddParticipantBoxController::createRow(not_null<Use
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Callback>
|
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()) {
|
switch (participant.type()) {
|
||||||
case mtpc_channelParticipantAdmin: {
|
case mtpc_channelParticipantAdmin: {
|
||||||
auto &admin = participant.c_channelParticipantAdmin();
|
auto &admin = participant.c_channelParticipantAdmin();
|
||||||
|
|
|
@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "mtproto/sender.h"
|
#include "mtproto/sender.h"
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
#include "base/weak_unique_ptr.h"
|
#include "base/weak_unique_ptr.h"
|
||||||
|
#include "info/profile/info_profile_members_controllers.h"
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
class Controller;
|
class Controller;
|
||||||
|
@ -102,6 +103,9 @@ protected:
|
||||||
virtual std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user) const;
|
virtual std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using Row = Info::Profile::MemberListRow;
|
||||||
|
using Type = Row::Type;
|
||||||
|
using Rights = Row::Rights;
|
||||||
struct SavedState : SavedStateBase {
|
struct SavedState : SavedStateBase {
|
||||||
std::unique_ptr<PeerListSearchController::SavedStateBase> searchState;
|
std::unique_ptr<PeerListSearchController::SavedStateBase> searchState;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
@ -133,6 +137,11 @@ private:
|
||||||
void refreshCustomStatus(not_null<PeerListRow*> row) const;
|
void refreshCustomStatus(not_null<PeerListRow*> row) const;
|
||||||
bool feedMegagroupLastParticipants();
|
bool feedMegagroupLastParticipants();
|
||||||
void refreshOnlineCount();
|
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<Window::Controller*> _window;
|
||||||
not_null<ChannelData*> _channel;
|
not_null<ChannelData*> _channel;
|
||||||
|
|
Loading…
Add table
Reference in a new issue