diff --git a/Telegram/SourceFiles/boxes/star_gift_box.cpp b/Telegram/SourceFiles/boxes/star_gift_box.cpp index c5a5a2051..74cbfd4db 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_box.cpp @@ -1528,7 +1528,7 @@ void SendGiftBox( bool sending = false; }; const auto state = raw->lifetime().make_state(State{ - .delegate = Delegate(window), + .delegate = Delegate(window, GiftButtonMode::Full), }); const auto single = state->delegate.buttonSize(); const auto shadow = st::defaultDropdownMenu.wrap.shadow; @@ -1575,7 +1575,7 @@ void SendGiftBox( for (auto i = 0; i != count; ++i) { const auto button = state->buttons[i].get(); const auto &descriptor = gifts.list[order[i]]; - button->setDescriptor(descriptor); + button->setDescriptor(descriptor, GiftButton::Mode::Full); const auto last = !((i + 1) % perRow); if (last) { diff --git a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp index 0d1f7b7b2..ac1584329 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.cpp @@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "settings/settings_credits_graphics.h" #include "settings/settings_credits_graphics.h" // GiftedCreditsBox #include "settings/settings_premium.h" // Settings::ShowGiftPremium +#include "ui/chat/chat_style.h" #include "ui/layers/generic_box.h" #include "ui/text/text_utilities.h" #include "window/window_session_controller.h" @@ -300,20 +301,35 @@ void PremiumGift::draw( } } -QString PremiumGift::cornerTagText() { +QImage PremiumGift::cornerTag(const PaintContext &context) { + auto badge = Info::PeerGifts::GiftBadge(); if (_data.unique) { - return tr::lng_gift_collectible_tag(tr::now); + badge = { + .text = tr::lng_gift_collectible_tag(tr::now), + .bg = _data.unique->backdrop.patternColor, + .fg = QColor(255, 255, 255), + }; } else if (const auto count = _data.limitedCount) { - return (count == 1) - ? tr::lng_gift_limited_of_one(tr::now) - : tr::lng_gift_limited_of_count( - tr::now, - lt_amount, - ((count % 1000) - ? Lang::FormatCountDecimal(count) - : Lang::FormatCountToShort(count).string)); + badge = { + .text = ((count == 1) + ? tr::lng_gift_limited_of_one(tr::now) + : tr::lng_gift_limited_of_count( + tr::now, + lt_amount, + (((count % 1000) && (count < 10'000)) + ? Lang::FormatCountDecimal(count) + : Lang::FormatCountToShort(count).string))), + .bg = context.st->msgServiceBg()->c, + .fg = context.st->msgServiceFg()->c, + }; + } else { + return {}; } - return QString(); + if (_badgeCache.isNull() || _badgeKey != badge) { + _badgeKey = badge; + _badgeCache = ValidateRotatedBadge(badge, 0); + } + return _badgeCache; } bool PremiumGift::hideServiceText() { diff --git a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h index 59943bd63..b782ea155 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h +++ b/Telegram/SourceFiles/history/view/media/history_view_premium_gift.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/media/history_view_sticker.h" #include "history/view/media/history_view_service_box.h" +#include "info/peer_gifts/info_peer_gifts_common.h" namespace Data { class MediaGiftBox; @@ -30,7 +31,7 @@ public: TextWithEntities subtitle() override; rpl::producer button() override; bool buttonMinistars() override; - QString cornerTagText() override; + QImage cornerTag(const PaintContext &context) override; int buttonSkip() override; void draw( Painter &p, @@ -60,6 +61,8 @@ private: const not_null _parent; const not_null _gift; const Data::GiftCode &_data; + QImage _badgeCache; + Info::PeerGifts::GiftBadge _badgeKey; mutable std::optional _sticker; }; diff --git a/Telegram/SourceFiles/history/view/media/history_view_service_box.cpp b/Telegram/SourceFiles/history/view/media/history_view_service_box.cpp index 7bf00b44a..fc81e9fec 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_service_box.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_service_box.cpp @@ -199,28 +199,9 @@ void ServiceBox::draw(Painter &p, const PaintContext &context) const { _content->draw(p, context, content); - if (const auto tag = _content->cornerTagText(); !tag.isEmpty()) { - const auto font = st::semiboldFont; - p.setFont(font); - p.setPen(Qt::NoPen); - const auto twidth = font->width(tag); - const auto pos = QPoint(_innerSize.width() - twidth, font->height); - const auto add = 0;// style::ConvertScale(2); - p.save(); - p.setClipRect( - -add, - -add, - _innerSize.width() + 2 * add, - _innerSize.height() + 2 * add); - p.translate(pos); - p.rotate(45.); - p.translate(-pos); - p.setPen(Qt::NoPen); - p.setBrush(context.st->msgServiceBg()); // ? - p.drawRect(-5 * twidth, 0, twidth * 12, font->height); - p.setPen(context.st->msgServiceFg()); - p.drawText(pos - QPoint(0, font->descent), tag); - p.restore(); + if (const auto tag = _content->cornerTag(context); !tag.isNull()) { + const auto width = tag.width() / tag.devicePixelRatio(); + p.drawImage(_innerSize.width() - width, 0, tag); } p.translate(0, -st::msgServiceGiftBoxTopSkip); diff --git a/Telegram/SourceFiles/history/view/media/history_view_service_box.h b/Telegram/SourceFiles/history/view/media/history_view_service_box.h index 733176c7d..822251186 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_service_box.h +++ b/Telegram/SourceFiles/history/view/media/history_view_service_box.h @@ -11,11 +11,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Ui { class RippleAnimation; -namespace Premium { -class ColoredMiniStars; -} // namespace Premium } // namespace Ui +namespace Ui::Premium { +class ColoredMiniStars; +} // namespace Ui::Premium + namespace HistoryView { class ServiceBoxContent { @@ -34,7 +35,7 @@ public: [[nodiscard]] virtual bool buttonMinistars() { return false; } - [[nodiscard]] virtual QString cornerTagText() { + [[nodiscard]] virtual QImage cornerTag(const PaintContext &context) { return {}; } virtual void draw( diff --git a/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp b/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp index d093f65ed..dc79e6cbe 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_unique_gift.cpp @@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_element.h" #include "history/history.h" #include "history/history_item.h" +#include "info/peer_gifts/info_peer_gifts_common.h" #include "lang/lang_keys.h" #include "main/main_session.h" #include "settings/settings_credits_graphics.h" @@ -490,6 +491,8 @@ Fn UniqueGiftBg( QImage bg; base::flat_map cache; std::unique_ptr pattern; + QImage badgeCache; + Info::PeerGifts::GiftBadge badgeKey; }; const auto state = std::make_shared(); state->pattern = view->history()->owner().customEmojiManager().create( @@ -531,29 +534,28 @@ Fn UniqueGiftBg( Ui::PaintPoints(p, state->cache, state->pattern.get(), *gift, outer); p.setClipping(false); - p.save(); - p.translate(inner.topLeft()); - const auto tag = tr::lng_gift_collectible_tag(tr::now); - const auto font = st::semiboldFont; - p.setFont(font); - p.setPen(Qt::NoPen); - const auto twidth = font->width(tag); - const auto pos = QPoint(inner.width() - twidth, font->height); const auto add = style::ConvertScale(2); p.setClipRect( - -add, - -add, + inner.x() - add, + inner.y() - add, inner.width() + 2 * add, inner.height() + 2 * add); - p.translate(pos); - p.rotate(45.); - p.translate(-pos); - p.setPen(Qt::NoPen); - p.setBrush(gift->backdrop.patternColor); - p.drawRect(-5 * twidth, 0, twidth * 12, font->height); - p.setPen(gift->backdrop.textColor); - p.drawText(pos - QPoint(0, font->descent), tag); - p.restore(); + auto badge = Info::PeerGifts::GiftBadge{ + .text = tr::lng_gift_collectible_tag(tr::now), + .bg = gift->backdrop.patternColor, + .fg = gift->backdrop.textColor, + }; + if (state->badgeCache.isNull() || state->badgeKey != badge) { + state->badgeKey = badge; + state->badgeCache = ValidateRotatedBadge(badge, add); + } + const auto badgeRatio = state->badgeCache.devicePixelRatio(); + const auto badgeWidth = state->badgeCache.width() / badgeRatio; + p.drawImage( + inner.x() + inner.width() + add - badgeWidth, + inner.y() - add, + state->badgeCache); + p.setClipping(false); }; } diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp index 4174948d5..eded88409 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp @@ -37,12 +37,23 @@ constexpr auto kGiftsPerRow = 3; } // namespace +std::strong_ordering operator<=>(const GiftBadge &a, const GiftBadge &b) { + const auto result1 = (a.text <=> b.text); + if (result1 != std::strong_ordering::equal) { + return result1; + } + const auto result2 = (a.bg.rgb() <=> b.bg.rgb()); + if (result2 != std::strong_ordering::equal) { + return result2; + } + return a.fg.rgb() <=> b.fg.rgb(); +} + GiftButton::GiftButton( QWidget *parent, not_null delegate) : AbstractButton(parent) -, _delegate(delegate) -, _stars(this, true, Ui::Premium::MiniStars::Type::SlowStars) { +, _delegate(delegate) { } GiftButton::~GiftButton() { @@ -55,11 +66,12 @@ void GiftButton::unsubscribe() { } } -void GiftButton::setDescriptor(const GiftDescriptor &descriptor) { +void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) { if (_descriptor == descriptor) { return; } auto player = base::take(_player); + const auto starsType = Ui::Premium::MiniStars::Type::SlowStars; _mediaLifetime.destroy(); _descriptor = descriptor; unsubscribe(); @@ -82,7 +94,10 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) { data.currency, true)); _userpic = nullptr; - _stars.setColorOverride(QGradientStops{ + if (!_stars) { + _stars.emplace(this, true, starsType); + } + _stars->setColorOverride(QGradientStops{ { 0., anim::with_alpha(st::windowActiveTextFg->c, .3) }, { 1., st::windowActiveTextFg->c }, }); @@ -91,6 +106,16 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) { const auto soldOut = data.info.limitedCount && !data.userpic && !data.info.limitedLeft; + _userpic = !data.userpic + ? nullptr + : data.from + ? Ui::MakeUserpicThumbnail(data.from) + : Ui::MakeHiddenAuthorThumbnail(); + if (mode == Mode::Minimal) { + _price = {}; + _stars.reset(); + return; + } _price.setMarkedText( st::semiboldTextStyle, (unique @@ -99,24 +124,20 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) { ' ' + QString::number(data.info.stars))), kMarkupTextOptions, _delegate->textContext()); - _userpic = !data.userpic - ? nullptr - : data.from - ? Ui::MakeUserpicThumbnail(data.from) - : Ui::MakeHiddenAuthorThumbnail(); + if (!_stars) { + _stars.emplace(this, true, starsType); + } if (unique) { const auto white = QColor(255, 255, 255); - _stars.setColorOverride(QGradientStops{ + _stars->setColorOverride(QGradientStops{ { 0., anim::with_alpha(white, .3) }, { 1., white }, }); } else if (soldOut) { - _stars.setColorOverride(QGradientStops{ - { 0., Qt::transparent }, - { 1., Qt::transparent }, - }); + _stars.reset(); } else { - _stars.setColorOverride(Ui::Premium::CreditsIconGradientStops()); + _stars->setColorOverride( + Ui::Premium::CreditsIconGradientStops()); } }); _delegate->sticker( @@ -125,6 +146,10 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) { setDocument(document); }, lifetime()); + if (mode != Mode::Full) { + _button = QRect(); + return; + } const auto buttonw = _price.maxWidth(); const auto buttonh = st::semiboldFont->height; const auto inner = QRect( @@ -137,9 +162,9 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) { const auto skipx = (width() - inner.width()) / 2; const auto outer = (width() - 2 * skipx); _button = QRect(skipx, skipy, outer, inner.height()); - { + if (_stars) { const auto padding = _button.height() / 2; - _stars.setCenter(_button - QMargins(padding, 0, padding, 0)); + _stars->setCenter(_button - QMargins(padding, 0, padding, 0)); } } @@ -193,8 +218,10 @@ void GiftButton::setGeometry(QRect inner, QMargins extend) { void GiftButton::resizeEvent(QResizeEvent *e) { if (!_button.isEmpty()) { _button.moveLeft((width() - _button.width()) / 2); - const auto padding = _button.height() / 2; - _stars.setCenter(_button - QMargins(padding, 0, padding, 0)); + if (_stars) { + const auto padding = _button.height() / 2; + _stars->setCenter(_button - QMargins(padding, 0, padding, 0)); + } } } @@ -338,76 +365,85 @@ void GiftButton::paintEvent(QPaintEvent *e) { const auto singlew = width - _extend.left() - _extend.right(); const auto font = st::semiboldFont; p.setFont(font); - const auto text = v::match(_descriptor, [&](GiftTypePremium data) { + + const auto badge = v::match(_descriptor, [&](GiftTypePremium data) { if (data.discountPercent > 0) { p.setBrush(st::attentionButtonFg); const auto kMinus = QChar(0x2212); - return kMinus + QString::number(data.discountPercent) + '%'; + return GiftBadge{ + .text = kMinus + QString::number(data.discountPercent) + '%', + .bg = st::attentionButtonFg->c, + .fg = st::windowBg->c, + }; } - return QString(); + return GiftBadge(); }, [&](const GiftTypeStars &data) { if (const auto count = data.info.limitedCount) { const auto soldOut = !data.userpic && !data.info.limitedLeft; - p.setBrush(unique - ? QBrush(unique->backdrop.patternColor) - : soldOut - ? st::attentionButtonFg - : st::windowActiveTextFg); - return soldOut - ? tr::lng_gift_stars_sold_out(tr::now) - : !data.userpic - ? tr::lng_gift_stars_limited(tr::now) - : (count == 1) - ? tr::lng_gift_limited_of_one(tr::now) - : tr::lng_gift_limited_of_count( - tr::now, - lt_amount, - ((count % 1000) - ? Lang::FormatCountDecimal(count) - : Lang::FormatCountToShort(count).string)); + return GiftBadge{ + .text = (soldOut + ? tr::lng_gift_stars_sold_out(tr::now) + : !data.userpic + ? tr::lng_gift_stars_limited(tr::now) + : (count == 1) + ? tr::lng_gift_limited_of_one(tr::now) + : tr::lng_gift_limited_of_count( + tr::now, + lt_amount, + (((count % 1000) && (count < 10'000)) + ? Lang::FormatCountDecimal(count) + : Lang::FormatCountToShort(count).string))), + .bg = (unique + ? unique->backdrop.patternColor + : soldOut + ? st::attentionButtonFg->c + : st::windowActiveTextFg->c), + .fg = unique ? QColor(255, 255, 255) : st::windowBg->c, + }; } - return QString(); + return GiftBadge(); }); - if (!text.isEmpty()) { - p.setPen(Qt::NoPen); - const auto twidth = font->width(text); - const auto pos = position + QPoint(singlew - twidth, font->height); - p.save(); + + if (badge) { const auto rubberOut = _extend.top(); const auto inner = rect().marginsRemoved(_extend); p.setClipRect(inner.marginsAdded( { rubberOut, rubberOut, rubberOut, rubberOut })); - p.translate(pos); - p.rotate(45.); - p.translate(-pos); - p.drawRect(-5 * twidth, position.y(), twidth * 12, font->height); - p.setPen(unique ? QPen(QColor(255, 255, 255)) : st::windowBg); - p.drawText(pos - QPoint(0, font->descent), text); - p.restore(); + + const auto cached = _delegate->cachedBadge(badge); + const auto width = cached.width() / cached.devicePixelRatio(); + p.drawImage( + position.x() + singlew + _extend.top() - width, + position.y() - _extend.top(), + cached); } - p.setBrush(unique - ? QBrush(QColor(255, 255, 255, .2 * 255)) - : premium - ? st::lightButtonBgOver - : st::creditsBg3); - p.setPen(Qt::NoPen); - if (!unique && !premium) { - p.setOpacity(0.12); - } - const auto geometry = _button; - const auto radius = geometry.height() / 2.; - p.drawRoundedRect(geometry, radius, radius); - if (!premium) { - p.setOpacity(1.); - } - if (unique) { - _stars.paint(p); - } else { - auto clipPath = QPainterPath(); - clipPath.addRoundedRect(geometry, radius, radius); - p.setClipPath(clipPath); - _stars.paint(p); - p.setClipping(false); + if (!_button.isEmpty()) { + p.setBrush(unique + ? QBrush(QColor(255, 255, 255, .2 * 255)) + : premium + ? st::lightButtonBgOver + : st::creditsBg3); + p.setPen(Qt::NoPen); + if (!unique && !premium) { + p.setOpacity(0.12); + } + const auto geometry = _button; + const auto radius = geometry.height() / 2.; + p.drawRoundedRect(geometry, radius, radius); + if (!premium) { + p.setOpacity(1.); + } + if (_stars) { + if (unique) { + _stars->paint(p); + } else { + auto clipPath = QPainterPath(); + clipPath.addRoundedRect(geometry, radius, radius); + p.setClipPath(clipPath); + _stars->paint(p); + p.setClipping(false); + } + } } if (!_text.isEmpty()) { @@ -420,25 +456,30 @@ void GiftButton::paintEvent(QPaintEvent *e) { }); } - const auto padding = st::giftBoxButtonPadding; - p.setPen(unique - ? QPen(QColor(255, 255, 255)) - : premium - ? st::windowActiveTextFg - : st::creditsFg); - _price.draw(p, { - .position = (geometry.topLeft() - + QPoint(padding.left(), padding.top())), - .availableWidth = _price.maxWidth(), - }); + if (!_button.isEmpty()) { + const auto padding = st::giftBoxButtonPadding; + p.setPen(unique + ? QPen(QColor(255, 255, 255)) + : premium + ? st::windowActiveTextFg + : st::creditsFg); + _price.draw(p, { + .position = (_button.topLeft() + + QPoint(padding.left(), padding.top())), + .availableWidth = _price.maxWidth(), + }); + } } -Delegate::Delegate(not_null window) +Delegate::Delegate( + not_null window, + GiftButtonMode mode) : _window(window) , _hiddenMark(std::make_unique( &window->session(), st::giftBoxHiddenMark, - RectPart::Center)) { + RectPart::Center)) +, _mode(mode) { } Delegate::Delegate(Delegate &&other) = default; @@ -466,7 +507,10 @@ QSize Delegate::buttonSize() { const auto available = width - padding.left() - padding.right(); const auto singlew = (available - 2 * st::giftBoxGiftSkip.x()) / kGiftsPerRow; - _single = QSize(singlew, st::giftBoxGiftHeight); + const auto minimal = (_mode == GiftButtonMode::Minimal); + _single = QSize( + singlew, + minimal ? st::giftBoxGiftSmall : st::giftBoxGiftHeight); return _single; } @@ -542,6 +586,15 @@ not_null Delegate::hiddenMark() { return _hiddenMark.get(); } +QImage Delegate::cachedBadge(const GiftBadge &badge) { + auto &image = _badges[badge]; + if (image.isNull()) { + const auto &extend = buttonExtend(); + image = ValidateRotatedBadge(badge, extend.top()); + } + return image; +} + DocumentData *LookupGiftSticker( not_null session, const GiftDescriptor &descriptor) { @@ -577,7 +630,57 @@ rpl::producer> GiftStickerValue( }, [&](GiftTypeStars data) { return rpl::single(data.info.document) | rpl::type_erased(); }); +} +QImage ValidateRotatedBadge(const GiftBadge &badge, int added) { + const auto &font = st::semiboldFont; + const auto twidth = font->width(badge.text) + 2 * added; + const auto skip = int(std::ceil(twidth / M_SQRT2)); + const auto ratio = style::DevicePixelRatio(); + const auto multiplier = ratio * 3; + const auto size = (twidth + font->height * 2); + const auto textpos = QPoint(size - skip, added); + auto image = QImage( + QSize(size, size) * multiplier, + QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::transparent); + image.setDevicePixelRatio(multiplier); + { + auto p = QPainter(&image); + auto hq = PainterHighQualityEnabler(p); + p.translate(textpos); + p.rotate(45.); + p.setFont(font); + p.setPen(badge.fg); + p.drawText(QPoint(added, font->ascent), badge.text); + } + + auto scaled = image.scaled( + QSize(size, size) * ratio, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); + scaled.setDevicePixelRatio(ratio); + + auto result = QImage( + QSize(size, size) * ratio, + QImage::Format_ARGB32_Premultiplied); + result.setDevicePixelRatio(ratio); + result.fill(Qt::transparent); + { + auto p = QPainter(&result); + auto hq = PainterHighQualityEnabler(p); + p.setPen(Qt::NoPen); + p.setBrush(badge.bg); + + p.save(); + p.translate(textpos); + p.rotate(45.); + p.drawRect(-5 * twidth, 0, twidth * 12, font->height); + p.restore(); + + p.drawImage(0, 0, scaled); + } + return result; } } // namespace Info::PeerGifts diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h index 48e502ea7..bf02e9e26 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "base/qt/qt_compare.h" #include "data/data_star_gift.h" #include "ui/abstract_button.h" #include "ui/effects/premium_stars_colored.h" @@ -71,6 +72,29 @@ struct GiftDescriptor : std::variant { const GiftDescriptor&) = default; }; +struct GiftBadge { + QString text; + QColor bg; + QColor fg; + + explicit operator bool() const { + return !text.isEmpty(); + } + + friend std::strong_ordering operator<=>( + const GiftBadge &a, + const GiftBadge &b); + + friend inline bool operator==( + const GiftBadge &, + const GiftBadge &) = default; +}; + +enum class GiftButtonMode { + Full, + Minimal, +}; + class GiftButtonDelegate { public: [[nodiscard]] virtual TextWithEntities star() = 0; @@ -85,6 +109,7 @@ public: [[nodiscard]] virtual rpl::producer> sticker( const GiftDescriptor &descriptor) = 0; [[nodiscard]] virtual not_null hiddenMark() = 0; + [[nodiscard]] virtual QImage cachedBadge(const GiftBadge &badge) = 0; }; class GiftButton final : public Ui::AbstractButton { @@ -92,7 +117,9 @@ public: GiftButton(QWidget *parent, not_null delegate); ~GiftButton(); - void setDescriptor(const GiftDescriptor &descriptor); + + using Mode = GiftButtonMode; + void setDescriptor(const GiftDescriptor &descriptor, Mode mode); void setGeometry(QRect inner, QMargins extend); private: @@ -118,7 +145,7 @@ private: QImage _uniqueBackgroundCache; std::unique_ptr _uniquePatternEmoji; base::flat_map _uniquePatternCache; - Ui::Premium::ColoredMiniStars _stars; + std::optional _stars; bool _subscribed = false; bool _patterned = false; @@ -132,7 +159,9 @@ private: class Delegate final : public GiftButtonDelegate { public: - explicit Delegate(not_null window); + Delegate( + not_null window, + GiftButtonMode mode); Delegate(Delegate &&other); ~Delegate(); @@ -148,12 +177,15 @@ public: rpl::producer> sticker( const GiftDescriptor &descriptor) override; not_null hiddenMark() override; + QImage cachedBadge(const GiftBadge &badge) override; private: const not_null _window; std::unique_ptr _hiddenMark; + base::flat_map _badges; QSize _single; QImage _bg; + GiftButtonMode _mode = GiftButtonMode::Full; }; @@ -165,4 +197,6 @@ private: not_null session, const GiftDescriptor &descriptor); +[[nodiscard]] QImage ValidateRotatedBadge(const GiftBadge &badge, int added); + } // namespace Info::PeerGifts diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp index 024901ed2..168b2ea9a 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_widget.cpp @@ -116,7 +116,7 @@ InnerWidget::InnerWidget( not_null user) : BoxContentDivider(parent) , _window(controller->parentController()) -, _delegate(_window) +, _delegate(_window, GiftButtonMode::Minimal) , _controller(controller) , _about(std::make_unique( this, @@ -271,6 +271,7 @@ void InnerWidget::validateButtons() { const auto fullw = _perRow * (_single.width() + skipw) - skipw; const auto left = padding.left() + (available - fullw) / 2; const auto oneh = _single.height() + st::giftBoxGiftSkip.y(); + const auto mode = GiftButton::Mode::Minimal; auto x = left; auto y = vskip + fromRow * oneh; auto views = std::vector(); @@ -301,7 +302,7 @@ void InnerWidget::validateButtons() { .entry = index, }); } - views.back().button->setDescriptor(descriptor); + views.back().button->setDescriptor(descriptor, mode); views.back().button->setClickedCallback(callback); }; for (auto j = fromRow; j != tillRow; ++j) { diff --git a/Telegram/SourceFiles/ui/effects/credits.style b/Telegram/SourceFiles/ui/effects/credits.style index 44d2cd554..15e27eec7 100644 --- a/Telegram/SourceFiles/ui/effects/credits.style +++ b/Telegram/SourceFiles/ui/effects/credits.style @@ -112,6 +112,7 @@ giftBoxTabBgActive: windowBgRipple; giftBoxPadding: margins(20px, 4px, 20px, 24px); giftBoxGiftSkip: point(10px, 8px); giftBoxGiftHeight: 164px; +giftBoxGiftSmall: 124px; giftBoxGiftRadius: 12px; giftBoxPremiumIconSize: 64px; giftBoxPremiumIconTop: 10px;