/* 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 "info/profile/info_profile_badge.h" #include "data/data_peer.h" #include "data/data_session.h" #include "data/data_user.h" #include "data/stickers/data_custom_emoji.h" #include "info/profile/info_profile_values.h" #include "info/profile/info_profile_emoji_status_panel.h" #include "lang/lang_keys.h" #include "ui/widgets/buttons.h" #include "ui/painter.h" #include "ui/power_saving.h" #include "main/main_session.h" #include "styles/style_info.h" namespace Info::Profile { namespace { [[nodiscard]] rpl::producer ContentForPeer( not_null peer) { const auto statusOnlyForPremium = peer->isUser(); return rpl::combine( BadgeValue(peer), EmojiStatusIdValue(peer) ) | rpl::map([=](BadgeType badge, DocumentId emojiStatusId) { if (statusOnlyForPremium && badge != BadgeType::Premium) { emojiStatusId = 0; } else if (emojiStatusId && badge == BadgeType::None) { badge = BadgeType::Premium; } return Badge::Content{ badge, emojiStatusId }; }); } } // namespace Badge::Badge( not_null parent, const style::InfoPeerBadge &st, not_null peer, EmojiStatusPanel *emojiStatusPanel, Fn animationPaused, int customStatusLoopsLimit, base::flags allowed) : Badge( parent, st, &peer->session(), ContentForPeer(peer), emojiStatusPanel, std::move(animationPaused), customStatusLoopsLimit, allowed) { } Badge::Badge( not_null parent, const style::InfoPeerBadge &st, not_null session, rpl::producer content, EmojiStatusPanel *emojiStatusPanel, Fn animationPaused, int customStatusLoopsLimit, base::flags allowed) : _parent(parent) , _st(st) , _session(session) , _emojiStatusPanel(emojiStatusPanel) , _customStatusLoopsLimit(customStatusLoopsLimit) , _allowed(allowed) , _animationPaused(std::move(animationPaused)) { std::move( content ) | rpl::start_with_next([=](Content content) { setContent(content); }, _lifetime); } Badge::~Badge() = default; Ui::RpWidget *Badge::widget() const { return _view.data(); } void Badge::setContent(Content content) { if (!(_allowed & content.badge) || (!_session->premiumBadgesShown() && content.badge == BadgeType::Premium)) { content.badge = BadgeType::None; } if (!(_allowed & content.badge)) { content.badge = BadgeType::None; } if (_content == content) { return; } _content = content; _emojiStatus = nullptr; _view.destroy(); if (_content.badge == BadgeType::None) { _updated.fire({}); return; } _view.create(_parent); _view->show(); switch (_content.badge) { case BadgeType::Verified: case BadgeType::Premium: { if (const auto id = _content.emojiStatusId) { _emojiStatus = _session->data().customEmojiManager().create( id, [raw = _view.data()] { raw->update(); }, sizeTag()); if (_customStatusLoopsLimit > 0) { _emojiStatus = std::make_unique( std::move(_emojiStatus), _customStatusLoopsLimit); } const auto emoji = Data::FrameSizeFromTag(sizeTag()) / style::DevicePixelRatio(); _view->resize(emoji, emoji); _view->paintRequest( ) | rpl::start_with_next([=, check = _view.data()]{ auto args = Ui::Text::CustomEmoji::Context{ .textColor = _st.premiumFg->c, .now = crl::now(), .paused = ((_animationPaused && _animationPaused()) || On(PowerSaving::kEmojiStatus)), }; if (!_emojiStatusPanel || !_emojiStatusPanel->paintBadgeFrame(check)) { Painter p(check); _emojiStatus->paint(p, args); } }, _view->lifetime()); } else { const auto icon = (_content.badge == BadgeType::Verified) ? &_st.verified : &_st.premium; _view->resize(icon->size()); _view->paintRequest( ) | rpl::start_with_next([=, check = _view.data()]{ Painter p(check); icon->paint(p, 0, 0, check->width()); }, _view->lifetime()); } } break; case BadgeType::Scam: case BadgeType::Fake: { const auto fake = (_content.badge == BadgeType::Fake); const auto size = Ui::ScamBadgeSize(fake); const auto skip = st::infoVerifiedCheckPosition.x(); _view->resize( size.width() + 2 * skip, size.height() + 2 * skip); _view->paintRequest( ) | rpl::start_with_next([=, badge = _view.data()]{ Painter p(badge); Ui::DrawScamBadge( fake, p, badge->rect().marginsRemoved({ skip, skip, skip, skip }), badge->width(), st::attentionButtonFg); }, _view->lifetime()); } break; } if (_content.badge != BadgeType::Premium || !_premiumClickCallback) { _view->setAttribute(Qt::WA_TransparentForMouseEvents); } else { _view->setClickedCallback(_premiumClickCallback); } _updated.fire({}); } void Badge::setPremiumClickCallback(Fn callback) { _premiumClickCallback = std::move(callback); if (_view && _content.badge == BadgeType::Premium) { if (!_premiumClickCallback) { _view->setAttribute(Qt::WA_TransparentForMouseEvents); } else { _view->setAttribute(Qt::WA_TransparentForMouseEvents, false); _view->setClickedCallback(_premiumClickCallback); } } } rpl::producer<> Badge::updated() const { return _updated.events(); } void Badge::move(int left, int top, int bottom) { if (!_view) { return; } const auto star = !_emojiStatus && (_content.badge == BadgeType::Premium || _content.badge == BadgeType::Verified); const auto fake = !_emojiStatus && !star; const auto skip = fake ? 0 : _st.position.x(); const auto badgeLeft = left + skip; const auto badgeTop = top + (star ? _st.position.y() : (bottom - top - _view->height()) / 2); _view->moveToLeft(badgeLeft, badgeTop); } Data::CustomEmojiSizeTag Badge::sizeTag() const { using SizeTag = Data::CustomEmojiSizeTag; return (_st.sizeTag == 2) ? SizeTag::Isolated : (_st.sizeTag == 1) ? SizeTag::Large : SizeTag::Normal; } } // namespace Info::Profile