diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 6f61de92d..44576f62f 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4346,6 +4346,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_boosts_list_tab_gifts#one" = "{count} Gifts"; "lng_boosts_list_tab_gifts#other" = "{count} Gifts"; +"lng_boosts_prepaid_giveaway_title" = "Prepaid giveaways"; +"lng_boosts_prepaid_giveaway_single" = "Prepaid giveaway"; +"lng_boosts_prepaid_giveaway_quantity#one" = "{count} Telegram Premium"; +"lng_boosts_prepaid_giveaway_quantity#other" = "{count} Telegram Premium"; +"lng_boosts_prepaid_giveaway_moths#one" = "{count}-month subscriptions"; +"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}"; + // Wnd specific "lng_wnd_choose_program_menu" = "Choose Default Program..."; diff --git a/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp b/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp index ac22dc934..cd833d1e2 100644 --- a/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp +++ b/Telegram/SourceFiles/info/boosts/create_giveaway_box.cpp @@ -230,7 +230,8 @@ void CreateGiveawayBox( not_null box, not_null controller, not_null peer, - Fn reloadOnDone) { + Fn reloadOnDone, + std::optional prepaid) { box->setWidth(st::boxWideWidth); const auto weakWindow = base::make_weak(controller->parentController()); @@ -298,7 +299,23 @@ void CreateGiveawayBox( object_ptr(box))); contentWrap->toggle(false, anim::type::instant); - { + if (prepaid) { + contentWrap->entity()->add( + object_ptr( + box, + GiveawayType::Prepaid, + 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( + lt_count, + rpl::single(prepaid->months) | tr::to_count()))) + )->setAttribute(Qt::WA_TransparentForMouseEvents); + } + if (!prepaid) { const auto row = contentWrap->entity()->add( object_ptr( box, @@ -309,7 +326,7 @@ void CreateGiveawayBox( state->typeValue.force_assign(GiveawayType::Random); }); } - { + if (!prepaid) { const auto row = contentWrap->entity()->add( object_ptr( box, @@ -387,6 +404,10 @@ void CreateGiveawayBox( object_ptr(randomWrap)); const auto fillSliderContainer = [=] { const auto availablePresets = state->apiOptions.availablePresets(); + if (prepaid) { + state->sliderValue = prepaid->quantity; + return; + } if (availablePresets.empty()) { return; } @@ -675,6 +696,9 @@ void CreateGiveawayBox( const auto listOptions = contentWrap->entity()->add( object_ptr(box)); const auto rebuildListOptions = [=](int amountUsers) { + if (prepaid) { + return; + } while (listOptions->count()) { delete listOptions->widgetAt(0); } @@ -714,8 +738,7 @@ void CreateGiveawayBox( box->verticalLayout()->resizeToWidth(box->width()); }; - { - + if (!prepaid) { rpl::combine( state->sliderValue.value(), state->typeValue.value() @@ -725,6 +748,8 @@ void CreateGiveawayBox( ? state->selectedToAward.size() : users); }, box->lifetime()); + } else { + typeGroup->setValue(GiveawayType::Random); } { using namespace Info::Statistics; @@ -783,7 +808,10 @@ void CreateGiveawayBox( isSpecific ? state->selectedToAward.size() : state->sliderValue.current(), - durationGroup->value()); + prepaid + ? prepaid->months + : state->apiOptions.monthsFromPreset( + durationGroup->value())); if (isSpecific) { if (state->selectedToAward.empty()) { return; @@ -855,7 +883,21 @@ void CreateGiveawayBox( state->confirmButtonBusy = false; } }; - Payments::CheckoutProcess::Start(std::move(invoice), done); + if (prepaid) { + state->apiOptions.applyPrepaid( + invoice, + prepaid->id + ) | rpl::start_with_error_done([=](const QString &error) { + if (const auto window = weakWindow.get()) { + window->uiShow()->showToast(error); + done(Payments::CheckoutResult::Cancelled); + } + }, [=] { + done(Payments::CheckoutResult::Paid); + }, box->lifetime()); + } else { + Payments::CheckoutProcess::Start(std::move(invoice), done); + } }); box->addButton(std::move(button)); } @@ -867,9 +909,7 @@ void CreateGiveawayBox( if (!loading->toggled()) { return; } - state->lifetimeApi = state->apiOptions.request( - ) | rpl::start_with_error_done([=](const QString &error) { - }, [=] { + const auto done = [=] { state->lifetimeApi.destroy(); loading->toggle(false, anim::type::instant); state->confirmButtonBusy = false; @@ -877,6 +917,14 @@ void CreateGiveawayBox( rebuildListOptions(1); contentWrap->toggle(true, anim::type::instant); contentWrap->resizeToWidth(box->width()); - }); + }; + if (prepaid) { + return done(); + } + state->lifetimeApi = state->apiOptions.request( + ) | rpl::start_with_error_done([=](const QString &error) { + box->uiShow()->showToast(error); + box->closeBox(); + }, done); }, box->lifetime()); } diff --git a/Telegram/SourceFiles/info/boosts/create_giveaway_box.h b/Telegram/SourceFiles/info/boosts/create_giveaway_box.h index d31383dc7..d1fb6736f 100644 --- a/Telegram/SourceFiles/info/boosts/create_giveaway_box.h +++ b/Telegram/SourceFiles/info/boosts/create_giveaway_box.h @@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class PeerData; +namespace Data { +struct BoostPrepaidGiveaway; +} // namespace Data + namespace Info { class Controller; } // namespace Info @@ -21,4 +25,5 @@ void CreateGiveawayBox( not_null box, not_null controller, not_null peer, - Fn reloadOnDone); + Fn reloadOnDone, + std::optional prepaidGiveaway); diff --git a/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.cpp b/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.cpp index db1fedb08..e54ba3540 100644 --- a/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.cpp +++ b/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/checkbox.h" #include "styles/style_boxes.h" #include "styles/style_giveaway.h" +#include "styles/style_statistics.h" namespace Giveaway { @@ -24,31 +25,46 @@ GiveawayTypeRow::GiveawayTypeRow( not_null parent, Type type, rpl::producer subtitle) +: GiveawayTypeRow( + parent, + type, + (type == Type::SpecificUsers) ? kColorIndexSpecific : kColorIndexRandom, + (type == Type::SpecificUsers) + ? tr::lng_giveaway_award_option() + : (type == Type::Random) + ? tr::lng_giveaway_create_option() + : (type == Type::AllMembers) + ? tr::lng_giveaway_users_all() + : tr::lng_giveaway_users_new(), + std::move(subtitle)) { +} + +GiveawayTypeRow::GiveawayTypeRow( + not_null parent, + Type type, + int colorIndex, + rpl::producer title, + rpl::producer subtitle) : RippleButton(parent, st::defaultRippleAnimation) , _type(type) , _st((_type == Type::SpecificUsers || _type == Type::Random) ? st::giveawayTypeListItem + : (_type == Type::Prepaid) + ? st::boostsListBox.item : st::giveawayGiftCodeMembersPeerList.item) , _userpic( - Ui::EmptyUserpic::UserpicColor((_type == Type::SpecificUsers) - ? kColorIndexSpecific - : kColorIndexRandom), - QString()) -, _name( - _st.nameStyle, - (type == Type::SpecificUsers) - ? tr::lng_giveaway_award_option(tr::now) - : (type == Type::Random) - ? tr::lng_giveaway_create_option(tr::now) - : (type == Type::AllMembers) - ? tr::lng_giveaway_users_all(tr::now) - : tr::lng_giveaway_users_new(tr::now), - Ui::NameTextOptions()) { + Ui::EmptyUserpic::UserpicColor(Ui::EmptyUserpic::ColorIndex(colorIndex)), + QString()) { std::move( subtitle ) | rpl::start_with_next([=] (const QString &s) { _status.setText(st::defaultTextStyle, s, Ui::NameTextOptions()); }, lifetime()); + std::move( + title + ) | rpl::start_with_next([=] (const QString &s) { + _name.setText(_st.nameStyle, s, Ui::NameTextOptions()); + }, lifetime()); } int GiveawayTypeRow::resizeGetHeight(int) { @@ -62,7 +78,10 @@ void GiveawayTypeRow::paintEvent(QPaintEvent *e) { const auto skipRight = _st.photoPosition.x(); const auto outerWidth = width(); const auto isSpecific = (_type == Type::SpecificUsers); - const auto hasUserpic = (_type == Type::Random) || isSpecific; + const auto isPrepaid = (_type == Type::Prepaid); + const auto hasUserpic = (_type == Type::Random) + || isSpecific + || isPrepaid; if (paintOver) { p.fillRect(e->rect(), _st.button.textBgOver); diff --git a/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.h b/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.h index 0167b338e..67b1e92ad 100644 --- a/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.h +++ b/Telegram/SourceFiles/info/boosts/giveaway/giveaway_type_row.h @@ -25,6 +25,8 @@ public: AllMembers, OnlyNewMembers, + + Prepaid, }; GiveawayTypeRow( @@ -32,6 +34,13 @@ public: Type type, rpl::producer subtitle); + GiveawayTypeRow( + not_null parent, + Type type, + int colorIndex, + rpl::producer title, + rpl::producer subtitle); + void addRadio(std::shared_ptr> typeGroup); protected: diff --git a/Telegram/SourceFiles/info/boosts/info_boosts_inner_widget.cpp b/Telegram/SourceFiles/info/boosts/info_boosts_inner_widget.cpp index 2cfebee08..3badce3bc 100644 --- a/Telegram/SourceFiles/info/boosts/info_boosts_inner_widget.cpp +++ b/Telegram/SourceFiles/info/boosts/info_boosts_inner_widget.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_user.h" #include "info/boosts/create_giveaway_box.h" +#include "info/boosts/giveaway/giveaway_type_row.h" #include "info/boosts/info_boosts_widget.h" #include "info/info_controller.h" #include "info/profile/info_profile_icon.h" @@ -25,11 +26,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "statistics/widgets/chart_header_widget.h" #include "ui/boxes/boost_box.h" #include "ui/controls/invite_link_label.h" +#include "ui/effects/ripple_animation.h" +#include "ui/empty_userpic.h" +#include "ui/painter.h" #include "ui/rect.h" #include "ui/widgets/buttons.h" #include "ui/widgets/discrete_sliders.h" #include "ui/widgets/labels.h" #include "ui/wrap/slide_wrap.h" +#include "styles/style_giveaway.h" #include "styles/style_info.h" #include "styles/style_statistics.h" @@ -230,7 +235,12 @@ void FillGetBoostsButton( tr::lng_boosts_get_boosts(), st)); button->setClickedCallback([=] { - show->showBox(Box(CreateGiveawayBox, controller, peer, reloadOnDone)); + show->showBox(Box( + CreateGiveawayBox, + controller, + peer, + reloadOnDone, + std::nullopt)); }); Ui::CreateChild( button, @@ -280,6 +290,13 @@ void InnerWidget::fill() { const auto &status = _state; const auto inner = this; + const auto reloadOnDone = crl::guard(this, [=] { + while (Ui::VerticalLayout::count()) { + delete Ui::VerticalLayout::widgetAt(0); + } + load(); + }); + { auto dividerContent = object_ptr(inner); Ui::FillBoostLimit( @@ -308,6 +325,37 @@ void InnerWidget::fill() { ::Settings::AddDivider(inner); ::Settings::AddSkip(inner); + if (!status.prepaidGiveaway.empty()) { + ::Settings::AddSkip(inner); + AddHeader(inner, tr::lng_boosts_prepaid_giveaway_title); + ::Settings::AddSkip(inner); + for (const auto &g : status.prepaidGiveaway) { + 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()))); + button->setClickedCallback([=] { + _controller->uiShow()->showBox(Box( + CreateGiveawayBox, + _controller, + _peer, + reloadOnDone, + g)); + }); + } + + ::Settings::AddSkip(inner); + ::Settings::AddDivider(inner); + ::Settings::AddSkip(inner); + } + const auto hasBoosts = (status.firstSliceBoosts.multipliedTotal > 0); const auto hasGifts = (status.firstSliceGifts.multipliedTotal > 0); if (hasBoosts || hasGifts) { @@ -429,12 +477,6 @@ void InnerWidget::fill() { ::Settings::AddSkip(inner); ::Settings::AddDividerText(inner, tr::lng_boosts_link_subtext()); - const auto reloadOnDone = crl::guard(this, [=] { - while (Ui::VerticalLayout::count()) { - delete Ui::VerticalLayout::widgetAt(0); - } - load(); - }); FillGetBoostsButton(inner, _controller, _show, _peer, reloadOnDone); resizeToWidth(width());