diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index b99e97913d..ba3f25c76a 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -126,6 +126,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_channel_status" = "channel"; "lng_group_status" = "group"; "lng_scam_badge" = "SCAM"; +"lng_fake_badge" = "FAKE"; "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/Resources/tl/api.tl b/Telegram/Resources/tl/api.tl index 4135cc33d4..75208c727c 100644 --- a/Telegram/Resources/tl/api.tl +++ b/Telegram/Resources/tl/api.tl @@ -109,7 +109,7 @@ storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; userEmpty#200250ba id:int = User; -user#938458c1 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; +user#938458c1 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#69d3ab26 flags:# has_video:flags.0?true photo_id:long photo_small:FileLocation photo_big:FileLocation dc_id:int = UserProfilePhoto; @@ -124,7 +124,7 @@ userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; chatForbidden#7328bdb id:int title:string = Chat; -channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; +channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int = Chat; channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#f3474af6 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall = ChatFull; @@ -1217,6 +1217,8 @@ messages.chatInviteImporters#81b6b00a count:int importers:VectorisFake(); + } else if (const auto channel = asChannel()) { + return channel->isFake(); + } + return false; +} + bool PeerData::isMegagroup() const { return isChannel() ? asChannel()->isMegagroup() : false; } diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index cb38944d49..72b4593eea 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -158,6 +158,7 @@ public: } [[nodiscard]] bool isVerified() const; [[nodiscard]] bool isScam() const; + [[nodiscard]] bool isFake() const; [[nodiscard]] bool isMegagroup() const; [[nodiscard]] bool isBroadcast() const; [[nodiscard]] bool isRepliesChat() const; diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index 39665a9686..a925afcac5 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -50,6 +50,7 @@ public: | MTPDuser::Flag::f_bot_nochats | MTPDuser::Flag::f_verified | MTPDuser::Flag::f_scam + | MTPDuser::Flag::f_fake | MTPDuser::Flag::f_restricted | MTPDuser::Flag::f_bot_inline_geo; using Flags = Data::Flags< @@ -111,48 +112,51 @@ public: void removeFullFlags(MTPDuserFull::Flags which) { _fullFlags.remove(which); } - auto fullFlags() const { + [[nodiscard]] auto fullFlags() const { return _fullFlags.current(); } - auto fullFlagsValue() const { + [[nodiscard]] auto fullFlagsValue() const { return _fullFlags.value(); } - bool isVerified() const { + [[nodiscard]] bool isVerified() const { return flags() & MTPDuser::Flag::f_verified; } - bool isScam() const { + [[nodiscard]] bool isScam() const { return flags() & MTPDuser::Flag::f_scam; } - bool isBotInlineGeo() const { + [[nodiscard]] bool isFake() const { + return flags() & MTPDuser::Flag::f_fake; + } + [[nodiscard]] bool isBotInlineGeo() const { return flags() & MTPDuser::Flag::f_bot_inline_geo; } - bool isBot() const { + [[nodiscard]] bool isBot() const { return botInfo != nullptr; } - bool isSupport() const { + [[nodiscard]] bool isSupport() const { return flags() & MTPDuser::Flag::f_support; } - bool isInaccessible() const { + [[nodiscard]] bool isInaccessible() const { constexpr auto inaccessible = 0 | MTPDuser::Flag::f_deleted; // | MTPDuser_ClientFlag::f_inaccessible; return flags() & inaccessible; } - bool canWrite() const { + [[nodiscard]] bool canWrite() const { // Duplicated in Data::CanWriteValue(). return !isInaccessible() && !isRepliesChat(); } - bool canShareThisContact() const; - bool canAddContact() const { + [[nodiscard]] bool canShareThisContact() const; + [[nodiscard]] bool canAddContact() const { return canShareThisContact() && !isContact(); } // In Data::Session::processUsers() we check only that. // When actually trying to share contact we perform // a full check by canShareThisContact() call. - bool canShareThisContactFast() const { + [[nodiscard]] bool canShareThisContactFast() const { return !_phone.isEmpty(); } @@ -161,7 +165,7 @@ public: QString firstName; QString lastName; QString username; - const QString &phone() const { + [[nodiscard]] const QString &phone() const { return _phone; } QString nameOrPhone; diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index 5b45e735f3..7aee359225 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -452,11 +452,6 @@ void paintRow( } p.setFont(st::msgNameFont); - p.setPen(active - ? st::dialogsNameFgActive - : selected - ? st::dialogsNameFgOver - : st::dialogsNameFg); if (flags & (Flag::SavedMessages | Flag::RepliesMessages)) { auto text = (flags & Flag::SavedMessages) ? tr::lng_saved_messages(tr::now) @@ -465,6 +460,11 @@ void paintRow( if (textWidth > rectForName.width()) { text = st::msgNameFont->elided(text, rectForName.width()); } + 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)) { @@ -488,15 +488,25 @@ void paintRow( 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) { + p.setPen(active + ? st::dialogsNameFgActive + : selected + ? st::dialogsNameFgOver + : st::dialogsNameFg); hiddenSenderInfo->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); } else { - if (!active) { - p.setPen(selected - ? st::dialogsArchiveFgOver - : st::dialogsArchiveFg); - } + p.setPen(active + ? st::dialogsNameFgActive + : selected + ? st::dialogsArchiveFgOver + : st::dialogsArchiveFg); auto text = entry->chatListName(); // TODO feed name with emoji auto textWidth = st::msgNameFont->width(text); if (textWidth > rectForName.width()) { diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp index ad7e4cd0a5..6fb26e7b3e 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp @@ -322,15 +322,10 @@ void Cover::initViewers(rpl::producer title) { } else if (_peer->isSelf()) { refreshUploadPhotoOverlay(); } - VerifiedValue( + BadgeValue( _peer - ) | rpl::start_with_next([=](bool verified) { - setVerified(verified); - }, lifetime()); - ScamValue( - _peer - ) | rpl::start_with_next([=](bool scam) { - setScam(scam); + ) | rpl::start_with_next([=](Badge badge) { + setBadge(badge); }, lifetime()); } @@ -345,50 +340,45 @@ void Cover::refreshUploadPhotoOverlay() { }()); } -void Cover::setVerified(bool verified) { - if ((_verifiedCheck != nullptr) == verified) { +void Cover::setBadge(Badge badge) { + if (_badge == badge) { return; } - if (verified) { - _scamBadge.destroy(); + _badge = badge; + _verifiedCheck.destroy(); + _scamFakeBadge.destroy(); + switch (_badge) { + case Badge::Verified: _verifiedCheck.create(this); _verifiedCheck->show(); _verifiedCheck->resize(st::infoVerifiedCheck.size()); _verifiedCheck->paintRequest( - ) | rpl::start_with_next([check = _verifiedCheck.data()] { + ) | rpl::start_with_next([check = _verifiedCheck.data()]{ Painter p(check); st::infoVerifiedCheck.paint(p, 0, 0, check->width()); - }, _verifiedCheck->lifetime()); - } else { - _verifiedCheck.destroy(); - } - refreshNameGeometry(width()); -} - -void Cover::setScam(bool scam) { - if ((_scamBadge != nullptr) == scam) { - return; - } - if (scam) { - _verifiedCheck.destroy(); - const auto size = Ui::ScamBadgeSize(); + }, _verifiedCheck->lifetime()); + break; + case Badge::Scam: + case Badge::Fake: { + const auto fake = (_badge == Badge::Fake); + const auto size = Ui::ScamBadgeSize(fake); const auto skip = st::infoVerifiedCheckPosition.x(); - _scamBadge.create(this); - _scamBadge->show(); - _scamBadge->resize( + _scamFakeBadge.create(this); + _scamFakeBadge->show(); + _scamFakeBadge->resize( size.width() + 2 * skip, size.height() + 2 * skip); - _scamBadge->paintRequest( - ) | rpl::start_with_next([=, badge = _scamBadge.data()] { + _scamFakeBadge->paintRequest( + ) | rpl::start_with_next([=, badge = _scamFakeBadge.data()]{ Painter p(badge); Ui::DrawScamBadge( + fake, p, badge->rect().marginsRemoved({ skip, skip, skip, skip }), badge->width(), st::attentionButtonFg); - }, _scamBadge->lifetime()); - } else { - _scamBadge.destroy(); + }, _scamFakeBadge->lifetime()); + } break; } refreshNameGeometry(width()); } @@ -452,9 +442,9 @@ void Cover::refreshNameGeometry(int newWidth) { if (_verifiedCheck) { nameWidth -= st::infoVerifiedCheckPosition.x() + _verifiedCheck->width(); - } else if (_scamBadge) { + } else if (_scamFakeBadge) { nameWidth -= st::infoVerifiedCheckPosition.x() - + _scamBadge->width(); + + _scamFakeBadge->width(); } _name->resizeToNaturalWidth(nameWidth); _name->moveToLeft(nameLeft, nameTop, newWidth); @@ -465,15 +455,15 @@ void Cover::refreshNameGeometry(int newWidth) { const auto checkTop = nameTop + st::infoVerifiedCheckPosition.y(); _verifiedCheck->moveToLeft(checkLeft, checkTop, newWidth); - } else if (_scamBadge) { + } else if (_scamFakeBadge) { 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); + + (_name->height() - _scamFakeBadge->height()) / 2; + _scamFakeBadge->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 35018c6efd..6e0b8a845d 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.h +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.h @@ -34,6 +34,8 @@ class Section; namespace Info { namespace Profile { +enum class Badge; + class SectionWithToggle : public Ui::FixedHeightWidget { public: using FixedHeightWidget::FixedHeightWidget; @@ -85,16 +87,16 @@ private: void refreshNameGeometry(int newWidth); void refreshStatusGeometry(int newWidth); void refreshUploadPhotoOverlay(); - void setVerified(bool verified); - void setScam(bool scam); + void setBadge(Badge badge); not_null _peer; int _onlineCount = 0; + Badge _badge = Badge(); object_ptr _userpic; object_ptr _name = { nullptr }; object_ptr _verifiedCheck = { nullptr }; - object_ptr _scamBadge = { nullptr }; + object_ptr _scamFakeBadge = { 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 dc31b11d9f..cf3fb4b514 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_values.cpp @@ -376,27 +376,31 @@ rpl::producer CanAddMemberValue(not_null peer) { return rpl::single(false); } -rpl::producer VerifiedValue(not_null peer) { - if (const auto user = peer->asUser()) { - return Data::PeerFlagValue(user, MTPDuser::Flag::f_verified); - } else if (const auto channel = peer->asChannel()) { - return Data::PeerFlagValue( - channel, - MTPDchannel::Flag::f_verified); - } - return rpl::single(false); +template +rpl::producer BadgeValueFromFlags(Peer peer) { + return Data::PeerFlagsValue( + peer, + Flag::f_verified | Flag::f_scam | Flag::f_fake + ) | rpl::map([=](base::flags value) { + return (value & Flag::f_verified) + ? Badge::Verified + : (value & Flag::f_scam) + ? Badge::Scam + : (value & Flag::f_fake) + ? Badge::Fake + : Badge::None; + }); } -rpl::producer ScamValue(not_null peer) { +rpl::producer BadgeValue(not_null peer) { if (const auto user = peer->asUser()) { - return Data::PeerFlagValue(user, MTPDuser::Flag::f_scam); + return BadgeValueFromFlags(user); } else if (const auto channel = peer->asChannel()) { - return Data::PeerFlagValue( - channel, - MTPDchannel::Flag::f_scam); + return BadgeValueFromFlags(channel); } - return rpl::single(false); + return rpl::single(Badge::None); } + // // #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 da87867f6f..d60111088a 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_values.h +++ b/Telegram/SourceFiles/info/profile/info_profile_values.h @@ -59,8 +59,14 @@ rpl::producer SharedMediaCountValue( Storage::SharedMediaType type); rpl::producer CommonGroupsCountValue(not_null user); rpl::producer CanAddMemberValue(not_null peer); -rpl::producer VerifiedValue(not_null peer); -rpl::producer ScamValue(not_null peer); + +enum class Badge { + None, + Verified, + Scam, + Fake, +}; +rpl::producer BadgeValue(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 23762262a8..732c14247f 100644 --- a/Telegram/SourceFiles/ui/unread_badge.cpp +++ b/Telegram/SourceFiles/ui/unread_badge.cpp @@ -48,8 +48,10 @@ void UnreadBadge::paintEvent(QPaintEvent *e) { unreadSt); } -QSize ScamBadgeSize() { - const auto phrase = tr::lng_scam_badge(tr::now); +QSize ScamBadgeSize(bool fake) { + const auto phrase = fake + ? tr::lng_fake_badge(tr::now) + : tr::lng_scam_badge(tr::now); const auto phraseWidth = st::dialogsScamFont->width(phrase); const auto width = st::dialogsScamPadding.left() + phraseWidth @@ -60,7 +62,7 @@ QSize ScamBadgeSize() { return { width, height }; } -void DrawScamBadge( +void DrawScamFakeBadge( Painter &p, QRect rect, int outerWidth, @@ -83,12 +85,15 @@ void DrawScamBadge( } void DrawScamBadge( + bool fake, Painter &p, QRect rect, int outerWidth, const style::color &color) { - const auto phrase = tr::lng_scam_badge(tr::now); - DrawScamBadge( + const auto phrase = fake + ? tr::lng_fake_badge(tr::now) + : tr::lng_scam_badge(tr::now); + DrawScamFakeBadge( p, rect, outerWidth, @@ -112,8 +117,10 @@ int DrawPeerBadgeGetWidth( rectForName.y(), outerWidth); return iconw; - } else if (peer->isScam() && st.scam) { - const auto phrase = tr::lng_scam_badge(tr::now); + } else if ((peer->isScam() || peer->isFake()) && st.scam) { + const auto phrase = peer->isScam() + ? tr::lng_scam_badge(tr::now) + : tr::lng_fake_badge(tr::now); const auto phraseWidth = st::dialogsScamFont->width(phrase); const auto width = st::dialogsScamPadding.left() + phraseWidth @@ -129,7 +136,7 @@ int DrawPeerBadgeGetWidth( rectForName.y() + (rectForName.height() - height) / 2, width, height); - DrawScamBadge(p, rect, outerWidth, *st.scam, phrase, phraseWidth); + DrawScamFakeBadge(p, rect, outerWidth, *st.scam, phrase, phraseWidth); return st::dialogsScamSkip + width; } return 0; diff --git a/Telegram/SourceFiles/ui/unread_badge.h b/Telegram/SourceFiles/ui/unread_badge.h index 426c53dec1..7cd1a790c6 100644 --- a/Telegram/SourceFiles/ui/unread_badge.h +++ b/Telegram/SourceFiles/ui/unread_badge.h @@ -38,8 +38,9 @@ int DrawPeerBadgeGetWidth( int nameWidth, int outerWidth, const PeerBadgeStyle &st); -QSize ScamBadgeSize(); +QSize ScamBadgeSize(bool fake); void DrawScamBadge( + bool fake, Painter &p, QRect rect, int outerWidth,