From db09c071d8f347010088229e2012bae11f6d16d8 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 20 Jan 2026 17:31:08 +0400 Subject: [PATCH] Nice state display in crafting middle. --- Telegram/SourceFiles/api/api_premium.cpp | 4 +- .../SourceFiles/boxes/star_gift_craft_box.cpp | 316 ++++++++++++++++-- .../export/data/export_data_types.cpp | 2 - Telegram/SourceFiles/history/history_item.cpp | 10 - .../view/history_view_paid_reaction_toast.cpp | 1 - .../view/media_view_playback_sponsored.cpp | 1 - Telegram/SourceFiles/mtproto/scheme/api.tl | 11 +- Telegram/SourceFiles/ui/effects/credits.style | 20 +- .../SourceFiles/ui/effects/premium_bubble.cpp | 1 - 9 files changed, 313 insertions(+), 53 deletions(-) diff --git a/Telegram/SourceFiles/api/api_premium.cpp b/Telegram/SourceFiles/api/api_premium.cpp index 1ff23cdf42..58a0a6e883 100644 --- a/Telegram/SourceFiles/api/api_premium.cpp +++ b/Telegram/SourceFiles/api/api_premium.cpp @@ -945,6 +945,8 @@ std::optional FromTL( .releasedBy = releasedBy, .themeUser = themeUser, .nanoTonForResale = FindTonForResale(data.vresell_amount()), + .craftChancePermille + = data.vcraft_chance_permille().value_or_empty(), .starsForResale = FindStarsForResale(data.vresell_amount()), .starsMinOffer = data.voffer_min_stars().value_or(-1), .number = data.vnum().v, @@ -1001,8 +1003,6 @@ std::optional FromTL( unique->canTransferAt = data.vcan_transfer_at().value_or_empty(); unique->canResellAt = data.vcan_resell_at().value_or_empty(); unique->canCraftAt = data.vcan_craft_at().value_or_empty(); - unique->craftChancePermille - = data.vcraft_chance_permille().value_or_empty(); } using Id = Data::SavedStarGiftId; const auto hasUnique = parsed->unique != nullptr; diff --git a/Telegram/SourceFiles/boxes/star_gift_craft_box.cpp b/Telegram/SourceFiles/boxes/star_gift_craft_box.cpp index b57df215a1..655f4df8bb 100644 --- a/Telegram/SourceFiles/boxes/star_gift_craft_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_craft_box.cpp @@ -23,12 +23,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/boxes/about_cocoon_box.h" // AddUniqueCloseButton. #include "ui/controls/button_labels.h" #include "ui/controls/feature_list.h" +#include "ui/effects/numbers_animation.h" #include "ui/layers/generic_box.h" #include "ui/widgets/buttons.h" #include "ui/painter.h" #include "ui/top_background_gradient.h" #include "ui/vertical_list.h" #include "window/window_session_controller.h" +#include "styles/style_chat_helpers.h" // stickerPanDeleteIconFg #include "styles/style_credits.h" #include "styles/style_layers.h" #include "styles/style_menu_icons.h" @@ -83,10 +85,191 @@ struct CraftingView { rpl::producer removeRequests; }; +[[nodiscard]] QString FormatPercent(int permille) { + const auto rounded = (permille + 5) / 10; + return QString::number(rounded) + '%'; +} + +[[nodiscard]] not_null MakeRadialPercent( + not_null parent, + const style::CraftRadialPercent &st, + rpl::producer permille) { + auto raw = CreateChild(parent); + + struct State { + State(const style::CraftRadialPercent &st, Fn callback) + : numbers(st.font, std::move(callback)) { + } + + Animations::Simple animation; + NumbersAnimation numbers; + int permille = 0; + }; + const auto state = raw->lifetime().make_state( + st, + [=] { raw->update(); }); + + std::move(permille) | rpl::on_next([=](int value) { + if (state->permille == value) { + return; + } + state->animation.start([=] { + raw->update(); + }, state->permille, value, st::slideWrapDuration); + state->permille = value; + state->numbers.setText(FormatPercent(value), value); + }, raw->lifetime()); + state->animation.stop(); + state->numbers.finishAnimating(); + + raw->show(); + raw->setAttribute(Qt::WA_TransparentForMouseEvents); + raw->paintOn([=, &st](QPainter &p) { + static constexpr auto kArcSkip = arc::kFullLength / 4; + static constexpr auto kArcStart = -(arc::kHalfLength - kArcSkip) / 2; + static constexpr auto kArcLength = arc::kFullLength - kArcSkip; + + const auto paint = [&](QColor color, float64 permille) { + p.setPen(QPen(color, st.stroke, Qt::SolidLine, Qt::RoundCap)); + p.setBrush(Qt::NoBrush); + const auto part = kArcLength * (permille / 1000.); + const auto length = int(base::SafeRound(part)); + const auto inner = raw->rect().marginsRemoved( + { st.stroke, st.stroke, st.stroke, st.stroke }); + p.drawArc(inner, kArcStart + kArcLength - length, length); + }; + + auto hq = PainterHighQualityEnabler(p); + + auto inactive = QColor(255, 255, 255, 64); + paint(inactive, 1000.); + paint(st::white->c, state->animation.value(state->permille)); + + state->numbers.paint( + p, + (raw->width() - state->numbers.countWidth()) / 2, + raw->height() - st.font->height, + raw->width()); + }); + + return raw; +} + +AbstractButton *MakeCornerButton( + not_null parent, + not_null button, + object_ptr content, + style::align align, + const GiftForCraft &gift, + rpl::producer edgeColor) { + Expects(content != nullptr); + + const auto result = CreateChild(parent); + result->show(); + + const auto inner = content.release(); + inner->setParent(result); + inner->show(); + inner->sizeValue() | rpl::on_next([=](QSize size) { + result->resize(size); + }, result->lifetime()); + inner->move(0, 0); + + rpl::combine( + button->geometryValue(), + result->sizeValue() + ) | rpl::on_next([=](QRect geometry, QSize size) { + const auto extend = st::defaultDropdownMenu.wrap.shadow.extend; + geometry = geometry.marginsRemoved(extend); + const auto out = QPoint(size.width(), size.height()) / 3; + const auto left = (align == style::al_left) + ? (geometry.x() - out.x()) + : (geometry.x() + geometry.width() - size.width() + out.x()); + const auto top = geometry.y() - out.y(); + result->move(left, top); + }, result->lifetime()); + + struct State { + rpl::variable edgeColor; + QColor buttonEdgeColor; + }; + const auto state = result->lifetime().make_state(); + state->edgeColor = std::move(edgeColor); + state->buttonEdgeColor = gift.unique->backdrop.edgeColor; + result->paintOn([=](QPainter &p) { + const auto right = result->width(); + const auto bottom = result->height(); + const auto add = QPoint(right, bottom) / 3; + const auto radius = bottom / 2.; + auto gradient = QLinearGradient( + (align == style::al_left) ? -add.x() : (right + add.x()), + -add.y(), + (align == style::al_left) ? (right + add.x()) : -add.x(), + bottom + add.y()); + gradient.setColorAt(0, state->edgeColor.current()); + gradient.setColorAt(1, state->buttonEdgeColor); + auto hq = PainterHighQualityEnabler(p); + p.setPen(Qt::NoPen); + p.setBrush(gradient); + p.drawRoundedRect(result->rect(), radius, radius); + }); + + return result; +} + +AbstractButton *MakePercentButton( + not_null parent, + not_null button, + const GiftForCraft &gift, + rpl::producer edgeColor) { + auto label = object_ptr( + parent, + FormatPercent(gift.unique->craftChancePermille), + st::craftPercentLabel); + label->setTextColorOverride(st::white->c); + const auto result = MakeCornerButton( + parent, + button, + std::move(label), + style::al_left, + gift, + std::move(edgeColor)); + result->setAttribute(Qt::WA_TransparentForMouseEvents); + return result; +} + +AbstractButton *MakeRemoveButton( + not_null parent, + not_null button, + int size, + const GiftForCraft &gift, + Fn onClick, + rpl::producer edgeColor) { + auto remove = object_ptr(parent); + const auto &icon = st::stickerPanDeleteIconFg; + const auto add = (size - icon.width()) / 2; + remove->resize(icon.size() + QSize(add, add) * 2); + remove->paintOn([=](QPainter &p) { + const auto &icon = st::stickerPanDeleteIconFg; + icon.paint(p, add, add, add * 2 + icon.width(), st::white->c); + }); + remove->setAttribute(Qt::WA_TransparentForMouseEvents); + const auto result = MakeCornerButton( + parent, + button, + std::move(remove), + style::al_right, + gift, + std::move(edgeColor)); + result->setClickedCallback(std::move(onClick)); + return result; +} + [[nodiscard]] CraftingView MakeCraftingView( not_null parent, not_null session, - rpl::producer> chosen) { + rpl::producer> chosen, + rpl::producer edgeColor) { const auto width = st::boxWidth; const auto buttonPadding = st::craftPreviewPadding; @@ -114,8 +297,11 @@ struct CraftingView { Fn refreshButton; rpl::event_stream editRequests; rpl::event_stream removeRequests; + rpl::variable chancePermille; + rpl::variable edgeColor; }; const auto state = raw->lifetime().make_state(session); + state->edgeColor = std::move(edgeColor); state->refreshButton = [=](int index) { Expects(index >= 0 && index < state->entries.size()); @@ -156,6 +342,12 @@ struct CraftingView { entry.button->setGeometry( geometry, state->delegate.buttonExtend()); + + entry.percent = MakePercentButton( + raw, + entry.button, + entry.gift, + state->edgeColor.value()); } else { entry.add = CreateChild(raw); entry.add->show(); @@ -176,43 +368,81 @@ struct CraftingView { }); entry.add->setGeometry(geometry); } + + const auto count = 4 - ranges::count( + state->entries, + nullptr, + &Entry::button); + const auto canRemove = (count > 1); + for (auto i = 0; i != 4; ++i) { + auto &entry = state->entries[i]; + if (entry.button) { + if (!canRemove) { + delete base::take(entry.remove); + } else if (!entry.remove) { + entry.remove = MakeRemoveButton( + raw, + entry.button, + entry.percent->height(), + entry.gift, + [=] { state->removeRequests.fire_copy(i); }, + state->edgeColor.value()); + } + } + } }; std::move( chosen ) | rpl::on_next([=](const std::vector &gifts) { + auto chance = 0; for (auto i = 0; i != 4; ++i) { auto &entry = state->entries[i]; const auto gift = (i < gifts.size()) ? gifts[i] : GiftForCraft(); + chance += gift.unique ? gift.unique->craftChancePermille : 0; if (entry.gift == gift && (entry.button || entry.add)) { continue; } entry.gift = gift; state->refreshButton(i); } + state->chancePermille = chance; }, raw->lifetime()); + const auto center = [&] { + const auto buttonPadding = st::craftPreviewPadding; + const auto buttonSize = st::giftBoxGiftTiny; + const auto left = buttonPadding.left() + + buttonSize + + buttonPadding.right(); + const auto center = (width - 2 * left); + const auto top = (height - center) / 2; + return QRect(left, top, center, center); + }(); raw->paintOn([=](QPainter &p) { auto hq = PainterHighQualityEnabler(p); const auto radius = st::boxRadius; - const auto buttonPadding = st::craftPreviewPadding; - const auto buttonSize = st::giftBoxGiftTiny; - const auto one = buttonPadding.left() - + buttonSize - + buttonPadding.right(); - const auto center = (width - 2 * one); - const auto top = (height - center) / 2; p.setPen(Qt::NoPen); p.setBrush(QColor(255, 255, 255, 32)); - const auto rect = QRect(one, top, center, center); - p.drawRoundedRect(rect, radius, radius); + p.drawRoundedRect(center, radius, radius); - st::craftForge.paintInCenter(p, rect, st::white->c); + st::craftForge.paintInCenter(p, center, st::white->c); }); + MakeRadialPercent( + raw, + st::craftForgePercent, + state->chancePermille.value() + )->setGeometry(center.marginsRemoved({ + st::craftForgePadding, + st::craftForgePadding, + st::craftForgePadding, + st::craftForgePadding, + })); + return { .widget = std::move(widget), .editRequests = state->editRequests.events(), @@ -367,6 +597,8 @@ void MakeCraftContent( Delegate delegate; std::array covers; + rpl::variable coverEdgeColor; + bool coversAnimate = false; rpl::variable> chosen; rpl::variable name; @@ -378,6 +610,7 @@ void MakeCraftContent( }; const auto session = &controller->session(); const auto state = box->lifetime().make_state(session); + state->coversAnimate = true; { auto backdrops = CraftBackdrops(); @@ -407,12 +640,28 @@ void MakeCraftContent( return result; }); state->successPercentText = state->successPercentPermille.value( - ) | rpl::map([](int permille) { - return QString::number(permille / 10.) + '%'; - }); + ) | rpl::map(FormatPercent); const auto raw = box->verticalLayout(); + state->chosen.value( + ) | rpl::on_next([=](const std::vector &gifts) { + const auto count = int(gifts.size()); + for (auto i = 4; i != 0;) { + auto &cover = state->covers[--i]; + const auto shown = (i < count); + if (cover.shown != shown) { + cover.shown = shown; + const auto from = shown ? 0. : 1.; + const auto to = shown ? 1. : 0.; + cover.shownAnimation.start([=] { + raw->update(); + }, from, to, st::fadeWrapDuration); + state->coversAnimate = true; + } + } + }, box->lifetime()); + const auto title = raw->add( object_ptr( box, @@ -422,7 +671,11 @@ void MakeCraftContent( style::al_top); title->setTextColorOverride(QColor(255, 255, 255)); - auto crafting = MakeCraftingView(raw, session, state->chosen.value()); + auto crafting = MakeCraftingView( + raw, + session, + state->chosen.value(), + state->coverEdgeColor.value()); raw->add(std::move(crafting.widget)); std::move(crafting.removeRequests) | rpl::on_next([=](int index) { auto chosen = state->chosen.current(); @@ -471,21 +724,7 @@ void MakeCraftContent( } else { copy.push_back(chosen); } - const auto count = int(copy.size()); state->chosen = std::move(copy); - - for (auto i = 4; i != 0;) { - auto &cover = state->covers[--i]; - const auto shown = (i < count); - if (cover.shown != shown) { - cover.shown = shown; - const auto from = shown ? 0. : 1.; - const auto to = shown ? 1. : 0.; - cover.shownAnimation.start([=] { - raw->update(); - }, from, to, st::fadeWrapDuration); - } - } }); }).send(); }, raw->lifetime()); @@ -544,8 +783,13 @@ void MakeCraftContent( QRect(0, 0, width, st::uniqueGiftSubtitleTop), shown); }; + auto animating = false; + auto edgeColor = std::optional(); for (auto i = 0; i != 4; ++i) { auto &cover = state->covers[i]; + if (cover.shownAnimation.animating()) { + animating = true; + } const auto finalValue = cover.shown ? 1. : 0.; const auto shown = cover.shownAnimation.value(finalValue); if (shown <= 0.) { @@ -561,6 +805,20 @@ void MakeCraftContent( p.setOpacity(shown); p.drawImage(0, 0, getBackdrop(cover.backdrop)); paintPattern(p, cover.pattern, cover.backdrop, 1.); + if (state->coversAnimate) { + const auto edge = cover.backdrop.colors.edgeColor; + if (!edgeColor) { + edgeColor = edge; + } else { + edgeColor = anim::color(*edgeColor, edge, shown); + } + } + } + if (edgeColor) { + state->coverEdgeColor = *edgeColor; + } + if (!animating) { + state->coversAnimate = false; } }); diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp index 8998893022..a25a384152 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.cpp +++ b/Telegram/SourceFiles/export/data/export_data_types.cpp @@ -1848,8 +1848,6 @@ ServiceAction ParseServiceAction( content.offerExpired = data.is_expired(); content.offerPrice = CreditsAmountFromTL(data.vprice()); result.content = content; - }, [&](const MTPDmessageActionStarGiftCraftFail &data) { - AssertIsDebug(); }, [](const MTPDmessageActionEmpty &data) {}); return result; } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 132a70f428..832f771d80 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -6597,13 +6597,6 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { return result; }; - auto prepareStarGiftCraftFail = [&]( - const MTPDmessageActionStarGiftCraftFail &action) { - auto result = PreparedServiceText{}; - result.text.text = u"Failed craft"_q; AssertIsDebug(); - return result; - }; - setServiceText(action.match( prepareChatAddUserText, prepareChatJoinedByLink, @@ -6663,7 +6656,6 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { prepareSuggestBirthday, prepareStarGiftPurchaseOffer, prepareStarGiftPurchaseOfferDeclined, - prepareStarGiftCraftFail, PrepareEmptyText, PrepareErrorText)); @@ -6942,8 +6934,6 @@ void HistoryItem::applyAction(const MTPMessageAction &action) { unique->canTransferAt = data.vcan_transfer_at().value_or_empty(); unique->canResellAt = data.vcan_resell_at().value_or_empty(); unique->canCraftAt = data.vcan_craft_at().value_or_empty(); - unique->craftChancePermille - = data.vcraft_chance_permille().value_or_empty(); } } _media = std::make_unique( diff --git a/Telegram/SourceFiles/history/view/history_view_paid_reaction_toast.cpp b/Telegram/SourceFiles/history/view/history_view_paid_reaction_toast.cpp index adda745bd7..0d1abb053e 100644 --- a/Telegram/SourceFiles/history/view/history_view_paid_reaction_toast.cpp +++ b/Telegram/SourceFiles/history/view/history_view_paid_reaction_toast.cpp @@ -106,7 +106,6 @@ constexpr auto kPremiumToastDuration = 5 * crl::time(1000); (result->height() - st::toastUndoDiameter) / 2, st::toastUndoDiameter, st::toastUndoDiameter); - p.setFont(st::toastUndoFont); state->countdown.paint( p, inner.x() + (inner.width() - state->countdown.countWidth()) / 2, diff --git a/Telegram/SourceFiles/media/view/media_view_playback_sponsored.cpp b/Telegram/SourceFiles/media/view/media_view_playback_sponsored.cpp index b099efb4cd..d5bc2f30e6 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_sponsored.cpp +++ b/Telegram/SourceFiles/media/view/media_view_playback_sponsored.cpp @@ -179,7 +179,6 @@ void Close::paintEvent(QPaintEvent *e) { (height() - st::mediaSponsoredCloseDiameter) / 2, st::mediaSponsoredCloseDiameter, st::mediaSponsoredCloseDiameter); - p.setFont(st::mediaSponsoredCloseFont); _countdown.paint( p, inner.x() + (inner.width() - _countdown.countWidth()) / 2, diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl index 5bc140fd0e..409a97cdcc 100644 --- a/Telegram/SourceFiles/mtproto/scheme/api.tl +++ b/Telegram/SourceFiles/mtproto/scheme/api.tl @@ -188,7 +188,7 @@ messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_am messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; messageActionStarGift#ea2c31d3 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true prepaid_upgrade:flags.13?true upgrade_separate:flags.16?true auction_acquired:flags.17?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long prepaid_upgrade_hash:flags.14?string gift_msg_id:flags.15?int to_id:flags.18?Peer gift_num:flags.19?int = MessageAction; -messageActionStarGiftUnique#6783d55e flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true prepaid_upgrade:flags.11?true assigned:flags.13?true from_offer:flags.14?true craft:flags.16?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int drop_original_details_stars:flags.12?long can_craft_at:flags.15?int craft_chance_permille:flags.15?int = MessageAction; +messageActionStarGiftUnique#e6c31522 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true prepaid_upgrade:flags.11?true assigned:flags.13?true from_offer:flags.14?true craft:flags.16?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int drop_original_details_stars:flags.12?long can_craft_at:flags.15?int = MessageAction; messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; @@ -201,7 +201,6 @@ messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currenc messageActionSuggestBirthday#2c8f2a25 birthday:Birthday = MessageAction; messageActionStarGiftPurchaseOffer#774278d4 flags:# accepted:flags.0?true declined:flags.1?true gift:StarGift price:StarsAmount expires_at:int = MessageAction; messageActionStarGiftPurchaseOfferDeclined#73ada76b flags:# expired:flags.0?true gift:StarGift price:StarsAmount = MessageAction; -messageActionStarGiftCraftFail#4470762c = MessageAction; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; @@ -455,6 +454,7 @@ updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update; updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update; updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update; +updateStarGiftCraftFail#ac072444 = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -1920,7 +1920,7 @@ starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; starGift#313a9547 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true peer_color_available:flags.10?true auction:flags.11?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int locked_until_date:flags.9?int auction_slug:flags.11?string gifts_per_round:flags.11?int auction_start_date:flags.11?int upgrade_variants:flags.12?int background:flags.13?StarGiftBackground = StarGift; -starGiftUnique#569d64c9 flags:# require_premium:flags.6?true resale_ton_only:flags.7?true theme_available:flags.9?true burned:flags.14?true crafted:flags.15?true id:long gift_id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer value_amount:flags.8?long value_currency:flags.8?string value_usd_amount:flags.8?long theme_peer:flags.10?Peer peer_color:flags.11?PeerColor host_id:flags.12?Peer offer_min_stars:flags.13?int = StarGift; +starGiftUnique#85f0a9cd flags:# require_premium:flags.6?true resale_ton_only:flags.7?true theme_available:flags.9?true burned:flags.14?true crafted:flags.15?true id:long gift_id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer value_amount:flags.8?long value_currency:flags.8?string value_usd_amount:flags.8?long theme_peer:flags.10?Peer peer_color:flags.11?PeerColor host_id:flags.12?Peer offer_min_stars:flags.13?int craft_chance_permille:flags.16?int = StarGift; payments.starGiftsNotModified#a388a368 = payments.StarGifts; payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; @@ -1969,7 +1969,7 @@ payments.uniqueStarGift#416c56e8 gift:StarGift chats:Vector users:Vector users:Vector = messages.WebPagePreview; -savedStarGift#389bb419 flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true upgrade_separate:flags.17?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector prepaid_upgrade_hash:flags.16?string drop_original_details_stars:flags.18?long gift_num:flags.19?int can_craft_at:flags.20?int craft_chance_permille:flags.20?int = SavedStarGift; +savedStarGift#41df43fc flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true upgrade_separate:flags.17?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector prepaid_upgrade_hash:flags.16?string drop_original_details_stars:flags.18?long gift_num:flags.19?int can_craft_at:flags.20?int = SavedStarGift; payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.SavedStarGifts; @@ -2118,7 +2118,6 @@ starGiftAttributeRarity#36437737 permille:int = StarGiftAttributeRarity; starGiftAttributeRarityRare#f08d516b = StarGiftAttributeRarity; starGiftAttributeRarityEpic#78fbf3a8 = StarGiftAttributeRarity; starGiftAttributeRarityLegendary#cef7e7a8 = StarGiftAttributeRarity; -starGiftAttributeRarityMythic#f8374495 = StarGiftAttributeRarity; ---functions--- @@ -2747,7 +2746,7 @@ payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password: payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool; payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool; -payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; +payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true for_craft:flags.4?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates; payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector = StarGiftCollection; payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector add_stargift:flags.2?Vector order:flags.3?Vector = StarGiftCollection; diff --git a/Telegram/SourceFiles/ui/effects/credits.style b/Telegram/SourceFiles/ui/effects/credits.style index e143cd3634..d9138a37cf 100644 --- a/Telegram/SourceFiles/ui/effects/credits.style +++ b/Telegram/SourceFiles/ui/effects/credits.style @@ -587,6 +587,11 @@ auctionListRaise: RoundButton(defaultActiveButton) { } auctionListRaisePadding: margins(0px, 8px, 0px, 0px); +CraftRadialPercent { + stroke: pixels; + font: font; +} + craftTitleMargin: margins(64px, 16px, 64px, 4px); craftAbout: FlatLabel(defaultFlatLabel) { align: align(top); @@ -601,4 +606,17 @@ craftAddIcon: icon {{ "settings/plus", windowFgActive }}; craftPreviewPadding: margins(24px, 12px, 18px, 8px); craftForge: icon{{ "chat/filled_forge-48x48", windowFg }}; craftForgePadding: 12px; -craftForgeTextBottom: 12px; +craftForgePercent: CraftRadialPercent { + stroke: 4px; + font: font(14px semibold); +} +craftForgeAttribute: CraftRadialPercent { + stroke: 3px; + font: font(12px semibold); +} +craftPercentLabel: FlatLabel(defaultFlatLabel) { + style: TextStyle(defaultTextStyle) { + font: font(10px semibold); + } + margin: margins(5px, 2px, 5px, 2px); +} diff --git a/Telegram/SourceFiles/ui/effects/premium_bubble.cpp b/Telegram/SourceFiles/ui/effects/premium_bubble.cpp index 4e5a9fe540..91f61bf70d 100644 --- a/Telegram/SourceFiles/ui/effects/premium_bubble.cpp +++ b/Telegram/SourceFiles/ui/effects/premium_bubble.cpp @@ -240,7 +240,6 @@ void Bubble::paintBubble(QPainter &p, const QRect &r, const QBrush &brush) { p.drawPath(bubblePath(r)); } p.setPen(st::activeButtonFg); - p.setFont(_st.font); const auto withSubtext = !_subtext.isEmpty(); const auto height = withSubtext ? (_st.font->height