Added slider for prize quantity to giveaway box.

This commit is contained in:
23rd 2023-10-30 18:44:36 +03:00 committed by John Preston
parent 2dcd8a9640
commit 986d347ea4
5 changed files with 142 additions and 7 deletions

View File

@ -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";

View File

@ -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<rpl::no_value, QString> 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<rpl::no_value, QString> PremiumGiftCodeOptions::request() {
};
}
const std::vector<int> &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<int>(
u"giveaway_boosts_per_premium"_q,
kFallbackCount);
}
} // namespace Api

View File

@ -151,10 +151,13 @@ public:
[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
[[nodiscard]] Data::SubscriptionOptions options(int amount);
[[nodiscard]] const std::vector<int> &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<int> _availablePresets;
base::flat_map<Token, Store> _stores;
MTP::Sender _api;

View File

@ -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<GiveawayType> typeValue;
rpl::variable<int> 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<Ui::SlideWrap<Ui::VerticalLayout>>(
box,
object_ptr<Ui::VerticalLayout>(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<Ui::VerticalLayout>(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<Ui::FlatLabel>(
sliderContainer,
st::giveawayGiftCodeQuantitySubtitle);
rightLabel->show();
const auto floatLabel = Ui::CreateChild<Ui::FlatLabel>(
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<Ui::MediaSlider>(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<Ui::RadiobuttonGroup>(0);
{
const auto listOptions = box->verticalLayout()->add(
object_ptr<Ui::VerticalLayout>(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(

View File

@ -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;