From 8c515d375135d03f72fe052b945051578ddb5751 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 21 Jan 2026 14:14:23 +0400 Subject: [PATCH] Support rare/legendary/epic rarities. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/api/api_premium.cpp | 32 +++++++------- .../SourceFiles/boxes/gift_premium_box.cpp | 36 +++++++++++----- .../boxes/star_gift_auction_box.cpp | 2 +- Telegram/SourceFiles/boxes/star_gift_box.cpp | 2 +- .../boxes/star_gift_preview_box.cpp | 2 +- Telegram/SourceFiles/data/data_star_gift.cpp | 43 +++++++++++++++++++ Telegram/SourceFiles/data/data_star_gift.h | 31 ++++++++++++- .../SourceFiles/ui/controls/table_rows.cpp | 11 +++-- Telegram/SourceFiles/ui/controls/table_rows.h | 11 ++++- .../ui/widgets/gradient_round_button.h | 2 +- 11 files changed, 134 insertions(+), 39 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index ffbc01391b..c693ac1d01 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3817,6 +3817,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_gift_limited_of_count" = "1 of {amount}"; "lng_gift_collectible_tag" = "gift"; "lng_gift_crafted_tag" = "crafted"; +"lng_gift_rare_tag" = "rare"; "lng_gift_epic_tag" = "epic"; "lng_gift_legendary_tag" = "legendary"; "lng_gift_view_unpack" = "Unpack"; diff --git a/Telegram/SourceFiles/api/api_premium.cpp b/Telegram/SourceFiles/api/api_premium.cpp index 58a0a6e883..67222fc2ea 100644 --- a/Telegram/SourceFiles/api/api_premium.cpp +++ b/Telegram/SourceFiles/api/api_premium.cpp @@ -1042,6 +1042,18 @@ std::optional FromTL( }; } +int ParseRarity(const MTPStarGiftAttributeRarity &rarity) { + return rarity.match([&](const MTPDstarGiftAttributeRarity &data) { + return data.vpermille().v; + }, [&](const MTPDstarGiftAttributeRarityRare &) { + return int(Data::UniqueGiftRarity::Rare); + }, [&](const MTPDstarGiftAttributeRarityEpic &) { + return int(Data::UniqueGiftRarity::Epic); + }, [&](const MTPDstarGiftAttributeRarityLegendary &) { + return int(Data::UniqueGiftRarity::Legendary); + }); +} + Data::UniqueGiftModel FromTL( not_null session, const MTPDstarGiftAttributeModel &data) { @@ -1049,17 +1061,7 @@ Data::UniqueGiftModel FromTL( .document = session->data().processDocument(data.vdocument()), }; result.name = qs(data.vname()); - data.vrarity().match([&](const MTPDstarGiftAttributeRarity &data) { - result.rarityPermille = data.vpermille().v; - }, [](const auto &) {}); - //MTPDstarGiftAttributeRarityRare &c_starGiftAttributeRarityRare() const; - //[[nodiscard]] const MTPDstarGiftAttributeRarityEpic &c_starGiftAttributeRarityEpic() const; - //[[nodiscard]] const MTPDstarGiftAttributeRarityLegendary &c_starGiftAttributeRarityLegendary() const; - //[[nodiscard]] const MTPDstarGiftAttributeRarityMythic &c_starGiftAttributeRarityMythic() const; - // ); - //data.vrarity().c_starGiftAttributeRarity(); - //data.vrarity().c_() - //result.rarityPermille = data.vrarity_permille().v; + result.rarityValue = ParseRarity(data.vrarity()); return result; } @@ -1071,18 +1073,14 @@ Data::UniqueGiftPattern FromTL( }; result.document->overrideEmojiUsesTextColor(true); result.name = qs(data.vname()); - data.vrarity().match([&](const MTPDstarGiftAttributeRarity &data) { - result.rarityPermille = data.vpermille().v; - }, [](const auto &) {}); + result.rarityValue = ParseRarity(data.vrarity()); return result; } Data::UniqueGiftBackdrop FromTL(const MTPDstarGiftAttributeBackdrop &data) { auto result = Data::UniqueGiftBackdrop{ .id = data.vbackdrop_id().v }; result.name = qs(data.vname()); - data.vrarity().match([&](const MTPDstarGiftAttributeRarity &data) { - result.rarityPermille = data.vpermille().v; - }, [](const auto &) {}); + result.rarityValue = ParseRarity(data.vrarity()); result.centerColor = Ui::ColorFromSerialized( data.vcenter_color()); result.edgeColor = Ui::ColorFromSerialized( diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index 1ca9042008..b384c60c25 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -65,6 +65,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text/format_values.h" #include "ui/text/text_utilities.h" #include "ui/toast/toast.h" +#include "ui/widgets/buttons.h" #include "ui/widgets/checkbox.h" #include "ui/widgets/gradient_round_button.h" #include "ui/widgets/tooltip.h" @@ -222,7 +223,7 @@ using SpinnerState = Data::GiftUpgradeSpinner::State; const auto prefix = (use > 0) ? u"+"_q : QString(); const auto percent = Lang::FormatExactCountDecimal(use) + '%'; auto text = rpl::single(prefix + percent); - return MakeValueWithSmallButton(table, label, std::move(text)); + return MakeValueWithSmallButton(table, label, std::move(text)).widget; } [[nodiscard]] object_ptr MakeMinimumPriceValue( @@ -241,7 +242,7 @@ using SpinnerState = Data::GiftUpgradeSpinner::State; tr::bold(text.text), lt_gift, tr::bold(unique->title), - tr::marked)); + tr::marked)).widget; } [[nodiscard]] object_ptr MakeAveragePriceValue( @@ -260,7 +261,7 @@ using SpinnerState = Data::GiftUpgradeSpinner::State; tr::bold(text.text), lt_gift, tr::bold(unique->title), - tr::marked)); + tr::marked)).widget; } [[nodiscard]] object_ptr MakeAttributeValue( @@ -273,13 +274,25 @@ using SpinnerState = Data::GiftUpgradeSpinner::State; table->st().defaultValue); label->setAttribute(Qt::WA_TransparentForMouseEvents); - const auto permille = attribute.rarityPermille; - auto text = rpl::single(QString::number(permille / 10.) + '%'); + const auto permille = attribute.rarityPermille(); + const auto rarity = attribute.rarityType(); + auto text = rpl::single(Data::UniqueGiftAttributeText(attribute)); const auto handler = [=](not_null button) { showTooltip(button, permille); }; - return MakeValueWithSmallButton(table, label, std::move(text), handler); + auto result = MakeValueWithSmallButton( + table, + label, + std::move(text), + handler); + if (rarity != Data::UniqueGiftRarity::Default) { + const auto colors = Data::UniqueGiftRarityBadgeColors(rarity); + result.button->setBrushOverride(colors.bg); + result.button->setTextFgOverride(colors.fg); + result.button->setRippleOverride(colors.bg); + } + return std::move(result.widget); } [[nodiscard]] object_ptr MakeAttributeValue( @@ -500,7 +513,7 @@ void AddUniqueGiftPropertyRows( const auto showRarity = [=](Data::GiftAttributeId id) { return [=]( not_null widget, - int rarity) { + int rarityPermille) { initVariants(); const auto weak = base::make_weak(widget); @@ -517,10 +530,11 @@ void AddUniqueGiftPropertyRows( id.type, unique)); } else if (const auto widget = weak.get()) { - const auto percent = QString::number(rarity / 10.) + '%'; + const auto percent = Data::UniqueGiftAttributeText( + { .rarityValue = rarityPermille }); showTooltip(widget, tr::lng_gift_unique_rarity( lt_percent, - rpl::single(TextWithEntities{ percent }), + rpl::single(tr::marked(percent)), tr::marked)); } }); @@ -615,7 +629,7 @@ void AddUniqueGiftPropertyRows( table, label.release(), std::move(text), - handler); + handler).widget; } [[nodiscard]] object_ptr MakeUniqueGiftValueValue( @@ -673,7 +687,7 @@ void AddUniqueGiftPropertyRows( table, label, tr::lng_gift_unique_value_learn_more(), - handler); + handler).widget; } void AddTable( diff --git a/Telegram/SourceFiles/boxes/star_gift_auction_box.cpp b/Telegram/SourceFiles/boxes/star_gift_auction_box.cpp index 29960cb216..5379c37217 100644 --- a/Telegram/SourceFiles/boxes/star_gift_auction_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_auction_box.cpp @@ -952,7 +952,7 @@ void AuctionBidBox(not_null box, AuctionBidBoxArgs &&args) { lt_gift, tr::bold(name), tr::marked), - helper.context()); + helper.context()).widget; } [[nodiscard]] object_ptr AuctionInfoTable( diff --git a/Telegram/SourceFiles/boxes/star_gift_box.cpp b/Telegram/SourceFiles/boxes/star_gift_box.cpp index 3a907bb986..603924baf8 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_box.cpp @@ -3385,7 +3385,7 @@ void AddUniqueGiftCover( value.name); state.percent = Ui::Text::String( st::uniqueAttributePercent, - QString::number(value.rarityPermille / 10.) + '%'); + Data::UniqueGiftAttributeText(value)); }; set(astate->model, gift.model); set(astate->pattern, gift.pattern); diff --git a/Telegram/SourceFiles/boxes/star_gift_preview_box.cpp b/Telegram/SourceFiles/boxes/star_gift_preview_box.cpp index 879bc91270..3ec8d021c7 100644 --- a/Telegram/SourceFiles/boxes/star_gift_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_preview_box.cpp @@ -309,7 +309,7 @@ void AttributeButton::setup() { _name.setText(st::uniqueAttributeName, data.name); _percent.setText( st::uniqueAttributePercent, - QString::number(data.rarityPermille / 10.) + '%'); + Data::UniqueGiftAttributeText(data)); }); v::match(_descriptor, [&](const GiftBackdrop &data) { diff --git a/Telegram/SourceFiles/data/data_star_gift.cpp b/Telegram/SourceFiles/data/data_star_gift.cpp index adebd29916..b1dc080166 100644 --- a/Telegram/SourceFiles/data/data_star_gift.cpp +++ b/Telegram/SourceFiles/data/data_star_gift.cpp @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_document.h" #include "data/data_session.h" #include "data/data_user.h" +#include "lang/lang_keys.h" #include "lang/lang_tag.h" #include "main/main_session.h" #include "ui/controls/ton_common.h" @@ -66,6 +67,48 @@ QString UniqueGiftName(const QString &title, int number) { return title + u" #"_q + QString::number(number); } +QString UniqueGiftRarityText(UniqueGiftRarity type) { + switch (type) { + case UniqueGiftRarity::Rare: + return tr::lng_gift_rare_tag(tr::now); + case UniqueGiftRarity::Epic: + return tr::lng_gift_epic_tag(tr::now); + case UniqueGiftRarity::Legendary: + return tr::lng_gift_legendary_tag(tr::now); + } + return QString(); +} + +UniqueGiftRarityColors UniqueGiftRarityBadgeColors(UniqueGiftRarity type) { + constexpr auto kBgOpacity = 0.15; + const auto base = [&] { + switch (type) { + case UniqueGiftRarity::Rare: return st::historyPeer2NameFg->c; + case UniqueGiftRarity::Epic: return st::historyPeer5NameFg->c; + case UniqueGiftRarity::Legendary: return st::historyPeer3NameFg->c; + } + Unexpected("Invalid rarity type."); + }(); + auto bg = base; + bg.setAlphaF(kBgOpacity); + return { bg, base }; +} + +QString UniqueGiftAttributeText(const UniqueGiftAttribute &attribute) { + const auto type = attribute.rarityType(); + if (type != UniqueGiftRarity::Default) { + return UniqueGiftRarityText(type); + } + const auto permille = attribute.rarityPermille(); + return (permille > 0) + ? (QString::number(permille / 10.) + '%') + : u"< 0.1%"_q; +} + +bool UniqueGiftAttributeHasSpecialRarity(const UniqueGiftAttribute &attribute) { + return attribute.rarityType() != UniqueGiftRarity::Default; +} + CreditsAmount UniqueGiftResaleStars(const UniqueGift &gift) { return CreditsAmount(gift.starsForResale); } diff --git a/Telegram/SourceFiles/data/data_star_gift.h b/Telegram/SourceFiles/data/data_star_gift.h index 6515479329..2426ebc4f4 100644 --- a/Telegram/SourceFiles/data/data_star_gift.h +++ b/Telegram/SourceFiles/data/data_star_gift.h @@ -17,15 +17,44 @@ struct ColorCollectible; namespace Data { +enum class UniqueGiftRarity : int { + Default = 0, + Rare = -1, + Epic = -2, + Legendary = -3, +}; + struct UniqueGiftAttribute { QString name; - int rarityPermille = 0; + int rarityValue = 0; + + [[nodiscard]] UniqueGiftRarity rarityType() const { + return (rarityValue >= 0) + ? UniqueGiftRarity::Default + : UniqueGiftRarity(rarityValue); + } + [[nodiscard]] int rarityPermille() const { + return (rarityValue >= 0) ? rarityValue : 0; + } friend inline bool operator==( const UniqueGiftAttribute &, const UniqueGiftAttribute &) = default; }; +struct UniqueGiftRarityColors { + QColor bg; + QColor fg; +}; + +[[nodiscard]] QString UniqueGiftRarityText(UniqueGiftRarity type); +[[nodiscard]] UniqueGiftRarityColors UniqueGiftRarityBadgeColors( + UniqueGiftRarity type); +[[nodiscard]] QString UniqueGiftAttributeText( + const UniqueGiftAttribute &attribute); +[[nodiscard]] bool UniqueGiftAttributeHasSpecialRarity( + const UniqueGiftAttribute &attribute); + struct UniqueGiftModel : UniqueGiftAttribute { not_null document; diff --git a/Telegram/SourceFiles/ui/controls/table_rows.cpp b/Telegram/SourceFiles/ui/controls/table_rows.cpp index 3ffd3fc260..78054e3020 100644 --- a/Telegram/SourceFiles/ui/controls/table_rows.cpp +++ b/Telegram/SourceFiles/ui/controls/table_rows.cpp @@ -87,7 +87,7 @@ void AddTableRow( st::giveawayGiftCodePeerMargin); } -object_ptr MakeValueWithSmallButton( +ValueWithSmallButton MakeValueWithSmallButton( not_null table, not_null value, rpl::producer buttonText, @@ -139,7 +139,10 @@ object_ptr MakeValueWithSmallButton( raw->resize(raw->width(), height + bottom); }, raw->lifetime()); - return result; + return { + .widget = std::move(result), + .button = button, + }; } object_ptr MakePeerTableValue( @@ -193,7 +196,7 @@ object_ptr MakePeerTableValue( result.release(), std::move(button), [=](not_null button) { handler(); }, - st::giveawayGiftCodeNamePosition.y()); + st::giveawayGiftCodeNamePosition.y()).widget; } object_ptr MakePeerWithStatusValue( @@ -372,7 +375,7 @@ void ShowTableRowTooltip( }, tooltip->lifetime()); } -object_ptr MakeTableValueWithTooltip( +ValueWithSmallButton MakeTableValueWithTooltip( not_null table, std::shared_ptr data, TextWithEntities price, diff --git a/Telegram/SourceFiles/ui/controls/table_rows.h b/Telegram/SourceFiles/ui/controls/table_rows.h index a5c0c120cc..7d27697828 100644 --- a/Telegram/SourceFiles/ui/controls/table_rows.h +++ b/Telegram/SourceFiles/ui/controls/table_rows.h @@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "base/object_ptr.h" + namespace st { extern const style::margins &giveawayGiftCodeLabelMargin; extern const style::margins &giveawayGiftCodeValueMargin; @@ -21,6 +23,7 @@ namespace Ui { class RpWidget; class TableLayout; class FlatLabel; +class RoundButton; class ImportantTooltip; void AddTableRow( @@ -42,7 +45,11 @@ void AddTableRow( PeerId id); -[[nodiscard]] object_ptr MakeValueWithSmallButton( +struct ValueWithSmallButton { + object_ptr widget; + not_null button; +}; +[[nodiscard]] ValueWithSmallButton MakeValueWithSmallButton( not_null table, not_null value, rpl::producer buttonText, @@ -73,7 +80,7 @@ void ShowTableRowTooltip( int duration, const Text::MarkedContext &context = {}); -[[nodiscard]] object_ptr MakeTableValueWithTooltip( +[[nodiscard]] ValueWithSmallButton MakeTableValueWithTooltip( not_null table, std::shared_ptr data, TextWithEntities price, diff --git a/Telegram/SourceFiles/ui/widgets/gradient_round_button.h b/Telegram/SourceFiles/ui/widgets/gradient_round_button.h index 941bfccadc..120f2b6d8a 100644 --- a/Telegram/SourceFiles/ui/widgets/gradient_round_button.h +++ b/Telegram/SourceFiles/ui/widgets/gradient_round_button.h @@ -23,7 +23,7 @@ public: void setGlarePaused(bool paused); private: - void paintEvent(QPaintEvent *e); + void paintEvent(QPaintEvent *e) override; void paintGlare(QPainter &p); void validateBg(); void validateGlare();