diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 30e93f09c..df5a3d6c0 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -5370,6 +5370,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_boosts_prepaid_giveaway_moths#other" = "{count}-month subscriptions"; "lng_boosts_prepaid_giveaway_status#one" = "{count} subscription {duration}"; "lng_boosts_prepaid_giveaway_status#other" = "{count} subscriptions {duration}"; +"lng_boosts_prepaid_giveaway_credits_status#one" = "{amount} among {count} winner."; +"lng_boosts_prepaid_giveaway_credits_status#other" = "{amount} among {count} winners."; "lng_channel_earn_title" = "Monetization"; "lng_channel_earn_about" = "Telegram shares 50% of the revenue from ads displayed in your channel. {link}"; diff --git a/Telegram/SourceFiles/api/api_premium.cpp b/Telegram/SourceFiles/api/api_premium.cpp index d7a29bc8c..c13565bae 100644 --- a/Telegram/SourceFiles/api/api_premium.cpp +++ b/Telegram/SourceFiles/api/api_premium.cpp @@ -508,7 +508,9 @@ rpl::producer PremiumGiftCodeOptions::applyPrepaid( _api.request(MTPpayments_LaunchPrepaidGiveaway( _peer->input, MTP_long(prepaidId), - Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice) + invoice.creditsAmount + ? Payments::InvoiceCreditsGiveawayToTL(invoice) + : Payments::InvoicePremiumGiftCodeGiveawayToTL(invoice) )).done([=](const MTPUpdates &result) { _peer->session().api().applyUpdates(result); consumer.put_done(); diff --git a/Telegram/SourceFiles/api/api_statistics.cpp b/Telegram/SourceFiles/api/api_statistics.cpp index 23bf96e70..c960aca33 100644 --- a/Telegram/SourceFiles/api/api_statistics.cpp +++ b/Telegram/SourceFiles/api/api_statistics.cpp @@ -573,13 +573,19 @@ rpl::producer Boosts::request() { ) | ranges::views::transform([](const MTPPrepaidGiveaway &r) { return r.match([&](const MTPDprepaidGiveaway &data) { return Data::BoostPrepaidGiveaway{ - .months = data.vmonths().v, - .id = data.vid().v, - .quantity = data.vquantity().v, .date = base::unixtime::parse(data.vdate().v), + .id = data.vid().v, + .months = data.vmonths().v, + .quantity = data.vquantity().v, }; }, [&](const MTPDprepaidStarsGiveaway &data) { - return Data::BoostPrepaidGiveaway(AssertIsDebug()); + return Data::BoostPrepaidGiveaway{ + .date = base::unixtime::parse(data.vdate().v), + .id = data.vid().v, + .credits = data.vstars().v, + .quantity = data.vquantity().v, + .boosts = data.vboosts().v, + }; }); }) | ranges::to_vector; } diff --git a/Telegram/SourceFiles/data/data_boosts.h b/Telegram/SourceFiles/data/data_boosts.h index 31d77652b..22d5c77de 100644 --- a/Telegram/SourceFiles/data/data_boosts.h +++ b/Telegram/SourceFiles/data/data_boosts.h @@ -54,10 +54,12 @@ struct BoostsListSlice final { }; struct BoostPrepaidGiveaway final { - int months = 0; - uint64 id = 0; - int quantity = 0; QDateTime date; + uint64 id = 0; + uint64 credits = 0; + int months = 0; + int quantity = 0; + int boosts = 0; }; struct BoostStatus final { diff --git a/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp b/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp index 17cecb812..7f46d01df 100644 --- a/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp @@ -59,6 +59,7 @@ namespace { constexpr auto kDoneTooltipDuration = 5 * crl::time(1000); constexpr auto kAdditionalPrizeLengthMax = 128; +constexpr auto kColorIndexCredits = int(1); [[nodiscard]] QDateTime ThreeDaysAfterToday() { auto dateNow = QDateTime::currentDateTime(); @@ -299,6 +300,8 @@ void CreateGiveawayBox( const auto typeGroup = std::make_shared(); const auto creditsGroup = std::make_shared(); + const auto isPrepaidCredits = (prepaid && prepaid->credits); + const auto isSpecificUsers = [=] { return !state->selectedToAward.empty(); }; @@ -355,16 +358,26 @@ void CreateGiveawayBox( contentWrap->entity()->add( object_ptr( box, - GiveawayType::Prepaid, - prepaid->id, + prepaid->credits + ? GiveawayType::PrepaidCredits + : GiveawayType::Prepaid, + prepaid->credits ? kColorIndexCredits : prepaid->id, tr::lng_boosts_prepaid_giveaway_single(), - tr::lng_boosts_prepaid_giveaway_status( - lt_count, - rpl::single(prepaid->quantity) | tr::to_count(), - lt_duration, - tr::lng_premium_gift_duration_months( + prepaid->credits + ? tr::lng_boosts_prepaid_giveaway_credits_status( lt_count, - rpl::single(prepaid->months) | tr::to_count())), + rpl::single(prepaid->quantity) | tr::to_count(), + lt_amount, + tr::lng_prize_credits_amount( + lt_count_decimal, + rpl::single(prepaid->credits) | tr::to_count())) + : tr::lng_boosts_prepaid_giveaway_status( + lt_count, + rpl::single(prepaid->quantity) | tr::to_count(), + lt_duration, + tr::lng_premium_gift_duration_months( + lt_count, + rpl::single(prepaid->months) | tr::to_count())), QImage()) )->setAttribute(Qt::WA_TransparentForMouseEvents); } @@ -454,7 +467,6 @@ void CreateGiveawayBox( if (state->apiCreditsOptions.options().empty()) { return; } - constexpr auto kColorIndexCredits = int(1); static constexpr auto kOutdated = 1735689600; auto badge = [&] { @@ -895,7 +907,9 @@ void CreateGiveawayBox( lt_count, state->sliderValue.value( ) | rpl::map([=](int v) -> float64 { - return state->apiOptions.giveawayBoostsPerPremium() * v; + return (prepaid && prepaid->boosts) + ? prepaid->boosts + : (state->apiOptions.giveawayBoostsPerPremium() * v); }))); using IconType = Settings::IconType; @@ -1355,21 +1369,23 @@ void CreateGiveawayBox( hideSpecificUsersOn(), tr::lng_giveaway_start(), tr::lng_giveaway_award()), - rpl::conditional( - state->typeValue.value( - ) | rpl::map(rpl::mappers::_1 == GiveawayType::Credits), - creditsGroup->value() | rpl::map([=](int v) { - return creditsOption(v).yearlyBoosts; - }), - rpl::combine( - state->sliderValue.value(), - hideSpecificUsersOn() - ) | rpl::map([=](int v, bool random) -> int { - const auto c = random - ? v - : int(state->selectedToAward.size()); - return state->apiOptions.giveawayBoostsPerPremium() * c; - })), + (prepaid && prepaid->boosts) + ? rpl::single(prepaid->boosts) + : rpl::conditional( + state->typeValue.value( + ) | rpl::map(rpl::mappers::_1 == GiveawayType::Credits), + creditsGroup->value() | rpl::map([=](int v) { + return creditsOption(v).yearlyBoosts; + }), + rpl::combine( + state->sliderValue.value(), + hideSpecificUsersOn() + ) | rpl::map([=](int value, bool random) -> int { + return state->apiOptions.giveawayBoostsPerPremium() + * (random + ? value + : int(state->selectedToAward.size())); + })), state->confirmButtonBusy.value() | rpl::map(!rpl::mappers::_1)); { @@ -1399,7 +1415,13 @@ void CreateGiveawayBox( return; } auto invoice = [&] { - if (isCredits) { + if (isPrepaidCredits) { + return Payments::InvoicePremiumGiftCode{ + .creditsAmount = prepaid->credits, + .randomId = prepaid->id, + .users = prepaid->quantity, + }; + } else if (isCredits) { const auto option = creditsOption( creditsGroup->current()); return Payments::InvoicePremiumGiftCode{ @@ -1433,7 +1455,7 @@ void CreateGiveawayBox( }) | ranges::to_vector, peer->asChannel(), }; - } else if (isRandom || isCredits) { + } else if (isRandom || isCredits || isPrepaidCredits) { invoice.purpose = Payments::InvoicePremiumGiftCodeGiveaway{ .boostPeer = peer->asChannel(), .additionalChannels = ranges::views::all( diff --git a/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway_type_row.cpp b/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway_type_row.cpp index 0bcf303ed..b97184dba 100644 --- a/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway_type_row.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway_type_row.cpp @@ -62,14 +62,14 @@ GiveawayTypeRow::GiveawayTypeRow( || _type == Type::Random || _type == Type::Credits) ? st::giveawayTypeListItem - : (_type == Type::Prepaid) + : ((_type == Type::Prepaid) || (_type == Type::PrepaidCredits)) ? st::boostsListBox.item : st::giveawayGiftCodeMembersPeerList.item) , _userpic( Ui::EmptyUserpic::UserpicColor(Ui::EmptyUserpic::ColorIndex(colorIndex)), QString()) , _badge(std::move(badge)) { - if (_type == Type::Credits) { + if (_type == Type::Credits || _type == Type::PrepaidCredits) { _customUserpic = Ui::CreditsWhiteDoubledIcon(_st.photoSize, 1.); } std::move( diff --git a/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway_type_row.h b/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway_type_row.h index 3b8efbdd6..ee53a4076 100644 --- a/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway_type_row.h +++ b/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway_type_row.h @@ -27,6 +27,7 @@ public: OnlyNewMembers, Prepaid, + PrepaidCredits, Credits, }; diff --git a/Telegram/SourceFiles/info/channel_statistics/boosts/info_boosts_inner_widget.cpp b/Telegram/SourceFiles/info/channel_statistics/boosts/info_boosts_inner_widget.cpp index bb8ab3f61..f25a28ef6 100644 --- a/Telegram/SourceFiles/info/channel_statistics/boosts/info_boosts_inner_widget.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/boosts/info_boosts_inner_widget.cpp @@ -253,9 +253,11 @@ void FillGetBoostsButton( (st.height + rect::m::sum::v(st.padding) - icon.height()) / 2, })->show(); Ui::AddSkip(content); - Ui::AddDividerText(content, peer->isMegagroup() - ? tr::lng_boosts_get_boosts_subtext_group() - : tr::lng_boosts_get_boosts_subtext()); + Ui::AddDividerText( + content, + peer->isMegagroup() + ? tr::lng_boosts_get_boosts_subtext_group() + : tr::lng_boosts_get_boosts_subtext()); } } // namespace @@ -334,6 +336,7 @@ void InnerWidget::fill() { Ui::AddSkip(inner); if (!status.prepaidGiveaway.empty()) { + constexpr auto kColorIndexCredits = int(1); const auto multiplier = Api::PremiumGiftCodeOptions(_peer) .giveawayBoostsPerPremium(); Ui::AddSkip(inner); @@ -343,17 +346,30 @@ void InnerWidget::fill() { using namespace Giveaway; const auto button = inner->add(object_ptr( inner, - GiveawayTypeRow::Type::Prepaid, - g.id, - tr::lng_boosts_prepaid_giveaway_quantity( - lt_count, - rpl::single(g.quantity) | tr::to_count()), - tr::lng_boosts_prepaid_giveaway_moths( - lt_count, - rpl::single(g.months) | tr::to_count()), + g.credits + ? GiveawayTypeRow::Type::PrepaidCredits + : GiveawayTypeRow::Type::Prepaid, + g.credits ? kColorIndexCredits : g.id, + g.credits + ? tr::lng_boosts_prepaid_giveaway_single() + : tr::lng_boosts_prepaid_giveaway_quantity( + lt_count, + rpl::single(g.quantity) | tr::to_count()), + g.credits + ? tr::lng_boosts_prepaid_giveaway_credits_status( + lt_count, + rpl::single(g.quantity) | tr::to_count(), + lt_amount, + tr::lng_prize_credits_amount( + lt_count_decimal, + rpl::single(g.credits) | tr::to_count())) + : tr::lng_boosts_prepaid_giveaway_moths( + lt_count, + rpl::single(g.months) | tr::to_count()), Info::Statistics::CreateBadge( st::statisticsDetailsBottomCaptionStyle, - QString::number(g.quantity * multiplier), + QString::number( + g.boosts ? g.boosts : (g.quantity * multiplier)), st::boostsListBadgeHeight, st::boostsListBadgeTextPadding, st::premiumButtonBg2, diff --git a/Telegram/SourceFiles/payments/payments_form.h b/Telegram/SourceFiles/payments/payments_form.h index 11265a61b..6b31f4108 100644 --- a/Telegram/SourceFiles/payments/payments_form.h +++ b/Telegram/SourceFiles/payments/payments_form.h @@ -269,6 +269,8 @@ struct FormUpdate : std::variant< [[nodiscard]] MTPinputStorePaymentPurpose InvoicePremiumGiftCodeGiveawayToTL( const InvoicePremiumGiftCode &invoice); +[[nodiscard]] MTPinputStorePaymentPurpose InvoiceCreditsGiveawayToTL( + const InvoicePremiumGiftCode &invoice); class Form final : public base::has_weak_ptr { public: