diff --git a/Telegram/SourceFiles/api/api_statistics.cpp b/Telegram/SourceFiles/api/api_statistics.cpp index fba7873499..fdb38e3892 100644 --- a/Telegram/SourceFiles/api/api_statistics.cpp +++ b/Telegram/SourceFiles/api/api_statistics.cpp @@ -639,9 +639,6 @@ void Boosts::requestBoosts( } : Data::GiftCodeLink(); list.push_back({ - data.is_gift(), - data.is_giveaway(), - data.is_unclaimed(), qs(data.vid()), data.vuser_id().value_or_empty(), data.vgiveaway_msg_id() @@ -652,6 +649,10 @@ void Boosts::requestBoosts( (data.vexpires().v - data.vdate().v) / kMonthsDivider, std::move(giftCodeLink), data.vmultiplier().value_or_empty(), + data.is_gift(), + data.is_giveaway(), + data.is_unclaimed(), + data.is_stars(), }); } done(Data::BoostsListSlice{ diff --git a/Telegram/SourceFiles/data/data_boosts.h b/Telegram/SourceFiles/data/data_boosts.h index a5924bc3d6..a92e409eec 100644 --- a/Telegram/SourceFiles/data/data_boosts.h +++ b/Telegram/SourceFiles/data/data_boosts.h @@ -27,10 +27,6 @@ struct GiftCodeLink final { }; struct Boost final { - bool isGift = false; - bool isGiveaway = false; - bool isUnclaimed = false; - QString id; UserId userId = UserId(0); FullMsgId giveawayMessage; @@ -39,6 +35,11 @@ struct Boost final { int expiresAfterMonths = 0; GiftCodeLink giftCodeLink; int multiplier = 0; + + bool isGift = false; + bool isGiveaway = false; + bool isUnclaimed = false; + bool isCredits = false; }; struct BoostsListSlice final { diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp index 86ec6c3209..087d571ece 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp @@ -479,6 +479,7 @@ private: Ui::EmptyUserpic _userpic; QImage _badge; QImage _rightBadge; + PaintRoundImageCallback _paintUserpicCallback; }; @@ -501,6 +502,55 @@ BoostRow::BoostRow(const Data::Boost &boost) } void BoostRow::init() { + if (!PeerListRow::special()) { + _paintUserpicCallback = PeerListRow::generatePaintUserpicCallback( + false); + } else { + _paintUserpicCallback = [=]( + Painter &p, + int x, + int y, + int outerWidth, + int size) mutable { + _userpic.paintCircle(p, x, y, outerWidth, size); + (_boost.isUnclaimed + ? st::boostsListUnclaimedIcon + : st::boostsListUnknownIcon).paintInCenter( + p, + Rect(x, y, Size(size))); + }; + } + if (_boost.isCredits) { + const auto copy = base::duplicate(_paintUserpicCallback); + const auto badgeSize = st::boostsListCreditsIconSize; + const auto drawCredits = Ui::PaintOutlinedColoredCreditsIconCallback( + badgeSize, + 1.); + _paintUserpicCallback = [=]( + Painter &p, + int x, + int y, + int outerWidth, + int size) { + auto result = QImage( + Size(size) * style::DevicePixelRatio(), + QImage::Format_ARGB32_Premultiplied); + result.fill(Qt::transparent); + result.setDevicePixelRatio(style::DevicePixelRatio()); + { + auto q = Painter(&result); + copy(q, 0, 0, outerWidth, size); + + const auto r = QRect( + QPoint(size - badgeSize, size - badgeSize), + Size(badgeSize)); + q.translate(r.x(), r.y()); + drawCredits(q); + } + p.drawImage(x, y, result); + }; + } + invalidateBadges(); auto status = !PeerListRow::special() ? tr::lng_boosts_list_status( @@ -528,17 +578,7 @@ QString BoostRow::generateName() { } PaintRoundImageCallback BoostRow::generatePaintUserpicCallback(bool force) { - if (!PeerListRow::special()) { - return PeerListRow::generatePaintUserpicCallback(force); - } - return [=](Painter &p, int x, int y, int outerWidth, int size) mutable { - _userpic.paintCircle(p, x, y, outerWidth, size); - (_boost.isUnclaimed - ? st::boostsListUnclaimedIcon - : st::boostsListUnknownIcon).paintInCenter( - p, - Rect(x, y, Size(size))); - }; + return _paintUserpicCallback; } void BoostRow::invalidateBadges() { diff --git a/Telegram/SourceFiles/statistics/statistics.style b/Telegram/SourceFiles/statistics/statistics.style index 3dd6a3f93f..882623394b 100644 --- a/Telegram/SourceFiles/statistics/statistics.style +++ b/Telegram/SourceFiles/statistics/statistics.style @@ -172,7 +172,8 @@ boostsListRightBadgeHeight: 20px; boostsListGiftMiniIconPadding: margins(4px, 2px, 0px, 0px); boostsListGiftMiniIcon: icon{{ "boosts/mini_gift", historyPeer8UserpicBg2 }}; boostsListGiveawayMiniIcon: icon{{ "boosts/mini_giveaway", historyPeer4UserpicBg2 }}; -boostsListUnclaimedIcon: icon{{ "boosts/boost_unknown", premiumButtonFg }}; -boostsListUnknownIcon: icon{{ "boosts/boost_unclaimed", premiumButtonFg }}; +boostsListUnclaimedIcon: icon{{ "boosts/boost_unclaimed", premiumButtonFg }}; +boostsListUnknownIcon: icon{{ "boosts/boost_unknown", premiumButtonFg }}; +boostsListCreditsIconSize: 13px; statisticsCurrencyIcon: icon {{ "statistics/mini_currency_graph", windowSubTextFg }}; diff --git a/Telegram/SourceFiles/ui/effects/credits_graphics.cpp b/Telegram/SourceFiles/ui/effects/credits_graphics.cpp index 58fe9ae411..f0ac9b682b 100644 --- a/Telegram/SourceFiles/ui/effects/credits_graphics.cpp +++ b/Telegram/SourceFiles/ui/effects/credits_graphics.cpp @@ -84,13 +84,7 @@ PaintRoundImageCallback MultiThumbnail( }; } -} // namespace - -QImage GenerateStars(int height, int count) { - constexpr auto kOutlineWidth = .6; - constexpr auto kStrokeWidth = 3; - constexpr auto kShift = 3; - +QByteArray CreditsIconSvg(int strokeWidth) { auto colorized = qs(Premium::ColorizedSvg( Premium::CreditsIconGradientStops())); colorized.replace( @@ -98,8 +92,18 @@ QImage GenerateStars(int height, int count) { u"stroke=\"%1\""_q.arg(st::creditsStroke->c.name())); colorized.replace( u"stroke-width=\"1\""_q, - u"stroke-width=\"%1\""_q.arg(kStrokeWidth)); - auto svg = QSvgRenderer(colorized.toUtf8()); + u"stroke-width=\"%1\""_q.arg(strokeWidth)); + return colorized.toUtf8(); +} + +} // namespace + +QImage GenerateStars(int height, int count) { + constexpr auto kOutlineWidth = .6; + constexpr auto kStrokeWidth = 3; + constexpr auto kShift = 3; + + auto svg = QSvgRenderer(CreditsIconSvg(kStrokeWidth)); svg.setViewBox(svg.viewBox() + Margins(kStrokeWidth)); const auto starSize = Size(height - kOutlineWidth * 2); @@ -472,6 +476,35 @@ TextWithEntities GenerateEntryName(const Data::CreditsHistoryEntry &entry) { TextWithEntities::Simple); } +Fn PaintOutlinedColoredCreditsIconCallback( + int size, + float64 outlineRatio) { + // constexpr auto kIdealSize = 42; + constexpr auto kPoints = uint(16); + constexpr auto kAngleStep = 2. * M_PI / kPoints; + constexpr auto kOutlineWidth = 1.6; + constexpr auto kStarShift = 3.8; + constexpr auto kStrokeWidth = 3; + const auto starSize = Size(size); + + auto svg = std::make_shared(CreditsIconSvg(kStrokeWidth)); + svg->setViewBox(svg->viewBox() + Margins(kStrokeWidth)); + const auto s = style::ConvertFloatScale(kOutlineWidth * outlineRatio); + return [=](QPainter &q) { + q.save(); + q.setCompositionMode(QPainter::CompositionMode_Clear); + for (auto i = 0; i < kPoints; ++i) { + const auto angle = i * kAngleStep; + const auto x = s * std::cos(angle); + const auto y = s * std::sin(angle); + svg->render(&q, QRectF(QPointF(x, y), starSize)); + } + q.setCompositionMode(QPainter::CompositionMode_SourceOver); + svg->render(&q, Rect(starSize)); + q.restore(); + }; +} + QImage CreditsWhiteDoubledIcon(int size, float64 outlineRatio) { auto svg = QSvgRenderer(Ui::Premium::Svg()); auto result = QImage( diff --git a/Telegram/SourceFiles/ui/effects/credits_graphics.h b/Telegram/SourceFiles/ui/effects/credits_graphics.h index 7880f2b7a4..038db1c8cb 100644 --- a/Telegram/SourceFiles/ui/effects/credits_graphics.h +++ b/Telegram/SourceFiles/ui/effects/credits_graphics.h @@ -20,12 +20,10 @@ class Session; } // namespace Main namespace Ui { + class MaskedInputField; class RpWidget; class VerticalLayout; -} // namespace Ui - -namespace Ui { using PaintRoundImageCallback = Fn)> PaintPreviewCallback( [[nodiscard]] TextWithEntities GenerateEntryName( const Data::CreditsHistoryEntry &entry); +Fn PaintOutlinedColoredCreditsIconCallback( + int size, + float64 outlineRatio); + [[nodiscard]] QImage CreditsWhiteDoubledIcon(int size, float64 outlineRatio); } // namespace Ui