diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 75e3d31ca..9a0a409a0 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2078,9 +2078,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_giveaway_award_subtitle" = "Select recipients >"; "lng_giveaway_award_chosen#one" = "{count} recipient >"; "lng_giveaway_award_chosen#other" = "{count} recipients >"; -"lng_giveaway_quantity_title" = "Quantity of prizes / boosts"; -"lng_giveaway_quantity#one" = "{count} Subscription / Boost"; -"lng_giveaway_quantity#other" = "{count} Subscriptions / Boosts"; +"lng_giveaway_quantity_title" = "Quantity of prizes"; +"lng_giveaway_quantity#one" = "{count} boost"; +"lng_giveaway_quantity#other" = "{count} boosts"; "lng_giveaway_quantity_about" = "Choose how many Premium subscriptions to give away and boosts to receive."; "lng_giveaway_channels_title" = "Channels included in the giveaway"; "lng_giveaway_channels_this#one" = "this channel will receive {count} boost"; diff --git a/Telegram/SourceFiles/api/api_premium.cpp b/Telegram/SourceFiles/api/api_premium.cpp index 4ca994a7d..ba63898c6 100644 --- a/Telegram/SourceFiles/api/api_premium.cpp +++ b/Telegram/SourceFiles/api/api_premium.cpp @@ -15,6 +15,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_peer.h" #include "data/data_peer_values.h" #include "data/data_session.h" +#include "main/main_account.h" +#include "main/main_app_config.h" #include "main/main_session.h" #include "payments/payments_form.h" #include "ui/text/format_values.h" @@ -362,6 +364,9 @@ rpl::producer PremiumGiftCodeOptions::request() { .product = qs(data.vstore_product().value_or_empty()), .quantity = data.vstore_quantity().value_or_empty(), }; + if (!ranges::contains(_availablePresets, data.vusers().v)) { + _availablePresets.push_back(data.vusers().v); + } } for (const auto &[amount, tlOptions] : tlMapOptions) { if (amount == 1 && _optionsForOnePerson.currency.isEmpty()) { @@ -385,6 +390,10 @@ rpl::producer PremiumGiftCodeOptions::request() { }; } +const std::vector &PremiumGiftCodeOptions::availablePresets() const { + return _availablePresets; +} + Payments::InvoicePremiumGiftCode PremiumGiftCodeOptions::invoice( int users, int monthsIndex) { @@ -426,4 +435,11 @@ Data::SubscriptionOptions PremiumGiftCodeOptions::options(int amount) { } } +[[nodiscard]] int PremiumGiftCodeOptions::giveawayBoostsPerPremium() const { + constexpr auto kFallbackCount = 4; + return _peer->session().account().appConfig().get( + u"giveaway_boosts_per_premium"_q, + kFallbackCount); +} + } // namespace Api diff --git a/Telegram/SourceFiles/api/api_premium.h b/Telegram/SourceFiles/api/api_premium.h index 5a2205725..d6141cac0 100644 --- a/Telegram/SourceFiles/api/api_premium.h +++ b/Telegram/SourceFiles/api/api_premium.h @@ -151,10 +151,13 @@ public: [[nodiscard]] rpl::producer request(); [[nodiscard]] Data::SubscriptionOptions options(int amount); + [[nodiscard]] const std::vector &availablePresets() const; [[nodiscard]] Payments::InvoicePremiumGiftCode invoice( int users, int monthsIndex); + [[nodiscard]] int giveawayBoostsPerPremium() const; + private: struct Token final { int users = 0; @@ -177,6 +180,8 @@ private: QString currency; } _optionsForOnePerson; + std::vector _availablePresets; + base::flat_map _stores; MTP::Sender _api; diff --git a/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp b/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp index 739bb5a28..ca0b7f36c 100644 --- a/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp +++ b/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp @@ -23,7 +23,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/layers/generic_box.h" #include "ui/text/text_utilities.h" #include "ui/widgets/checkbox.h" +#include "ui/widgets/continuous_sliders.h" #include "ui/widgets/labels.h" +#include "ui/wrap/slide_wrap.h" #include "styles/style_layers.h" #include "styles/style_premium.h" #include "styles/style_settings.h" @@ -81,6 +83,7 @@ void CreateGiveawayBox( rpl::event_stream<> toAwardAmountChanged; rpl::variable typeValue; + rpl::variable sliderValue; bool confirmButtonBusy = false; }; @@ -153,11 +156,104 @@ void CreateGiveawayBox( Settings::AddDivider(box->verticalLayout()); Settings::AddSkip(box->verticalLayout()); + const auto randomWrap = box->verticalLayout()->add( + object_ptr>( + box, + object_ptr(box))); + state->typeValue.value( + ) | rpl::start_with_next([=](GiveawayType type) { + randomWrap->toggle(type == GiveawayType::Random, anim::type::instant); + }, randomWrap->lifetime()); + + const auto sliderContainer = randomWrap->entity()->add( + object_ptr(randomWrap)); + const auto fillSliderContainer = [=] { + if (sliderContainer->count()) { + return; + } + const auto availablePresets = state->apiOptions.availablePresets(); + if (availablePresets.empty()) { + return; + } + state->sliderValue = availablePresets.front(); + const auto title = Settings::AddSubsectionTitle( + sliderContainer, + tr::lng_giveaway_quantity_title()); + const auto rightLabel = Ui::CreateChild( + sliderContainer, + st::giveawayGiftCodeQuantitySubtitle); + rightLabel->show(); + + const auto floatLabel = Ui::CreateChild( + sliderContainer, + st::giveawayGiftCodeQuantityFloat); + floatLabel->show(); + + rpl::combine( + tr::lng_giveaway_quantity( + lt_count, + state->sliderValue.value( + ) | rpl::map([=](int v) -> float64 { + return state->apiOptions.giveawayBoostsPerPremium() * v; + })), + title->positionValue(), + sliderContainer->geometryValue() + ) | rpl::start_with_next([=](QString s, const QPoint &p, QRect) { + rightLabel->setText(std::move(s)); + rightLabel->moveToRight(st::boxRowPadding.right(), p.y()); + }, rightLabel->lifetime()); + + Settings::AddSkip(sliderContainer); + Settings::AddSkip(sliderContainer); + const auto slider = sliderContainer->add( + object_ptr(sliderContainer, st::settingsScale), + st::boxRowPadding); + Settings::AddSkip(sliderContainer); + slider->resize(slider->width(), st::settingsScale.seekSize.height()); + slider->setPseudoDiscrete( + availablePresets.size(), + [=](int index) { return availablePresets[index]; }, + availablePresets.front(), + [=](int boosts) { state->sliderValue = boosts; }, + [](int) {}); + + state->sliderValue.value( + ) | rpl::start_with_next([=](int boosts) { + floatLabel->setText(QString::number(boosts)); + + const auto count = availablePresets.size(); + const auto sliderWidth = slider->width() + - st::settingsScale.seekSize.width(); + for (auto i = 0; i < count; i++) { + if ((i + 1 == count || availablePresets[i + 1] > boosts) + && availablePresets[i] <= boosts) { + const auto x = (sliderWidth * i) / (count - 1); + floatLabel->moveToLeft( + slider->x() + + x + + st::settingsScale.seekSize.width() / 2 + - floatLabel->width() / 2, + slider->y() - floatLabel->height()); + break; + } + } + }, floatLabel->lifetime()); + + Settings::AddSkip(sliderContainer); + Settings::AddDividerText( + sliderContainer, + tr::lng_giveaway_quantity_about()); + Settings::AddSkip(sliderContainer); + + sliderContainer->resizeToWidth(box->width()); + }; + const auto durationGroup = std::make_shared(0); { const auto listOptions = box->verticalLayout()->add( object_ptr(box)); const auto rebuildListOptions = [=](int amountUsers) { + fillSliderContainer(); while (listOptions->count()) { delete listOptions->widgetAt(0); } @@ -192,16 +288,18 @@ void CreateGiveawayBox( std::move(terms), st::settingsDividerLabelPadding)); - listOptions->resizeToWidth(box->width()); + box->verticalLayout()->resizeToWidth(box->width()); }; - state->typeValue.value( - ) | rpl::start_with_next([=](GiveawayType type) { + rpl::combine( + state->sliderValue.value(), + state->typeValue.value() + ) | rpl::start_with_next([=](int users, GiveawayType type) { typeGroup->setValue(type); const auto rebuild = [=] { rebuildListOptions((type == GiveawayType::SpecificUsers) ? state->selectedToAward.size() - : 1); + : users); }; if (!listOptions->count()) { state->lifetimeApi = state->apiOptions.request( diff --git a/Telegram/SourceFiles/ui/effects/premium.style b/Telegram/SourceFiles/ui/effects/premium.style index 6d1ae3772..522661517 100644 --- a/Telegram/SourceFiles/ui/effects/premium.style +++ b/Telegram/SourceFiles/ui/effects/premium.style @@ -296,6 +296,22 @@ giveawayGiftCodeStartButton: RoundButton(defaultActiveButton) { textTop: 12px; radius: 6px; } +giveawayGiftCodeQuantitySubtitle: FlatLabel(defaultFlatLabel) { + style: TextStyle(semiboldTextStyle) { + font: font(boxFontSize semibold); + } + textFg: windowActiveTextFg; + minWidth: 240px; + align: align(right); +} +giveawayGiftCodeQuantityFloat: FlatLabel(defaultFlatLabel) { + style: TextStyle(semiboldTextStyle) { + font: font(13px); + } + textFg: windowActiveTextFg; + minWidth: 50px; + align: align(center); +} boostLinkStatsButton: IconButton(defaultIconButton) { width: giveawayGiftCodeLinkCopyWidth;