Added ability to choose subscription option for Premium in Settings.

This commit is contained in:
23rd 2022-08-25 20:30:10 +03:00 committed by John Preston
parent 6f3d19914d
commit 149d92d224
8 changed files with 232 additions and 57 deletions

View file

@ -1702,6 +1702,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_premium_unlock_stickers" = "Unlock Premium Stickers"; "lng_premium_unlock_stickers" = "Unlock Premium Stickers";
"lng_premium_unlock_emoji" = "Unlock Animated Emoji"; "lng_premium_unlock_emoji" = "Unlock Animated Emoji";
"lng_premium_subscribe_months_12" = "Annual";
"lng_premium_subscribe_months_6" = "Semiannual";
"lng_premium_subscribe_months_1" = "Monthly";
"lng_premium_subscribe_total" = "{cost} per year";
"lng_premium_subscribe_button" = "Subscribe for {cost} per month";
"lng_premium_emoji_status_title" = "{user} set this emoji from {link} as their current status."; "lng_premium_emoji_status_title" = "{user} set this emoji from {link} as their current status.";
"lng_premium_emoji_status_about" = "Emoji status is a premium feature. Other features included in **Telegram Premium**:"; "lng_premium_emoji_status_about" = "Emoji status is a premium feature. Other features included in **Telegram Premium**:";
"lng_premium_emoji_status_button" = "Unlock Emoji Status"; "lng_premium_emoji_status_button" = "Unlock Emoji Status";

View file

@ -10,8 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h" #include "apiwrap.h"
#include "api/api_premium_option.h" #include "api/api_premium_option.h"
#include "base/weak_ptr.h" #include "base/weak_ptr.h"
#include "core/click_handler_types.h" // ClickHandlerContext.
#include "core/local_url_handlers.h" // TryConvertUrlToLocal.
#include "data/data_changes.h" #include "data/data_changes.h"
#include "data/data_peer_values.h" // Data::PeerPremiumValue. #include "data/data_peer_values.h" // Data::PeerPremiumValue.
#include "data/data_session.h" #include "data/data_session.h"
@ -167,7 +165,11 @@ void GiftBox(
options[value].total); options[value].total);
state->buttonText.fire(std::move(text)); state->buttonText.fire(std::move(text));
}); });
Ui::Premium::AddGiftOptions(buttonsParent, group, options); Ui::Premium::AddGiftOptions(
buttonsParent,
group,
options,
st::premiumGiftOption);
// Footer. // Footer.
auto terms = object_ptr<Ui::FlatLabel>( auto terms = object_ptr<Ui::FlatLabel>(
@ -198,26 +200,17 @@ void GiftBox(
[] { return QString("gift"); }, [] { return QString("gift"); },
state->buttonText.events(), state->buttonText.events(),
Ui::Premium::GiftGradientStops(), Ui::Premium::GiftGradientStops(),
[=] {
const auto value = group->value();
return (value < options.size() && value >= 0)
? options[value].botUrl
: QString();
},
}); });
auto button = object_ptr<Ui::GradientButton>::fromRaw(raw); auto button = object_ptr<Ui::GradientButton>::fromRaw(raw);
button->resizeToWidth(boxWidth button->resizeToWidth(boxWidth
- stButton.buttonPadding.left() - stButton.buttonPadding.left()
- stButton.buttonPadding.right()); - stButton.buttonPadding.right());
button->setClickedCallback([=] {
const auto value = group->value();
Assert(value < options.size() && value >= 0);
const auto local = Core::TryConvertUrlToLocal(options[value].botUrl);
if (local.isEmpty()) {
return;
}
UrlClickHandler::Open(
local,
QVariant::fromValue(ClickHandlerContext{
.sessionWindow = base::make_weak(controller.get()),
.botStartAutoSubmit = true,
}));
});
box->setShowFinishedCallback([raw = button.data()]{ box->setShowFinishedCallback([raw = button.data()]{
raw->startGlareAnimation(); raw->startGlareAnimation();
}); });

View file

@ -489,6 +489,7 @@ settingsPremiumArrow: icon{{ "fast_to_original", menuIconFg }};
settingsPremiumArrowOver: icon{{ "fast_to_original", menuIconFgOver }}; settingsPremiumArrowOver: icon{{ "fast_to_original", menuIconFgOver }};
settingsPremiumStatusPadding: margins(22px, 8px, 22px, 2px); settingsPremiumStatusPadding: margins(22px, 8px, 22px, 2px);
settingsPremiumOptionsPadding: margins(0px, 9px, 0px, 2px);
settingsPremiumTopHeight: 220px; settingsPremiumTopHeight: 220px;
settingsPremiumUserHeight: 223px; settingsPremiumUserHeight: 223px;
settingsPremiumUserTitlePadding: margins(0px, 16px, 0px, 6px); settingsPremiumUserTitlePadding: margins(0px, 16px, 0px, 6px);

View file

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/stickers_lottie.h" // LottiePlayerFromDocument. #include "chat_helpers/stickers_lottie.h" // LottiePlayerFromDocument.
#include "core/application.h" #include "core/application.h"
#include "core/click_handler_types.h" #include "core/click_handler_types.h"
#include "core/local_url_handlers.h" // Core::TryConvertUrlToLocal.
#include "core/ui_integration.h" // MarkedTextContext. #include "core/ui_integration.h" // MarkedTextContext.
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_document_media.h" #include "data/data_document_media.h"
@ -39,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text/format_values.h" #include "ui/text/format_values.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/widgets/checkbox.h" // Ui::RadiobuttonGroup.
#include "ui/widgets/gradient_round_button.h" #include "ui/widgets/gradient_round_button.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/wrap/fade_wrap.h" #include "ui/wrap/fade_wrap.h"
@ -69,6 +71,33 @@ constexpr auto kTitleAdditionalScale = 0.15;
return u":/gui/icons/settings/star.svg"_q; return u":/gui/icons/settings/star.svg"_q;
} }
[[nodiscard]] Data::SubscriptionOptions SubscriptionOptionsForRows(
Data::SubscriptionOptions result) {
for (auto &option : result) {
const auto total = option.costTotal;
const auto perMonth = option.costPerMonth;
option.costTotal = tr::lng_premium_gift_per(
tr::now,
lt_cost,
perMonth);
option.costPerMonth = tr::lng_premium_subscribe_total(
tr::now,
lt_cost,
total);
if (option.duration == tr::lng_months(tr::now, lt_count, 1)) {
option.costPerMonth = QString();
option.duration = tr::lng_premium_subscribe_months_1(tr::now);
} else if (option.duration == tr::lng_months(tr::now, lt_count, 6)) {
option.duration = tr::lng_premium_subscribe_months_6(tr::now);
} else if (option.duration == tr::lng_years(tr::now, lt_count, 1)) {
option.duration = tr::lng_premium_subscribe_months_12(tr::now);
}
}
return result;
}
namespace Ref { namespace Ref {
namespace Gift { namespace Gift {
@ -968,6 +997,9 @@ public:
private: private:
void setupContent(); void setupContent();
void setupSubscriptionOptions(
not_null<Ui::VerticalLayout*> container,
int lastSkip);
const not_null<Window::SessionController*> _controller; const not_null<Window::SessionController*> _controller;
const QString _ref; const QString _ref;
@ -979,8 +1011,11 @@ private:
rpl::variable<Info::Wrap> _wrap; rpl::variable<Info::Wrap> _wrap;
Fn<void(bool)> _setPaused; Fn<void(bool)> _setPaused;
std::shared_ptr<Ui::RadiobuttonGroup> _radioGroup;
rpl::event_stream<> _showBack; rpl::event_stream<> _showBack;
rpl::event_stream<> _showFinished; rpl::event_stream<> _showFinished;
rpl::event_stream<QString> _buttonText;
}; };
@ -989,7 +1024,8 @@ Premium::Premium(
not_null<Window::SessionController*> controller) not_null<Window::SessionController*> controller)
: Section(parent) : Section(parent)
, _controller(controller) , _controller(controller)
, _ref(ResolveRef(controller->premiumRef())) { , _ref(ResolveRef(controller->premiumRef()))
, _radioGroup(std::make_shared<Ui::RadiobuttonGroup>()) {
setupContent(); setupContent();
_controller->session().api().premium().reload(); _controller->session().api().premium().reload();
} }
@ -1016,6 +1052,47 @@ void Premium::setStepDataReference(std::any &data) {
} }
} }
void Premium::setupSubscriptionOptions(
not_null<Ui::VerticalLayout*> container,
int lastSkip) {
const auto options = container->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container,
object_ptr<Ui::VerticalLayout>(container)));
const auto skip = container->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container,
object_ptr<Ui::VerticalLayout>(container)));
const auto content = options->entity();
AddSkip(content, st::settingsPremiumOptionsPadding.top());
Ui::Premium::AddGiftOptions(
content,
_radioGroup,
SubscriptionOptionsForRows(
_controller->session().api().premium().subscriptionOptions()),
st::premiumSubscriptionOption,
true);
AddSkip(content, st::settingsPremiumOptionsPadding.bottom());
AddDivider(content);
AddSkip(content, lastSkip - st::settingsSectionSkip);
AddSkip(skip->entity(), lastSkip);
auto toggleOn = rpl::combine(
Data::AmPremiumValue(&_controller->session()),
rpl::single(!!(Ref::EmojiStatus::Parse(_ref)))
) | rpl::map([=](bool premium, bool isEmojiStatus) {
return !premium && !isEmojiStatus;
});
options->toggleOn(rpl::duplicate(toggleOn), anim::type::instant);
skip->toggleOn(std::move(
toggleOn
) | rpl::map([](bool value) { return !value; }), anim::type::instant);
}
void Premium::setupContent() { void Premium::setupContent() {
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this); const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
@ -1025,7 +1102,9 @@ void Premium::setupContent() {
const auto &titlePadding = st::settingsPremiumRowTitlePadding; const auto &titlePadding = st::settingsPremiumRowTitlePadding;
const auto &descriptionPadding = st::settingsPremiumRowAboutPadding; const auto &descriptionPadding = st::settingsPremiumRowAboutPadding;
AddSkip(content, stDefault.padding.top() + titlePadding.top()); setupSubscriptionOptions(
content,
stDefault.padding.top() + titlePadding.top());
auto entryMap = EntryMap(); auto entryMap = EntryMap();
auto iconContainers = std::vector<Ui::AbstractButton*>(); auto iconContainers = std::vector<Ui::AbstractButton*>();
@ -1385,10 +1464,11 @@ QPointer<Ui::RpWidget> Premium::createPinnedToBottom(
} }
const auto emojiStatusData = Ref::EmojiStatus::Parse(_ref); const auto emojiStatusData = Ref::EmojiStatus::Parse(_ref);
const auto session = &_controller->session();
auto buttonText = [&]() -> std::optional<rpl::producer<QString>> { auto buttonText = [&]() -> std::optional<rpl::producer<QString>> {
if (emojiStatusData) { if (emojiStatusData) {
auto &data = _controller->session().data(); auto &data = session->data();
if (const auto peer = data.peer(emojiStatusData.peerId)) { if (const auto peer = data.peer(emojiStatusData.peerId)) {
return Info::Profile::EmojiStatusIdValue( return Info::Profile::EmojiStatusIdValue(
peer peer
@ -1399,7 +1479,7 @@ QPointer<Ui::RpWidget> Premium::createPinnedToBottom(
}) | rpl::flatten_latest(); }) | rpl::flatten_latest();
} }
} }
return std::nullopt; return _buttonText.events();
}(); }();
_subscribe = CreateSubscribeButton({ _subscribe = CreateSubscribeButton({
@ -1407,6 +1487,13 @@ QPointer<Ui::RpWidget> Premium::createPinnedToBottom(
content, content,
[ref = _ref] { return ref; }, [ref = _ref] { return ref; },
std::move(buttonText), std::move(buttonText),
std::nullopt,
[=, options = session->api().premium().subscriptionOptions()] {
const auto value = _radioGroup->value();
return (value < options.size() && value >= 0)
? options[value].botUrl
: QString();
},
}); });
if (emojiStatusData) { if (emojiStatusData) {
// "Learn More" should open the general Premium Settings // "Learn More" should open the general Premium Settings
@ -1419,6 +1506,18 @@ QPointer<Ui::RpWidget> Premium::createPinnedToBottom(
ShowPremium(controller, QString()); ShowPremium(controller, QString());
controller->setPremiumRef(ref); controller->setPremiumRef(ref);
}); });
} else {
_radioGroup->setChangedCallback([=](int value) {
const auto options =
_controller->session().api().premium().subscriptionOptions();
Expects(value < options.size() && value >= 0);
auto text = tr::lng_premium_subscribe_button(
tr::now,
lt_cost,
options[value].costPerMonth);
_buttonText.fire(std::move(text));
});
_radioGroup->setValue(0);
} }
_showFinished.events( _showFinished.events(
@ -1432,7 +1531,6 @@ QPointer<Ui::RpWidget> Premium::createPinnedToBottom(
_subscribe->resizeToWidth(width - padding.left() - padding.right()); _subscribe->resizeToWidth(width - padding.left() - padding.right());
}, _subscribe->lifetime()); }, _subscribe->lifetime());
const auto session = &_controller->session();
rpl::combine( rpl::combine(
_subscribe->heightValue(), _subscribe->heightValue(),
Data::AmPremiumValue(session), Data::AmPremiumValue(session),
@ -1543,9 +1641,24 @@ not_null<Ui::GradientButton*> CreateSubscribeButton(
result->setClickedCallback([ result->setClickedCallback([
controller = args.controller, controller = args.controller,
computeRef = args.computeRef] { computeRef = args.computeRef,
SendScreenAccept(controller); computeBotUrl = args.computeBotUrl] {
StartPremiumPayment(controller, computeRef()); const auto url = computeBotUrl ? QString() : computeBotUrl();
if (!url.isEmpty()) {
const auto local = Core::TryConvertUrlToLocal(url);
if (local.isEmpty()) {
return;
}
UrlClickHandler::Open(
local,
QVariant::fromValue(ClickHandlerContext{
.sessionWindow = base::make_weak(controller.get()),
.botStartAutoSubmit = true,
}));
} else {
SendScreenAccept(controller);
StartPremiumPayment(controller, computeRef());
}
}); });
const auto &st = st::premiumPreviewBox.button; const auto &st = st::premiumPreviewBox.button;

View file

@ -53,6 +53,7 @@ struct SubscribeButtonArgs final {
Fn<QString()> computeRef; Fn<QString()> computeRef;
std::optional<rpl::producer<QString>> text; std::optional<rpl::producer<QString>> text;
std::optional<QGradientStops> gradientStops; std::optional<QGradientStops> gradientStops;
Fn<QString()> computeBotUrl; // nullable
}; };
[[nodiscard]] not_null<Ui::GradientButton*> CreateSubscribeButton( [[nodiscard]] not_null<Ui::GradientButton*> CreateSubscribeButton(

View file

@ -97,17 +97,56 @@ premiumAccountsNameTop: 13px;
premiumAccountsPadding: margins(0px, 20px, 0px, 14px); premiumAccountsPadding: margins(0px, 20px, 0px, 14px);
premiumAccountsHeight: 105px; premiumAccountsHeight: 105px;
PremiumOption {
rowPadding: margins;
rowMargins: margins;
rowHeight: pixels;
borderWidth: pixels;
borderRadius: pixels;
subtitleTop: pixels;
textLeft: pixels;
badgeHeight: pixels;
badgeRadius: pixels;
badgeMargins: margins;
badgeShift: point;
}
premiumSubscriptionOption: PremiumOption {
rowPadding: margins(9px, 2px, 17px, 3px);
rowMargins: margins(14px, 0px, 5px, 0px);
rowHeight: 39px;
borderWidth: 0px;
borderRadius: 0px;
subtitleTop: 1px;
textLeft: 51px;
badgeHeight: 15px;
badgeRadius: 4px;
badgeMargins: margins(3px, 1px, 3px, 0px);
badgeShift: point(9px, 0px);
}
// Gift. // Gift.
premiumGiftRowHeight: 56px; premiumGiftOption: PremiumOption {
premiumGiftRowBorderWidth: 2px; rowPadding: margins(19px, 2px, 17px, 2px);
premiumGiftRowBorderRadius: 9px; rowMargins: margins(14px, 0px, 15px, 0px);
premiumGiftRowPaddings: margins(19px, 2px, 17px, 2px); rowHeight: 56px;
premiumGiftRowMargins: margins(14px, 0px, 15px, 0px);
premiumGiftRowSubtitleTop: 7px; borderWidth: 2px;
premiumGiftRowTextLeft: 53px; borderRadius: 9px;
premiumGiftRowBadgeHeight: 18px;
premiumGiftRowBadgeRadius: 4px; subtitleTop: 7px;
premiumGiftRowBadgeMargins: margins(5px, 1px, 5px, 0px); textLeft: 53px;
badgeHeight: 18px;
badgeRadius: 4px;
badgeMargins: margins(5px, 1px, 5px, 0px);
}
premiumGiftUserpicPadding: margins(10px, 27px, 18px, 13px); premiumGiftUserpicPadding: margins(10px, 27px, 18px, 13px);
premiumGiftTitlePadding: margins(18px, 0px, 18px, 0px); premiumGiftTitlePadding: margins(18px, 0px, 18px, 0px);

View file

@ -938,7 +938,9 @@ void ShowListBox(
void AddGiftOptions( void AddGiftOptions(
not_null<Ui::VerticalLayout*> parent, not_null<Ui::VerticalLayout*> parent,
std::shared_ptr<Ui::RadiobuttonGroup> group, std::shared_ptr<Ui::RadiobuttonGroup> group,
std::vector<Data::SubscriptionOption> gifts) { std::vector<Data::SubscriptionOption> gifts,
const style::PremiumOption &st,
bool topBadges) {
struct Edges { struct Edges {
Ui::RpWidget *top = nullptr; Ui::RpWidget *top = nullptr;
@ -956,8 +958,8 @@ void AddGiftOptions(
const auto addRow = [&](const Data::SubscriptionOption &info, int index) { const auto addRow = [&](const Data::SubscriptionOption &info, int index) {
const auto row = parent->add( const auto row = parent->add(
object_ptr<Ui::AbstractButton>(parent), object_ptr<Ui::AbstractButton>(parent),
st::premiumGiftRowPaddings); st.rowPadding);
row->resize(row->width(), st::premiumGiftRowHeight); row->resize(row->width(), st.rowHeight);
{ {
if (!index) { if (!index) {
edges->top = row; edges->top = row;
@ -981,7 +983,7 @@ void AddGiftOptions(
- margins.top() - margins.top()
- margins.bottom(); - margins.bottom();
radio->moveToLeft( radio->moveToLeft(
st::premiumGiftRowMargins.left(), st.rowMargins.left(),
(s.height() - radioHeight) / 2); (s.height() - radioHeight) / 2);
}, radio->lifetime()); }, radio->lifetime());
@ -992,30 +994,45 @@ void AddGiftOptions(
p.fillRect(r, Qt::transparent); p.fillRect(r, Qt::transparent);
const auto left = st::premiumGiftRowTextLeft; const auto left = st.textLeft;
const auto borderWidth = st::premiumGiftRowBorderWidth;
const auto halfHeight = row->height() / 2; const auto halfHeight = row->height() / 2;
const auto titleFont = st::semiboldFont; const auto titleFont = st::semiboldFont;
p.setFont(titleFont); p.setFont(titleFont);
p.setPen(st::boxTextFg); p.setPen(st::boxTextFg);
p.drawText( if (info.costPerMonth.isEmpty() && info.discount.isEmpty()) {
left, const auto r = row->rect().translated(
st::premiumGiftRowSubtitleTop + titleFont->ascent, -row->rect().left() + left,
info.duration); 0);
p.drawText(r, info.duration, style::al_left);
} else {
p.drawText(
left,
st.subtitleTop + titleFont->ascent,
info.duration);
}
const auto discountFont = st::windowFiltersButton.badgeStyle.font; const auto discountFont = st::windowFiltersButton.badgeStyle.font;
const auto discountWidth = discountFont->width(info.discount); const auto discountWidth = discountFont->width(info.discount);
const auto &discountMargins = discountWidth const auto &discountMargins = discountWidth
? st::premiumGiftRowBadgeMargins ? st.badgeMargins
: style::margins(); : style::margins();
const auto discountRect = QRect(
const auto bottomLeftRect = QRect(
left, left,
halfHeight + discountMargins.top(), halfHeight + discountMargins.top(),
discountWidth discountWidth
+ discountMargins.left() + discountMargins.left()
+ discountMargins.right(), + discountMargins.right(),
st::premiumGiftRowBadgeHeight); st.badgeHeight);
const auto discountRect = topBadges
? bottomLeftRect.translated(
titleFont->width(info.duration) + st.badgeShift.x(),
-bottomLeftRect.top()
+ st.badgeShift.y()
+ st.subtitleTop
+ (titleFont->height - bottomLeftRect.height()) / 2)
: bottomLeftRect;
{ {
const auto from = edges->top->y(); const auto from = edges->top->y();
const auto to = edges->bottom->y() + edges->bottom->height(); const auto to = edges->bottom->y() + edges->bottom->height();
@ -1023,17 +1040,17 @@ void AddGiftOptions(
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.setBrush(partialGradient.compute(row->y(), row->height())); p.setBrush(partialGradient.compute(row->y(), row->height()));
const auto round = st::premiumGiftRowBadgeRadius; const auto round = st.badgeRadius;
p.drawRoundedRect(discountRect, round, round); p.drawRoundedRect(discountRect, round, round);
} }
if (animation->nowIndex == index) { if (st.borderWidth && (animation->nowIndex == index)) {
const auto progress = animation->animation.value(1.); const auto progress = animation->animation.value(1.);
const auto w = row->width(); const auto w = row->width();
auto gradient = QLinearGradient(w - w * progress, 0, w * 2, 0); auto gradient = QLinearGradient(w - w * progress, 0, w * 2, 0);
gradient.setSpread(QGradient::Spread::RepeatSpread); gradient.setSpread(QGradient::Spread::RepeatSpread);
gradient.setStops(stops); gradient.setStops(stops);
const auto pen = QPen(QBrush(gradient), borderWidth); const auto pen = QPen(QBrush(gradient), st.borderWidth);
p.setPen(pen); p.setPen(pen);
p.setBrush(Qt::NoBrush); p.setBrush(Qt::NoBrush);
const auto borderRect = row->rect() const auto borderRect = row->rect()
@ -1042,7 +1059,7 @@ void AddGiftOptions(
pen.width() / 2, pen.width() / 2,
pen.width() / 2, pen.width() / 2,
pen.width() / 2); pen.width() / 2);
const auto round = st::premiumGiftRowBorderRadius; const auto round = st.borderRadius;
p.drawRoundedRect(borderRect, round, round); p.drawRoundedRect(borderRect, round, round);
} }
@ -1051,15 +1068,17 @@ void AddGiftOptions(
p.drawText(discountRect, info.discount, style::al_center); p.drawText(discountRect, info.discount, style::al_center);
const auto perRect = QMargins(0, 0, row->width(), 0) const auto perRect = QMargins(0, 0, row->width(), 0)
+ discountRect.translated( + bottomLeftRect.translated(
discountRect.width() + discountMargins.left(), topBadges
? 0
: bottomLeftRect.width() + discountMargins.left(),
0); 0);
p.setPen(st::windowSubTextFg); p.setPen(st::windowSubTextFg);
p.setFont(st::shareBoxListItem.nameStyle.font); p.setFont(st::shareBoxListItem.nameStyle.font);
p.drawText(perRect, info.costPerMonth, style::al_left); p.drawText(perRect, info.costPerMonth, style::al_left);
const auto totalRect = row->rect() const auto totalRect = row->rect()
- QMargins(0, 0, st::premiumGiftRowMargins.right(), 0); - QMargins(0, 0, st.rowMargins.right(), 0);
p.setFont(st::normalFont); p.setFont(st::normalFont);
p.drawText(totalRect, info.costTotal, style::al_right); p.drawText(totalRect, info.costTotal, style::al_right);
}, row->lifetime()); }, row->lifetime());

View file

@ -22,6 +22,7 @@ struct SubscriptionOption;
namespace style { namespace style {
struct RoundImageCheckbox; struct RoundImageCheckbox;
struct PremiumOption;
struct TextStyle; struct TextStyle;
} // namespace style } // namespace style
@ -90,7 +91,9 @@ void ShowListBox(
void AddGiftOptions( void AddGiftOptions(
not_null<Ui::VerticalLayout*> parent, not_null<Ui::VerticalLayout*> parent,
std::shared_ptr<Ui::RadiobuttonGroup> group, std::shared_ptr<Ui::RadiobuttonGroup> group,
std::vector<Data::SubscriptionOption> gifts); std::vector<Data::SubscriptionOption> gifts,
const style::PremiumOption &st,
bool topBadges = false);
} // namespace Premium } // namespace Premium
} // namespace Ui } // namespace Ui