[Improvement] Admin ranks

This commit is contained in:
Eric Kotato 2022-09-11 04:13:57 +03:00
parent dec9de947c
commit 51808da2be
14 changed files with 276 additions and 43 deletions

View file

@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_boxes.h" #include "styles/style_boxes.h"
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include "styles/style_info.h"
#include <rpl/range.h> #include <rpl/range.h>
@ -633,9 +634,37 @@ void PeerListRow::invalidatePixmapsCache() {
} }
int PeerListRow::nameIconWidth() const { int PeerListRow::nameIconWidth() const {
return (special() || !_peer->isVerified()) if (special()) {
return 0;
}
auto hasCreatorRights = false;
auto hasAdminRights = false;
if (const auto chat = _peer->asChat()) {
if (chat->amCreator()) {
hasCreatorRights = true;
hasAdminRights = true;
} else if (chat->hasAdminRights()) {
hasAdminRights = true;
}
} else if (const auto channel = _peer->asChannel()) {
if (channel->amCreator()) {
hasCreatorRights = true;
hasAdminRights = true;
} else if (channel->hasAdminRights()) {
hasAdminRights = true;
}
}
return special()
? 0 ? 0
: st::dialogsVerifiedIcon.width(); : (_peer->isVerified()
? st::dialogsVerifiedIcon.width()
: 0)
+ (hasCreatorRights
? st::infoMembersCreatorIcon.width()
: hasAdminRights
? st::infoMembersAdminIcon.width()
: 0);
} }
void PeerListRow::paintNameIcon( void PeerListRow::paintNameIcon(
@ -644,7 +673,43 @@ void PeerListRow::paintNameIcon(
int y, int y,
int outerWidth, int outerWidth,
bool selected) { bool selected) {
st::dialogsVerifiedIcon.paint(p, x, y, outerWidth); if (special()) {
return;
}
auto hasCreatorRights = false;
auto hasAdminRights = false;
if (const auto chat = _peer->asChat()) {
if (chat->amCreator()) {
hasCreatorRights = true;
hasAdminRights = true;
} else if (chat->hasAdminRights()) {
hasAdminRights = true;
}
} else if (const auto channel = _peer->asChannel()) {
if (channel->amCreator()) {
hasCreatorRights = true;
hasAdminRights = true;
} else if (channel->hasAdminRights()) {
hasAdminRights = true;
}
}
auto icon = [&] {
return hasCreatorRights
? (selected
? &st::infoMembersCreatorIconOver
: &st::infoMembersCreatorIcon)
: (selected
? &st::infoMembersAdminIconOver
: &st::infoMembersAdminIcon);
}();
if (_peer->isVerified()) {
st::dialogsVerifiedIcon.paint(p, x, y, outerWidth);
}
if (hasAdminRights) {
icon->paint(p, x + (_peer->isVerified() ? st::dialogsVerifiedIcon.width() : 0 ), y, outerWidth);
}
} }
void PeerListRow::paintStatusText( void PeerListRow::paintStatusText(
@ -662,6 +727,10 @@ void PeerListRow::paintStatusText(
_status.drawLeftElided(p, x, y, availableWidth, outerWidth); _status.drawLeftElided(p, x, y, availableWidth, outerWidth);
} }
bool PeerListRow::hasAction() {
return true;
}
template <typename MaskGenerator, typename UpdateCallback> template <typename MaskGenerator, typename UpdateCallback>
void PeerListRow::addRipple(const style::PeerListItem &st, MaskGenerator &&maskGenerator, QPoint point, UpdateCallback &&updateCallback) { void PeerListRow::addRipple(const style::PeerListItem &st, MaskGenerator &&maskGenerator, QPoint point, UpdateCallback &&updateCallback) {
if (!_ripple) { if (!_ripple) {
@ -674,6 +743,18 @@ void PeerListRow::addRipple(const style::PeerListItem &st, MaskGenerator &&maskG
_ripple->add(point); _ripple->add(point);
} }
int PeerListRow::adminRankWidth() const {
return 0;
}
void PeerListRow::paintAdminRank(
Painter &p,
int x,
int y,
int outerWidth,
bool selected) {
}
void PeerListRow::stopLastRipple() { void PeerListRow::stopLastRipple() {
if (_ripple) { if (_ripple) {
_ripple->lastStop(); _ripple->lastStop();
@ -1538,20 +1619,22 @@ crl::time PeerListContent::paintRow(
p.setPen(st::contactsNameFg); p.setPen(st::contactsNameFg);
auto skipRight = _st.item.photoPosition.x(); auto skipRight = _st.item.photoPosition.x();
auto rightActionSize = row->rightActionSize(); auto rightActionSize = !row->rightActionSize().isEmpty()
auto rightActionMargins = rightActionSize.isEmpty() && (row->placeholderSize().isEmpty()
? QMargins() || selected)
: row->rightActionMargins(); ? row->rightActionSize()
: row->placeholderSize();
auto rightActionMargins = rightActionSize.isEmpty() ? QMargins() : row->rightActionMargins();
auto &name = row->name(); auto &name = row->name();
auto namex = _st.item.namePosition.x(); auto namex = _st.item.namePosition.x();
auto namew = outerWidth - namex - skipRight; auto namew = outerWidth - namex - skipRight;
auto statusw = namew;
if (!rightActionSize.isEmpty()) { if (!rightActionSize.isEmpty()) {
namew -= rightActionMargins.left() statusw -= rightActionMargins.left()
+ rightActionSize.width() + rightActionSize.width()
+ rightActionMargins.right() + rightActionMargins.right()
- skipRight; - skipRight;
} }
auto statusw = namew;
if (auto iconWidth = row->nameIconWidth()) { if (auto iconWidth = row->nameIconWidth()) {
namew -= iconWidth; namew -= iconWidth;
row->paintNameIcon( row->paintNameIcon(
@ -1561,6 +1644,17 @@ crl::time PeerListContent::paintRow(
width(), width(),
selected); selected);
} }
if (auto adminRankWidth = row->adminRankWidth()) {
namew -= adminRankWidth + skipRight;
auto rankx = width() - adminRankWidth - skipRight;
p.setFont(st::normalFont);
row->paintAdminRank(
p,
rankx,
_st.item.namePosition.y(),
width(),
selected);
}
auto nameCheckedRatio = row->disabled() ? 0. : row->checkedRatio(); auto nameCheckedRatio = row->disabled() ? 0. : row->checkedRatio();
p.setPen(anim::pen(_st.item.nameFg, _st.item.nameFgChecked, nameCheckedRatio)); p.setPen(anim::pen(_st.item.nameFg, _st.item.nameFgChecked, nameCheckedRatio));
name.drawLeftElided(p, namex, _st.item.namePosition.y(), namew, width()); name.drawLeftElided(p, namex, _st.item.namePosition.y(), namew, width());

View file

@ -101,10 +101,20 @@ public:
int y, int y,
int outerWidth, int outerWidth,
bool selected); bool selected);
virtual int adminRankWidth() const;
virtual void paintAdminRank(
Painter &p,
int x,
int y,
int outerWidth,
bool selected);
virtual QSize rightActionSize() const { virtual QSize rightActionSize() const {
return QSize(); return QSize();
} }
virtual QSize placeholderSize() const {
return QSize();
}
virtual QMargins rightActionMargins() const { virtual QMargins rightActionMargins() const {
return QMargins(); return QMargins();
} }
@ -231,6 +241,8 @@ public:
int outerWidth, int outerWidth,
bool selected); bool selected);
virtual bool hasAction();
protected: protected:
bool isInitialized() const { bool isInitialized() const {
return _initialized; return _initialized;

View file

@ -146,9 +146,16 @@ void PeerListRowWithLink::setActionLink(const QString &action) {
refreshActionLink(); refreshActionLink();
} }
void PeerListRowWithLink::setActionPlaceholder(const QString &placeholder, bool active) {
_actionPlaceholder = placeholder;
_actionPlaceholderActive = active;
refreshActionLink();
}
void PeerListRowWithLink::refreshActionLink() { void PeerListRowWithLink::refreshActionLink() {
if (!isInitialized()) return; if (!isInitialized()) return;
_actionWidth = _action.isEmpty() ? 0 : st::normalFont->width(_action); _actionWidth = _action.isEmpty() ? 0 : st::normalFont->width(_action);
_actionPlaceholderWidth = _actionPlaceholder.isEmpty() ? 0 : st::normalFont->width(_actionPlaceholder);
} }
void PeerListRowWithLink::lazyInitialize(const style::PeerListItem &st) { void PeerListRowWithLink::lazyInitialize(const style::PeerListItem &st) {
@ -156,10 +163,18 @@ void PeerListRowWithLink::lazyInitialize(const style::PeerListItem &st) {
refreshActionLink(); refreshActionLink();
} }
bool PeerListRowWithLink::hasAction() {
return !_action.isEmpty();
}
QSize PeerListRowWithLink::rightActionSize() const { QSize PeerListRowWithLink::rightActionSize() const {
return QSize(_actionWidth, st::normalFont->height); return QSize(_actionWidth, st::normalFont->height);
} }
QSize PeerListRowWithLink::placeholderSize() const {
return QSize(_actionPlaceholderWidth, st::normalFont->height);
}
QMargins PeerListRowWithLink::rightActionMargins() const { QMargins PeerListRowWithLink::rightActionMargins() const {
return QMargins( return QMargins(
st::contactsCheckPosition.x(), st::contactsCheckPosition.x(),
@ -175,9 +190,45 @@ void PeerListRowWithLink::rightActionPaint(
int outerWidth, int outerWidth,
bool selected, bool selected,
bool actionSelected) { bool actionSelected) {
p.setFont(actionSelected ? st::linkOverFont : st::linkFont); if (!_action.isEmpty() && ((_actionPlaceholder.isEmpty() && _adminRank.isEmpty()) || selected)) {
p.setPen(actionSelected ? st::defaultLinkButton.overColor : st::defaultLinkButton.color); p.setFont(actionSelected ? st::linkOverFont : st::linkFont);
p.drawTextLeft(x, y, outerWidth, _action, _actionWidth); p.setPen(actionSelected ? st::defaultLinkButton.overColor : st::defaultLinkButton.color);
p.drawTextLeft(x, y, outerWidth, _action, _actionWidth);
} else {
p.setFont(st::linkFont);
p.setPen(_actionPlaceholderActive
? st::defaultPeerListItem.statusFgActive
: selected
? st::defaultPeerListItem.statusFgOver
: st::defaultPeerListItem.statusFg);
p.drawTextLeft(x, y, outerWidth, _actionPlaceholder, _actionPlaceholderWidth);
}
}
void PeerListRowWithLink::setAdminRank(const QString &rank, bool isCreator) {
_adminRank = rank;
_isCreator = isCreator;
}
int PeerListRowWithLink::adminRankWidth() const {
return st::normalFont->width(_adminRank);
}
void PeerListRowWithLink::paintAdminRank(
Painter &p,
int x,
int y,
int outerWidth,
bool selected) {
if (hasAction() && selected) {
return;
}
p.setPen(_isCreator
? st::defaultPeerListItem.statusFgActive
: selected
? st::defaultPeerListItem.statusFgOver
: st::defaultPeerListItem.statusFg);
p.drawTextLeft(x, y, outerWidth, _adminRank, adminRankWidth());
} }
PeerListGlobalSearchController::PeerListGlobalSearchController( PeerListGlobalSearchController::PeerListGlobalSearchController(

View file

@ -43,12 +43,24 @@ public:
using PeerListRow::PeerListRow; using PeerListRow::PeerListRow;
void setActionLink(const QString &action); void setActionLink(const QString &action);
void setActionPlaceholder(const QString &placeholder, bool active = false);
void lazyInitialize(const style::PeerListItem &st) override; void lazyInitialize(const style::PeerListItem &st) override;
bool hasAction() override;
void setAdminRank(const QString &rank, bool isCreator = false);
int adminRankWidth() const override;
void paintAdminRank(
Painter &p,
int x,
int y,
int outerWidth,
bool selected) override;
private: private:
void refreshActionLink(); void refreshActionLink();
QSize rightActionSize() const override; QSize rightActionSize() const override;
QSize placeholderSize() const override;
QMargins rightActionMargins() const override; QMargins rightActionMargins() const override;
void rightActionPaint( void rightActionPaint(
Painter &p, Painter &p,
@ -59,8 +71,13 @@ private:
bool actionSelected) override; bool actionSelected) override;
QString _action; QString _action;
QString _actionPlaceholder;
bool _actionPlaceholderActive = false;
int _actionWidth = 0; int _actionWidth = 0;
int _actionPlaceholderWidth = 0;
QString _adminRank;
bool _isCreator = false;
}; };
class PeerListGlobalSearchController : public PeerListSearchController { class PeerListGlobalSearchController : public PeerListSearchController {

View file

@ -60,6 +60,7 @@ public:
template <typename Widget> template <typename Widget>
Widget *addControl(object_ptr<Widget> widget, QMargins margin); Widget *addControl(object_ptr<Widget> widget, QMargins margin);
void setCustomStatus(const QString &status);
protected: protected:
int resizeGetHeight(int newWidth) override; int resizeGetHeight(int newWidth) override;
@ -72,6 +73,7 @@ private:
Ui::Text::String _userName; Ui::Text::String _userName;
bool _hasAdminRights = false; bool _hasAdminRights = false;
object_ptr<Ui::VerticalLayout> _rows; object_ptr<Ui::VerticalLayout> _rows;
QString _customStatus;
}; };
@ -109,6 +111,10 @@ Widget *EditParticipantBox::Inner::addControl(
return _rows->add(std::move(widget), margin); return _rows->add(std::move(widget), margin);
} }
void EditParticipantBox::Inner::setCustomStatus(const QString &status) {
_customStatus = status;
}
int EditParticipantBox::Inner::resizeGetHeight(int newWidth) { int EditParticipantBox::Inner::resizeGetHeight(int newWidth) {
_userPhoto->moveToLeft( _userPhoto->moveToLeft(
st::rightsPhotoMargin.left(), st::rightsPhotoMargin.left(),
@ -138,6 +144,10 @@ void EditParticipantBox::Inner::paintEvent(QPaintEvent *e) {
namew, namew,
width()); width());
const auto statusText = [&] { const auto statusText = [&] {
if (!_customStatus.isEmpty()) {
return _customStatus;
}
if (_user->isBot()) { if (_user->isBot()) {
const auto seesAllMessages = _user->botInfo->readsAllHistory const auto seesAllMessages = _user->botInfo->readsAllHistory
|| _hasAdminRights; || _hasAdminRights;
@ -166,6 +176,13 @@ EditParticipantBox::EditParticipantBox(
, _hasAdminRights(hasAdminRights) { , _hasAdminRights(hasAdminRights) {
} }
void EditParticipantBox::setCustomStatus(const QString &status) {
_customStatus = status;
if (_inner) {
_inner->setCustomStatus(status);
}
}
void EditParticipantBox::prepare() { void EditParticipantBox::prepare() {
_inner = setInnerWidget(object_ptr<Inner>( _inner = setInnerWidget(object_ptr<Inner>(
this, this,
@ -173,6 +190,7 @@ void EditParticipantBox::prepare() {
_user, _user,
hasAdminRights())); hasAdminRights()));
setDimensionsToContent(st::boxWideWidth, _inner); setDimensionsToContent(st::boxWideWidth, _inner);
_inner->setCustomStatus(_customStatus);
} }
template <typename Widget> template <typename Widget>

View file

@ -36,6 +36,7 @@ public:
not_null<UserData*> user, not_null<UserData*> user,
bool hasAdminRights); bool hasAdminRights);
void setCustomStatus(const QString &status);
protected: protected:
void prepare() override; void prepare() override;
@ -61,6 +62,7 @@ private:
class Inner; class Inner;
QPointer<Inner> _inner; QPointer<Inner> _inner;
QString _customStatus;
}; };

View file

@ -1912,10 +1912,17 @@ std::unique_ptr<PeerListRow> ParticipantsBoxController::createRow(
refreshCustomStatus(row.get()); refreshCustomStatus(row.get());
if (_role == Role::Admins if (_role == Role::Admins
&& user && user
&& !_additional.isCreator(user) && (_additional.adminRights(user).has_value()
&& _additional.adminRights(user).has_value() || _additional.isCreator(user))) {
&& _additional.canEditAdmin(user)) { if (_additional.canEditAdmin(user) && !_additional.isCreator(user)) {
row->setActionLink(tr::lng_profile_kick(tr::now)); row->setActionLink(tr::lng_profile_kick(tr::now));
}
row->setAdminRank(channel
? channel->adminRank(user)
: (chat && _additional.isCreator(user))
? tr::lng_owner_badge(tr::now)
: QString(),
_additional.isCreator(user));
} else if (_role == Role::Kicked || _role == Role::Restricted) { } else if (_role == Role::Kicked || _role == Role::Restricted) {
if (_additional.canRestrictParticipant(participant)) { if (_additional.canRestrictParticipant(participant)) {
row->setActionLink(tr::lng_profile_delete_removed(tr::now)); row->setActionLink(tr::lng_profile_delete_removed(tr::now));
@ -1948,6 +1955,11 @@ auto ParticipantsBoxController::computeType(
? Rights::Admin ? Rights::Admin
: Rights::Normal; : Rights::Normal;
result.canRemove = _additional.canRemoveParticipant(participant); result.canRemove = _additional.canRemoveParticipant(participant);
if (user) {
if (const auto channel = _peer->asChannel()) {
result.adminRank = channel->adminRank(user);
}
}
return result; return result;
} }

View file

@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_histories.h" #include "data/data_histories.h"
#include "data/data_group_call.h" #include "data/data_group_call.h"
#include "data/data_message_reactions.h" #include "data/data_message_reactions.h"
#include "lang/lang_keys.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "main/session/send_as_peers.h" #include "main/session/send_as_peers.h"
#include "base/unixtime.h" #include "base/unixtime.h"
@ -403,6 +404,26 @@ bool ChannelData::lastParticipantsRequestNeeded() const {
& MegagroupInfo::LastParticipantsCountOutdated); & MegagroupInfo::LastParticipantsCountOutdated);
} }
QString ChannelData::adminRank(not_null<UserData*> user) const {
if (!isGroupAdmin(user)) {
return QString();
}
const auto info = mgInfo.get();
const auto i = mgInfo->admins.find(peerToUser(user->id));
const auto custom = (i != mgInfo->admins.end())
? i->second
: (info->creator == user)
? info->creatorRank
: QString();
return !custom.isEmpty()
? custom
: (info->creator == user)
? tr::lng_owner_badge(tr::now)
: (i != mgInfo->admins.end())
? tr::lng_admin_badge(tr::now)
: QString();
}
auto ChannelData::unavailableReasons() const auto ChannelData::unavailableReasons() const
-> const std::vector<Data::UnavailableReason> & { -> const std::vector<Data::UnavailableReason> & {
return _unavailableReasons; return _unavailableReasons;

View file

@ -233,6 +233,7 @@ public:
void markForbidden(); void markForbidden();
[[nodiscard]] bool isGroupAdmin(not_null<UserData*> user) const; [[nodiscard]] bool isGroupAdmin(not_null<UserData*> user) const;
[[nodiscard]] QString adminRank(not_null<UserData*> user) const;
[[nodiscard]] bool lastParticipantsRequestNeeded() const; [[nodiscard]] bool lastParticipantsRequestNeeded() const;
[[nodiscard]] bool isMegagroup() const { [[nodiscard]] bool isMegagroup() const {
return flags() & Flag::Megagroup; return flags() & Flag::Megagroup;

View file

@ -62,34 +62,29 @@ void MemberListRow::rightActionPaint(
} }
} }
int MemberListRow::nameIconWidth() const { int MemberListRow::adminRankWidth() const {
return (_type.rights == Rights::Admin) return st::normalFont->width(_type.adminRank);
? st::infoMembersAdminIcon.width()
: (_type.rights == Rights::Creator)
? st::infoMembersCreatorIcon.width()
: 0;
} }
not_null<UserData*> MemberListRow::user() const { not_null<UserData*> MemberListRow::user() const {
return peer()->asUser(); return peer()->asUser();
} }
void MemberListRow::paintNameIcon( void MemberListRow::paintAdminRank(
Painter &p, Painter &p,
int x, int x,
int y, int y,
int outerWidth, int outerWidth,
bool selected) { bool selected) {
auto icon = [&] { if (_type.canRemove && selected) {
return (_type.rights == Rights::Admin) return;
? (selected }
? &st::infoMembersAdminIconOver p.setPen(_type.rights == Rights::Creator
: &st::infoMembersAdminIcon) ? st::defaultPeerListItem.statusFgActive
: (selected : selected
? &st::infoMembersCreatorIconOver ? st::defaultPeerListItem.statusFgOver
: &st::infoMembersCreatorIcon); : st::defaultPeerListItem.statusFg);
}(); p.drawTextLeft(x, y, outerWidth, _type.adminRank, adminRankWidth());
icon->paint(p, x, y, outerWidth);
} }
void MemberListRow::refreshStatus() { void MemberListRow::refreshStatus() {

View file

@ -26,6 +26,7 @@ public:
struct Type { struct Type {
Rights rights; Rights rights;
bool canRemove = false; bool canRemove = false;
QString adminRank;
}; };
MemberListRow(not_null<UserData*> user, Type type); MemberListRow(not_null<UserData*> user, Type type);
@ -39,8 +40,8 @@ public:
int outerWidth, int outerWidth,
bool selected, bool selected,
bool actionSelected) override; bool actionSelected) override;
int nameIconWidth() const override; int adminRankWidth() const override;
void paintNameIcon( void paintAdminRank(
Painter &p, Painter &p,
int x, int x,
int y, int y,

View file

@ -307,6 +307,10 @@ void GroupMembersWidget::setItemFlags(
? AdminState::Admin ? AdminState::Admin
: AdminState::None; : AdminState::None;
item->adminState = adminState; item->adminState = adminState;
if (isCreator) {
item->adminRank = tr::lng_owner_badge(tr::now);
item->adminRankWidth = st::normalFont->width(item->adminRank);
}
if (item->peer->id == chat->session().userPeerId()) { if (item->peer->id == chat->session().userPeerId()) {
item->hasRemoveLink = false; item->hasRemoveLink = false;
} else if (chat->amCreator() } else if (chat->amCreator()
@ -410,6 +414,8 @@ void GroupMembersWidget::setItemFlags(
updateItemStatusText(item); updateItemStatusText(item);
} }
} }
item->adminRank = megagroup->adminRank(item->peer->asUser());
item->adminRankWidth = st::normalFont->width(item->adminRank);
if (item->peer->isSelf()) { if (item->peer->isSelf()) {
item->hasRemoveLink = false; item->hasRemoveLink = false;
} else if (megagroup->amCreator() || (megagroup->canBanMembers() && ((adminState == AdminState::None) || adminCanEdit))) { } else if (megagroup->amCreator() || (megagroup->canBanMembers() && ((adminState == AdminState::None) || adminCanEdit))) {

View file

@ -110,14 +110,15 @@ void PeerListWidget::paintItem(Painter &p, int x, int y, Item *item, bool select
p.setPen(st::windowActiveTextFg); p.setPen(st::windowActiveTextFg);
p.drawTextLeft(nameLeft + nameWidth - _removeWidth, nameTop, width(), _removeText, _removeWidth); p.drawTextLeft(nameLeft + nameWidth - _removeWidth, nameTop, width(), _removeText, _removeWidth);
nameWidth -= _removeWidth + skip; nameWidth -= _removeWidth + skip;
} } else if (item->adminState != Item::AdminState::None) {
if (item->adminState != Item::AdminState::None) { p.setFont(st::normalFont);
nameWidth -= st::profileMemberAdminIcon.width(); p.setPen(item->adminState == Item::AdminState::Creator
auto iconLeft = nameLeft + qMin(nameWidth, item->name.maxWidth()); ? _st.statusFgActive
auto &icon = (item->adminState == Item::AdminState::Creator) : selected
? (selected ? st::profileMemberCreatorIconOver : st::profileMemberCreatorIcon) ? _st.statusFgOver
: (selected ? st::profileMemberAdminIconOver : st::profileMemberAdminIcon); : _st.statusFg);
icon.paint(p, QPoint(iconLeft, nameTop), width()); p.drawTextLeft(nameLeft + nameWidth - item->adminRankWidth, nameTop, width(), item->adminRank, item->adminRankWidth);
nameWidth -= item->adminRankWidth + skip;
} }
p.setPen(st::profileMemberNameFg); p.setPen(st::profileMemberNameFg);
item->name.drawLeftElided(p, nameLeft, nameTop, nameWidth, width()); item->name.drawLeftElided(p, nameLeft, nameTop, nameWidth, width());

View file

@ -43,6 +43,8 @@ public:
Creator, Creator,
}; };
AdminState adminState = AdminState::None; AdminState adminState = AdminState::None;
QString adminRank;
int adminRankWidth = 0;
bool hasRemoveLink = false; bool hasRemoveLink = false;
std::unique_ptr<Ui::RippleAnimation> ripple; std::unique_ptr<Ui::RippleAnimation> ripple;
}; };