diff --git a/Telegram/Resources/colors.palette b/Telegram/Resources/colors.palette index 1467b92fe5..0c241710b4 100644 --- a/Telegram/Resources/colors.palette +++ b/Telegram/Resources/colors.palette @@ -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 diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 6167779132..1bca841383 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -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 :("; diff --git a/Telegram/SourceFiles/boxes/add_contact_box.cpp b/Telegram/SourceFiles/boxes/add_contact_box.cpp index 71cc5b2040..82dcb3ad63 100644 --- a/Telegram/SourceFiles/boxes/add_contact_box.cpp +++ b/Telegram/SourceFiles/boxes/add_contact_box.cpp @@ -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); diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h index 127d27cd8b..f225a0fe57 100644 --- a/Telegram/SourceFiles/data/data_channel.h +++ b/Telegram/SourceFiles/data/data_channel.h @@ -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); diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 3772074cc7..20a9b7ee51 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -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( diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index 8473fe3c69..fa609225a7 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -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 { diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index 12be6cd890..5a6df93d1f 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -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; } diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index f33e81e502..88d4e2fc0a 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -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; + diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 30031cacb6..ac4b27f3b8 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -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); diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index 07eeaef90b..f184e2bac1 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -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()); diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index 0cbcd50a25..e4bf90dde0 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -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()); } } } diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp index 1be1a6bda5..cdbda619b8 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp @@ -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 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); } } diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.h b/Telegram/SourceFiles/info/profile/info_profile_cover.h index 6089cf1f33..35018c6efd 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.h +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.h @@ -86,6 +86,7 @@ private: void refreshStatusGeometry(int newWidth); void refreshUploadPhotoOverlay(); void setVerified(bool verified); + void setScam(bool scam); not_null _peer; int _onlineCount = 0; @@ -93,6 +94,7 @@ private: object_ptr _userpic; object_ptr _name = { nullptr }; object_ptr _verifiedCheck = { nullptr }; + object_ptr _scamBadge = { nullptr }; object_ptr _status = { nullptr }; //object_ptr _dropArea = { nullptr }; base::Timer _refreshStatusTimer; diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.cpp b/Telegram/SourceFiles/info/profile/info_profile_values.cpp index 6d182cdd5d..8172e05919 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_values.cpp @@ -310,14 +310,14 @@ rpl::producer CommonGroupsCountValue(not_null user) { } rpl::producer CanAddMemberValue(not_null 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 CanAddMemberValue(not_null peer) { } rpl::producer VerifiedValue(not_null 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 ScamValue(not_null 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 FeedChannelsCountValue(not_null feed) { // using Flag = Data::FeedUpdateFlag; diff --git a/Telegram/SourceFiles/info/profile/info_profile_values.h b/Telegram/SourceFiles/info/profile/info_profile_values.h index cb1b62c528..59a9bab73e 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.h +++ b/Telegram/SourceFiles/info/profile/info_profile_values.h @@ -58,6 +58,7 @@ rpl::producer SharedMediaCountValue( rpl::producer CommonGroupsCountValue(not_null user); rpl::producer CanAddMemberValue(not_null peer); rpl::producer VerifiedValue(not_null peer); +rpl::producer ScamValue(not_null peer); //rpl::producer FeedChannelsCountValue(not_null feed); // #feed diff --git a/Telegram/SourceFiles/ui/unread_badge.cpp b/Telegram/SourceFiles/ui/unread_badge.cpp index b9d53909b3..23762262a8 100644 --- a/Telegram/SourceFiles/ui/unread_badge.cpp +++ b/Telegram/SourceFiles/ui/unread_badge.cpp @@ -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 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 diff --git a/Telegram/SourceFiles/ui/unread_badge.h b/Telegram/SourceFiles/ui/unread_badge.h index f204a50155..426c53dec1 100644 --- a/Telegram/SourceFiles/ui/unread_badge.h +++ b/Telegram/SourceFiles/ui/unread_badge.h @@ -27,4 +27,22 @@ private: }; +struct PeerBadgeStyle { + const style::icon *verified = nullptr; + const style::color *scam = nullptr; +}; +int DrawPeerBadgeGetWidth( + not_null 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