Add SCAM badge for users and channels.

This commit is contained in:
John Preston 2019-06-23 14:18:33 +02:00
parent 88b7387a40
commit 352839337d
17 changed files with 332 additions and 61 deletions

View File

@ -195,6 +195,7 @@ dialogsUnreadBgMuted: #bbbbbb; // chat list unread badge background for muted ch
dialogsUnreadFg: windowFgActive; // chat list unread badge text
dialogsArchiveFg: #525252 | dialogsNameFg; // chat list archive name text
dialogsOnlineBadgeFg: #4dc920 | dialogsUnreadBg; // chat list online status
dialogsScamFg: dialogsDraftFg; // chat list scam label
dialogsBgOver: windowBgOver; // chat list background with mouse over
dialogsNameFgOver: windowBoldFgOver; // chat list name text with mouse over
@ -210,7 +211,8 @@ dialogsSentIconFgOver: dialogsSentIconFg; // chat list sent message tick / doubl
dialogsUnreadBgOver: dialogsUnreadBg; // chat list unread badge background for not muted chat with mouse over
dialogsUnreadBgMutedOver: dialogsUnreadBgMuted; // chat list unread badge background for muted chat with mouse over
dialogsUnreadFgOver: dialogsUnreadFg; // chat list unread badge text with mouse over
dialogsArchiveFgOver: #525252 | dialogsNameFgOver; // chat list archive name text
dialogsArchiveFgOver: #525252 | dialogsNameFgOver; // chat list archive name text with mouse over
dialogsScamFgOver: dialogsDraftFgOver; // chat list scam label with mouse over
dialogsBgActive: #419fd9; // chat list background for current (active) chat
dialogsNameFgActive: windowFgActive; // chat list name text for current (active) chat
@ -227,6 +229,7 @@ dialogsUnreadBgActive: dialogsTextFgActive; // chat list unread badge background
dialogsUnreadBgMutedActive: dialogsDraftFgActive; // chat list unread badge background for muted chat for current (active) chat
dialogsUnreadFgActive: dialogsBgActive; // chat list unread badge text for current (active) chat
dialogsOnlineBadgeFgActive: #ffffff; // chat list online status for current (active) chat
dialogsScamFgActive: dialogsDraftFgActive; // chat list scam label for current (active) chat
dialogsRippleBg: windowBgRipple; // chat list background ripple effect
dialogsRippleBgActive: activeButtonBgRipple; // chat list background ripple effect for current (active) chat

View File

@ -119,6 +119,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_channel_status" = "channel";
"lng_group_status" = "group";
"lng_scam_badge" = "SCAM";
"lng_flood_error" = "Too many tries. Please try again later.";
"lng_gif_error" = "An error has occurred while reading GIF animation :(";

View File

@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/toast/toast.h"
#include "ui/special_buttons.h"
#include "ui/text_options.h"
#include "ui/unread_badge.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_user.h"
@ -1399,11 +1400,21 @@ void RevokePublicLinkBox::Inner::paintChat(Painter &p, const ChatRow &row, bool
int32 namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
int32 namew = width() - namex - st::contactsPadding.right() - (_revokeWidth + st::contactsCheckPosition.x() * 2);
if (peer->isVerified()) {
auto icon = &st::dialogsVerifiedIcon;
namew -= icon->width();
icon->paint(p, namex + qMin(row.name.maxWidth(), namew), st::contactsPadding.top() + st::contactsNameTop, width());
}
const auto badgeStyle = Ui::PeerBadgeStyle{
&st::dialogsVerifiedIcon,
&st::attentionButtonFg };
namew -= Ui::DrawPeerBadgeGetWidth(
peer,
p,
QRect(
namex,
st::contactsPadding.top() + st::contactsNameTop,
row.name.maxWidth(),
st::contactsNameStyle.font->height),
namew,
width(),
badgeStyle);
row.name.drawLeftElided(p, namex, st::contactsPadding.top() + st::contactsNameTop, namew, width());
p.setFont(selected ? st::linkOverFont : st::linkFont);

View File

@ -91,6 +91,7 @@ public:
| MTPDchannel_ClientFlag::f_forbidden
| MTPDchannel::Flag::f_broadcast
| MTPDchannel::Flag::f_verified
| MTPDchannel::Flag::f_scam
| MTPDchannel::Flag::f_megagroup
| MTPDchannel::Flag::f_restricted
| MTPDchannel::Flag::f_signatures
@ -192,6 +193,9 @@ public:
bool isVerified() const {
return flags() & MTPDchannel::Flag::f_verified;
}
bool isScam() const {
return flags() & MTPDchannel::Flag::f_scam;
}
static MTPChatBannedRights KickedRestrictedRights();
static constexpr auto kRestrictUntilForever = TimeId(INT_MAX);

View File

@ -618,19 +618,30 @@ const QString &PeerData::shortName() const {
}
QString PeerData::userName() const {
return isUser()
? asUser()->username
: isChannel()
? asChannel()->username
: QString();
if (const auto user = asUser()) {
return user->username;
} else if (const auto channel = asChannel()) {
return channel->username;
}
return QString();
}
bool PeerData::isVerified() const {
return isUser()
? asUser()->isVerified()
: isChannel()
? asChannel()->isVerified()
: false;
if (const auto user = asUser()) {
return user->isVerified();
} else if (const auto channel = asChannel()) {
return channel->isVerified();
}
return false;
}
bool PeerData::isScam() const {
if (const auto user = asUser()) {
return user->isScam();
} else if (const auto channel = asChannel()) {
return channel->isScam();
}
return false;
}
bool PeerData::isMegagroup() const {
@ -638,13 +649,14 @@ bool PeerData::isMegagroup() const {
}
bool PeerData::canWrite() const {
return isChannel()
? asChannel()->canWrite()
: isChat()
? asChat()->canWrite()
: isUser()
? asUser()->canWrite()
: false;
if (const auto user = asUser()) {
return user->canWrite();
} else if (const auto channel = asChannel()) {
return channel->canWrite();
} else if (const auto chat = asChat()) {
return chat->canWrite();
}
return false;
}
Data::RestrictionCheckResult PeerData::amRestricted(

View File

@ -141,6 +141,7 @@ public:
return (input.type() == mtpc_inputPeerSelf);
}
[[nodiscard]] bool isVerified() const;
[[nodiscard]] bool isScam() const;
[[nodiscard]] bool isMegagroup() const;
[[nodiscard]] bool isNotificationsUser() const {

View File

@ -48,6 +48,7 @@ public:
| MTPDuser::Flag::f_bot_chat_history
| MTPDuser::Flag::f_bot_nochats
| MTPDuser::Flag::f_verified
| MTPDuser::Flag::f_scam
| MTPDuser::Flag::f_restricted
| MTPDuser::Flag::f_bot_inline_geo;
using Flags = Data::Flags<
@ -119,6 +120,9 @@ public:
bool isVerified() const {
return flags() & MTPDuser::Flag::f_verified;
}
bool isScam() const {
return flags() & MTPDuser::Flag::f_scam;
}
bool isBotInlineGeo() const {
return flags() & MTPDuser::Flag::f_bot_inline_geo;
}

View File

@ -268,3 +268,9 @@ dialogsSearchFromStyle: TextStyle(defaultTextStyle) {
dialogsSearchFromPalette: TextPalette(defaultTextPalette) {
linkFg: dialogsNameFg;
}
dialogsScamPadding: margins(2px, 0px, 2px, 0px);
dialogsScamFont: font(9px semibold);
dialogsScamSkip: 4px;
dialogsScamRadius: 2px;

View File

@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_peer_menu.h"
#include "ui/widgets/multi_select.h"
#include "ui/empty_userpic.h"
#include "ui/unread_badge.h"
#include "styles/style_dialogs.h"
#include "styles/style_chat_helpers.h"
#include "styles/style_window.h"
@ -736,11 +737,25 @@ void InnerWidget::paintPeerSearchResult(
chatTypeIcon->paint(p, rectForName.topLeft(), fullWidth);
rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip);
}
if (peer->isVerified()) {
auto icon = &(active ? st::dialogsVerifiedIconActive : (selected ? st::dialogsVerifiedIconOver : st::dialogsVerifiedIcon));
rectForName.setWidth(rectForName.width() - icon->width());
icon->paint(p, rectForName.topLeft() + QPoint(qMin(peer->nameText().maxWidth(), rectForName.width()), 0), fullWidth);
}
const auto badgeStyle = Ui::PeerBadgeStyle{
(active
? &st::dialogsVerifiedIconActive
: selected
? &st::dialogsVerifiedIconOver
: &st::dialogsVerifiedIcon),
(active
? &st::dialogsScamFgActive
: selected
? &st::dialogsScamFgOver
: &st::dialogsScamFg) };
const auto badgeWidth = Ui::DrawPeerBadgeGetWidth(
peer,
p,
rectForName,
peer->nameText().maxWidth(),
fullWidth,
badgeStyle);
rectForName.setWidth(rectForName.width() - badgeWidth);
QRect tr(nameleft, st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip, namewidth, st::dialogsTextFont->height);
p.setFont(st::dialogsTextFont);

View File

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/localstorage.h"
#include "ui/empty_userpic.h"
#include "ui/text_options.h"
#include "ui/unread_badge.h"
#include "lang/lang_keys.h"
#include "support/support_helper.h"
#include "history/history_item_components.h"
@ -406,26 +407,46 @@ void paintRow(
sendStateIcon->paint(p, rectForName.topLeft() + QPoint(rectForName.width(), 0), fullWidth);
}
const auto nameFg = active
? st::dialogsNameFgActive
: (selected
? st::dialogsNameFgOver
: st::dialogsNameFg);
p.setPen(nameFg);
if (flags & Flag::SavedMessages) {
p.setFont(st::msgNameFont);
auto text = tr::lng_saved_messages(tr::now);
auto textWidth = st::msgNameFont->width(text);
const auto textWidth = st::msgNameFont->width(text);
if (textWidth > rectForName.width()) {
text = st::msgNameFont->elided(text, rectForName.width());
}
p.setFont(st::msgNameFont);
p.setPen(active
? st::dialogsNameFgActive
: selected
? st::dialogsNameFgOver
: st::dialogsNameFg);
p.drawTextLeft(rectForName.left(), rectForName.top(), fullWidth, text);
} else if (from) {
if (!(flags & Flag::SearchResult) && from->isVerified()) {
auto icon = &(active ? st::dialogsVerifiedIconActive : (selected ? st::dialogsVerifiedIconOver : st::dialogsVerifiedIcon));
rectForName.setWidth(rectForName.width() - icon->width());
icon->paint(p, rectForName.topLeft() + QPoint(qMin(from->nameText().maxWidth(), rectForName.width()), 0), fullWidth);
if (!(flags & Flag::SearchResult)) {
const auto badgeStyle = Ui::PeerBadgeStyle{
(active
? &st::dialogsVerifiedIconActive
: selected
? &st::dialogsVerifiedIconOver
: &st::dialogsVerifiedIcon),
(active
? &st::dialogsScamFgActive
: selected
? &st::dialogsScamFgOver
: &st::dialogsScamFg) };
const auto badgeWidth = Ui::DrawPeerBadgeGetWidth(
from,
p,
rectForName,
from->nameText().maxWidth(),
fullWidth,
badgeStyle);
rectForName.setWidth(rectForName.width() - badgeWidth);
}
p.setPen(active
? st::dialogsNameFgActive
: selected
? st::dialogsNameFgOver
: st::dialogsNameFg);
from->nameText().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
} else if (hiddenSenderInfo) {
hiddenSenderInfo->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());

View File

@ -304,17 +304,17 @@ void TopBarWidget::paintTopBar(Painter &p) {
auto nameleft = _leftTaken;
auto nametop = st::topBarArrowPadding.top();
auto statustop = st::topBarHeight - st::topBarArrowPadding.bottom() - st::dialogsTextFont->height;
auto namewidth = width() - _rightTaken - nameleft;
auto availableWidth = width() - _rightTaken - nameleft;
auto history = _activeChat.history();
p.setPen(st::dialogsNameFg);
if (const auto folder = _activeChat.folder()) {
auto text = folder->chatListName(); // TODO feed name emoji
auto textWidth = st::historySavedFont->width(text);
if (namewidth < textWidth) {
text = st::historySavedFont->elided(text, namewidth);
const auto textWidth = st::historySavedFont->width(text);
if (availableWidth < textWidth) {
text = st::historySavedFont->elided(text, availableWidth);
}
p.setPen(st::dialogsNameFg);
p.setFont(st::historySavedFont);
p.drawTextLeft(
nameleft,
@ -323,10 +323,11 @@ void TopBarWidget::paintTopBar(Painter &p) {
text);
} else if (_activeChat.peer()->isSelf()) {
auto text = tr::lng_saved_messages(tr::now);
auto textWidth = st::historySavedFont->width(text);
if (namewidth < textWidth) {
text = st::historySavedFont->elided(text, namewidth);
const auto textWidth = st::historySavedFont->width(text);
if (availableWidth < textWidth) {
text = st::historySavedFont->elided(text, availableWidth);
}
p.setPen(st::dialogsNameFg);
p.setFont(st::historySavedFont);
p.drawTextLeft(
nameleft,
@ -334,7 +335,30 @@ void TopBarWidget::paintTopBar(Painter &p) {
width(),
text);
} else if (const auto history = _activeChat.history()) {
history->peer->topBarNameText().drawElided(p, nameleft, nametop, namewidth);
const auto peer = history->peer;
const auto &text = peer->topBarNameText();
const auto badgeStyle = Ui::PeerBadgeStyle{
nullptr,
&st::attentionButtonFg };
const auto badgeWidth = Ui::DrawPeerBadgeGetWidth(
peer,
p,
QRect(
nameleft,
nametop,
availableWidth,
st::msgNameStyle.font->height),
text.maxWidth(),
width(),
badgeStyle);
const auto namewidth = availableWidth - badgeWidth;
p.setPen(st::dialogsNameFg);
peer->topBarNameText().drawElided(
p,
nameleft,
nametop,
namewidth);
p.setFont(st::dialogsTextFont);
if (paintConnectingState(p, nameleft, statustop, width())) {
@ -343,13 +367,13 @@ void TopBarWidget::paintTopBar(Painter &p) {
p,
nameleft,
statustop,
namewidth,
availableWidth,
width(),
st::historyStatusFgTyping,
crl::now())) {
return;
} else {
paintStatus(p, nameleft, statustop, namewidth, width());
paintStatus(p, nameleft, statustop, availableWidth, width());
}
}
}

View File

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/ripple_animation.h"
#include "ui/text/text_utilities.h" // Ui::Text::ToUpper
#include "ui/special_buttons.h"
#include "ui/unread_badge.h"
#include "window/window_session_controller.h"
#include "observer_peer.h"
#include "core/application.h"
@ -316,9 +317,14 @@ void Cover::initViewers(rpl::producer<QString> title) {
}
VerifiedValue(
_peer
) | rpl::start_with_next(
[=](bool verified) { setVerified(verified); },
lifetime());
) | rpl::start_with_next([=](bool verified) {
setVerified(verified);
}, lifetime());
ScamValue(
_peer
) | rpl::start_with_next([=](bool scam) {
setScam(scam);
}, lifetime());
}
void Cover::refreshUploadPhotoOverlay() {
@ -337,6 +343,7 @@ void Cover::setVerified(bool verified) {
return;
}
if (verified) {
_scamBadge.destroy();
_verifiedCheck.create(this);
_verifiedCheck->show();
_verifiedCheck->resize(st::infoVerifiedCheck.size());
@ -351,6 +358,34 @@ void Cover::setVerified(bool verified) {
refreshNameGeometry(width());
}
void Cover::setScam(bool scam) {
if ((_scamBadge != nullptr) == scam) {
return;
}
if (scam) {
_verifiedCheck.destroy();
const auto size = Ui::ScamBadgeSize();
const auto skip = st::infoVerifiedCheckPosition.x();
_scamBadge.create(this);
_scamBadge->show();
_scamBadge->resize(
size.width() + 2 * skip,
size.height() + 2 * skip);
_scamBadge->paintRequest(
) | rpl::start_with_next([=, badge = _scamBadge.data()] {
Painter p(badge);
Ui::DrawScamBadge(
p,
badge->rect().marginsRemoved({ skip, skip, skip, skip }),
badge->width(),
st::attentionButtonFg);
}, _scamBadge->lifetime());
} else {
_scamBadge.destroy();
}
refreshNameGeometry(width());
}
void Cover::refreshStatusText() {
auto hasMembersLink = [&] {
if (auto megagroup = _peer->asMegagroup()) {
@ -409,17 +444,29 @@ void Cover::refreshNameGeometry(int newWidth) {
- toggleSkip();
if (_verifiedCheck) {
nameWidth -= st::infoVerifiedCheckPosition.x()
+ st::infoVerifiedCheck.width();
+ _verifiedCheck->width();
} else if (_scamBadge) {
nameWidth -= st::infoVerifiedCheckPosition.x()
+ _scamBadge->width();
}
_name->resizeToNaturalWidth(nameWidth);
_name->moveToLeft(nameLeft, nameTop, newWidth);
if (_verifiedCheck) {
auto checkLeft = nameLeft
const auto checkLeft = nameLeft
+ _name->width()
+ st::infoVerifiedCheckPosition.x();
auto checkTop = nameTop
const auto checkTop = nameTop
+ st::infoVerifiedCheckPosition.y();
_verifiedCheck->moveToLeft(checkLeft, checkTop, newWidth);
} else if (_scamBadge) {
const auto skip = st::infoVerifiedCheckPosition.x();
const auto badgeLeft = nameLeft
+ _name->width()
+ st::infoVerifiedCheckPosition.x()
- skip;
const auto badgeTop = nameTop
+ (_name->height() - _scamBadge->height()) / 2;
_scamBadge->moveToLeft(badgeLeft, badgeTop, newWidth);
}
}

View File

@ -86,6 +86,7 @@ private:
void refreshStatusGeometry(int newWidth);
void refreshUploadPhotoOverlay();
void setVerified(bool verified);
void setScam(bool scam);
not_null<PeerData*> _peer;
int _onlineCount = 0;
@ -93,6 +94,7 @@ private:
object_ptr<Ui::UserpicButton> _userpic;
object_ptr<Ui::FlatLabel> _name = { nullptr };
object_ptr<Ui::RpWidget> _verifiedCheck = { nullptr };
object_ptr<Ui::RpWidget> _scamBadge = { nullptr };
object_ptr<Ui::FlatLabel> _status = { nullptr };
//object_ptr<CoverDropArea> _dropArea = { nullptr };
base::Timer _refreshStatusTimer;

View File

@ -310,14 +310,14 @@ rpl::producer<int> CommonGroupsCountValue(not_null<UserData*> user) {
}
rpl::producer<bool> CanAddMemberValue(not_null<PeerData*> peer) {
if (auto chat = peer->asChat()) {
if (const auto chat = peer->asChat()) {
return Notify::PeerUpdateValue(
chat,
Notify::PeerUpdate::Flag::RightsChanged
) | rpl::map([=] {
return chat->canAddMembers();
});
} else if (auto channel = peer->asChannel()) {
} else if (const auto channel = peer->asChannel()) {
return Notify::PeerUpdateValue(
channel,
Notify::PeerUpdate::Flag::RightsChanged
@ -329,15 +329,26 @@ rpl::producer<bool> CanAddMemberValue(not_null<PeerData*> peer) {
}
rpl::producer<bool> VerifiedValue(not_null<PeerData*> peer) {
if (auto user = peer->asUser()) {
if (const auto user = peer->asUser()) {
return Data::PeerFlagValue(user, MTPDuser::Flag::f_verified);
} else if (auto channel = peer->asChannel()) {
} else if (const auto channel = peer->asChannel()) {
return Data::PeerFlagValue(
channel,
MTPDchannel::Flag::f_verified);
}
return rpl::single(false);
}
rpl::producer<bool> ScamValue(not_null<PeerData*> peer) {
if (const auto user = peer->asUser()) {
return Data::PeerFlagValue(user, MTPDuser::Flag::f_scam);
} else if (const auto channel = peer->asChannel()) {
return Data::PeerFlagValue(
channel,
MTPDchannel::Flag::f_scam);
}
return rpl::single(false);
}
// // #feed
//rpl::producer<int> FeedChannelsCountValue(not_null<Data::Feed*> feed) {
// using Flag = Data::FeedUpdateFlag;

View File

@ -58,6 +58,7 @@ rpl::producer<int> SharedMediaCountValue(
rpl::producer<int> CommonGroupsCountValue(not_null<UserData*> user);
rpl::producer<bool> CanAddMemberValue(not_null<PeerData*> peer);
rpl::producer<bool> VerifiedValue(not_null<PeerData*> peer);
rpl::producer<bool> ScamValue(not_null<PeerData*> peer);
//rpl::producer<int> FeedChannelsCountValue(not_null<Data::Feed*> feed); // #feed

View File

@ -7,7 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "ui/unread_badge.h"
#include "data/data_peer.h"
#include "dialogs/dialogs_layout.h"
#include "lang/lang_keys.h"
#include "styles/style_dialogs.h"
namespace Ui {
@ -45,4 +48,91 @@ void UnreadBadge::paintEvent(QPaintEvent *e) {
unreadSt);
}
QSize ScamBadgeSize() {
const auto phrase = tr::lng_scam_badge(tr::now);
const auto phraseWidth = st::dialogsScamFont->width(phrase);
const auto width = st::dialogsScamPadding.left()
+ phraseWidth
+ st::dialogsScamPadding.right();
const auto height = st::dialogsScamPadding.top()
+ st::dialogsScamFont->height
+ st::dialogsScamPadding.bottom();
return { width, height };
}
void DrawScamBadge(
Painter &p,
QRect rect,
int outerWidth,
const style::color &color,
const QString &phrase,
int phraseWidth) {
PainterHighQualityEnabler hq(p);
auto pen = color->p;
pen.setWidth(st::lineWidth);
p.setPen(pen);
p.setBrush(Qt::NoBrush);
p.drawRoundedRect(rect, st::dialogsScamRadius, st::dialogsScamRadius);
p.setFont(st::dialogsScamFont);
p.drawTextLeft(
rect.x() + st::dialogsScamPadding.left(),
rect.y() + st::dialogsScamPadding.top(),
outerWidth,
phrase,
phraseWidth);
}
void DrawScamBadge(
Painter &p,
QRect rect,
int outerWidth,
const style::color &color) {
const auto phrase = tr::lng_scam_badge(tr::now);
DrawScamBadge(
p,
rect,
outerWidth,
color,
phrase,
st::dialogsScamFont->width(phrase));
}
int DrawPeerBadgeGetWidth(
not_null<PeerData*> peer,
Painter &p,
QRect rectForName,
int nameWidth,
int outerWidth,
const PeerBadgeStyle &st) {
if (peer->isVerified() && st.verified) {
const auto iconw = st.verified->width();
st.verified->paint(
p,
rectForName.x() + qMin(nameWidth, rectForName.width() - iconw),
rectForName.y(),
outerWidth);
return iconw;
} else if (peer->isScam() && st.scam) {
const auto phrase = tr::lng_scam_badge(tr::now);
const auto phraseWidth = st::dialogsScamFont->width(phrase);
const auto width = st::dialogsScamPadding.left()
+ phraseWidth
+ st::dialogsScamPadding.right();
const auto height = st::dialogsScamPadding.top()
+ st::dialogsScamFont->height
+ st::dialogsScamPadding.bottom();
const auto rect = QRect(
(rectForName.x()
+ qMin(
nameWidth + st::dialogsScamSkip,
rectForName.width() - width)),
rectForName.y() + (rectForName.height() - height) / 2,
width,
height);
DrawScamBadge(p, rect, outerWidth, *st.scam, phrase, phraseWidth);
return st::dialogsScamSkip + width;
}
return 0;
}
} // namespace Ui

View File

@ -27,4 +27,22 @@ private:
};
struct PeerBadgeStyle {
const style::icon *verified = nullptr;
const style::color *scam = nullptr;
};
int DrawPeerBadgeGetWidth(
not_null<PeerData*> peer,
Painter &p,
QRect rectForName,
int nameWidth,
int outerWidth,
const PeerBadgeStyle &st);
QSize ScamBadgeSize();
void DrawScamBadge(
Painter &p,
QRect rect,
int outerWidth,
const style::color &color);
} // namespace Ui