| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "ui/unread_badge.h"
- #include "data/data_emoji_statuses.h"
- #include "data/data_peer.h"
- #include "data/data_user.h"
- #include "data/data_session.h"
- #include "data/stickers/data_custom_emoji.h"
- #include "main/main_session.h"
- #include "lang/lang_keys.h"
- #include "ui/painter.h"
- #include "ui/power_saving.h"
- #include "ui/unread_badge_paint.h"
- #include "styles/style_dialogs.h"
- namespace Ui {
- namespace {
- constexpr auto kPlayStatusLimit = 2;
- } // namespace
- struct PeerBadge::EmojiStatus {
- EmojiStatusId id;
- std::unique_ptr<Ui::Text::CustomEmoji> emoji;
- int skip = 0;
- };
- struct PeerBadge::BotVerifiedData {
- QImage cache;
- std::unique_ptr<Text::CustomEmoji> icon;
- };
- void UnreadBadge::setText(const QString &text, bool active) {
- _text = text;
- _active = active;
- const auto st = Dialogs::Ui::UnreadBadgeStyle();
- resize(
- std::max(st.font->width(text) + 2 * st.padding, st.size),
- st.size);
- update();
- }
- int UnreadBadge::textBaseline() const {
- const auto st = Dialogs::Ui::UnreadBadgeStyle();
- return ((st.size - st.font->height) / 2) + st.font->ascent;
- }
- void UnreadBadge::paintEvent(QPaintEvent *e) {
- if (_text.isEmpty()) {
- return;
- }
- auto p = QPainter(this);
- UnreadBadgeStyle unreadSt;
- unreadSt.muted = !_active;
- auto unreadRight = width();
- auto unreadTop = 0;
- PaintUnreadBadge(
- p,
- _text,
- unreadRight,
- unreadTop,
- unreadSt);
- }
- 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
- + st::dialogsScamPadding.right();
- const auto height = st::dialogsScamPadding.top()
- + st::dialogsScamFont->height
- + st::dialogsScamPadding.bottom();
- return { width, height };
- }
- void DrawScamFakeBadge(
- 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(
- bool fake,
- Painter &p,
- QRect rect,
- int outerWidth,
- const style::color &color) {
- const auto phrase = fake
- ? tr::lng_fake_badge(tr::now)
- : tr::lng_scam_badge(tr::now);
- DrawScamFakeBadge(
- p,
- rect,
- outerWidth,
- color,
- phrase,
- st::dialogsScamFont->width(phrase));
- }
- PeerBadge::PeerBadge() = default;
- PeerBadge::~PeerBadge() = default;
- int PeerBadge::drawGetWidth(Painter &p, Descriptor &&descriptor) {
- Expects(descriptor.customEmojiRepaint != nullptr);
- const auto peer = descriptor.peer;
- if (descriptor.scam && (peer->isScam() || peer->isFake())) {
- return drawScamOrFake(p, descriptor);
- }
- const auto verifyCheck = descriptor.verified && peer->isVerified();
- const auto premiumMark = descriptor.premium
- && peer->session().premiumBadgesShown();
- const auto emojiStatus = premiumMark
- && peer->emojiStatusId()
- && (peer->isPremium() || peer->isChannel());
- const auto premiumStar = premiumMark
- && !emojiStatus
- && peer->isPremium();
- const auto paintVerify = verifyCheck
- && (descriptor.prioritizeVerification
- || descriptor.bothVerifyAndStatus
- || !emojiStatus);
- const auto paintEmoji = emojiStatus
- && (!paintVerify || descriptor.bothVerifyAndStatus);
- const auto paintStar = premiumStar && !paintVerify;
- auto result = 0;
- if (paintEmoji) {
- auto &rectForName = descriptor.rectForName;
- const auto verifyWidth = descriptor.verified->width();
- if (paintVerify) {
- rectForName.setWidth(rectForName.width() - verifyWidth);
- }
- result += drawPremiumEmojiStatus(p, descriptor);
- if (!paintVerify) {
- return result;
- }
- rectForName.setWidth(rectForName.width() + verifyWidth);
- descriptor.nameWidth += result;
- }
- if (paintVerify) {
- result += drawVerifyCheck(p, descriptor);
- return result;
- } else if (paintStar) {
- return drawPremiumStar(p, descriptor);
- }
- return 0;
- }
- int PeerBadge::drawScamOrFake(Painter &p, const Descriptor &descriptor) {
- const auto phrase = descriptor.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
- + st::dialogsScamPadding.right();
- const auto height = st::dialogsScamPadding.top()
- + st::dialogsScamFont->height
- + st::dialogsScamPadding.bottom();
- const auto rectForName = descriptor.rectForName;
- const auto rect = QRect(
- (rectForName.x()
- + qMin(
- descriptor.nameWidth + st::dialogsScamSkip,
- rectForName.width() - width)),
- rectForName.y() + (rectForName.height() - height) / 2,
- width,
- height);
- DrawScamFakeBadge(
- p,
- rect,
- descriptor.outerWidth,
- *descriptor.scam,
- phrase,
- phraseWidth);
- return st::dialogsScamSkip + width;
- }
- int PeerBadge::drawVerifyCheck(Painter &p, const Descriptor &descriptor) {
- const auto iconw = descriptor.verified->width();
- const auto rectForName = descriptor.rectForName;
- const auto nameWidth = descriptor.nameWidth;
- descriptor.verified->paint(
- p,
- rectForName.x() + qMin(nameWidth, rectForName.width() - iconw),
- rectForName.y(),
- descriptor.outerWidth);
- return iconw;
- }
- int PeerBadge::drawPremiumEmojiStatus(
- Painter &p,
- const Descriptor &descriptor) {
- const auto peer = descriptor.peer;
- const auto id = peer->emojiStatusId();
- const auto rectForName = descriptor.rectForName;
- const auto iconw = descriptor.premium->width();
- const auto iconx = rectForName.x()
- + qMin(descriptor.nameWidth, rectForName.width() - iconw);
- const auto icony = rectForName.y();
- if (!_emojiStatus) {
- _emojiStatus = std::make_unique<EmojiStatus>();
- const auto size = st::emojiSize;
- const auto emoji = Ui::Text::AdjustCustomEmojiSize(size);
- _emojiStatus->skip = (size - emoji) / 2;
- }
- if (_emojiStatus->id != id) {
- using namespace Ui::Text;
- auto &manager = peer->session().data().customEmojiManager();
- _emojiStatus->id = id;
- _emojiStatus->emoji = std::make_unique<LimitedLoopsEmoji>(
- manager.create(
- Data::EmojiStatusCustomId(id),
- descriptor.customEmojiRepaint),
- kPlayStatusLimit);
- }
- _emojiStatus->emoji->paint(p, {
- .textColor = (*descriptor.premiumFg)->c,
- .now = descriptor.now,
- .position = QPoint(
- iconx - 2 * _emojiStatus->skip,
- icony + _emojiStatus->skip),
- .paused = descriptor.paused || On(PowerSaving::kEmojiStatus),
- });
- return iconw - 4 * _emojiStatus->skip;
- }
- int PeerBadge::drawPremiumStar(Painter &p, const Descriptor &descriptor) {
- const auto rectForName = descriptor.rectForName;
- const auto iconw = descriptor.premium->width();
- const auto iconx = rectForName.x()
- + qMin(descriptor.nameWidth, rectForName.width() - iconw);
- const auto icony = rectForName.y();
- _emojiStatus = nullptr;
- descriptor.premium->paint(p, iconx, icony, descriptor.outerWidth);
- return iconw;
- }
- void PeerBadge::unload() {
- _emojiStatus = nullptr;
- }
- bool PeerBadge::ready(const BotVerifyDetails *details) const {
- if (!details || !*details) {
- _botVerifiedData = nullptr;
- return true;
- } else if (!_botVerifiedData) {
- return false;
- }
- if (!details->iconId) {
- _botVerifiedData->icon = nullptr;
- } else if (!_botVerifiedData->icon
- || (_botVerifiedData->icon->entityData()
- != Data::SerializeCustomEmojiId(details->iconId))) {
- return false;
- }
- return true;
- }
- void PeerBadge::set(
- not_null<const BotVerifyDetails*> details,
- Ui::Text::CustomEmojiFactory factory,
- Fn<void()> repaint) {
- if (!_botVerifiedData) {
- _botVerifiedData = std::make_unique<BotVerifiedData>();
- }
- if (details->iconId) {
- _botVerifiedData->icon = std::make_unique<Ui::Text::FirstFrameEmoji>(
- factory(
- Data::SerializeCustomEmojiId(details->iconId),
- { .repaint = repaint }));
- }
- }
- int PeerBadge::drawVerified(
- QPainter &p,
- QPoint position,
- const style::VerifiedBadge &st) {
- const auto data = _botVerifiedData.get();
- if (!data) {
- return 0;
- }
- if (const auto icon = data->icon.get()) {
- icon->paint(p, {
- .textColor = st.color->c,
- .now = crl::now(),
- .position = position,
- });
- return icon->width();
- }
- return 0;
- }
- } // namespace Ui
|