Implement stories premium promo.

This commit is contained in:
John Preston 2023-08-04 08:07:37 +02:00
parent 40b274e1b4
commit 7877cb0b3a
21 changed files with 292 additions and 113 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1828,6 +1828,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_premium_summary_subtitle_gift#other" = "{user} has gifted you a {count}-months subscription for Telegram Premium.";
"lng_premium_summary_subtitle_gift_me#one" = "You gifted {user} a {count}-month subscription for Telegram Premium.";
"lng_premium_summary_subtitle_gift_me#other" = "You gifted {user} a {count}-months subscription for Telegram Premium.";
"lng_premium_summary_subtitle_stories" = "Upgraded Stories";
"lng_premium_summary_about_stories" = "Priority order, stealth mode, permanent views history and more.";
"lng_premium_summary_subtitle_double_limits" = "Doubled Limits";
"lng_premium_summary_about_double_limits" = "Up to 1000 channels, 20 folders, 10 pins, 20 public links, 4 accounts and more.";
"lng_premium_summary_subtitle_more_upload" = "4Gb Upload Size";
@ -1861,6 +1863,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_premium_success" = "You've successfully subscribed to Telegram Premium!";
"lng_premium_unavailable" = "This feature requires subscription to **Telegram Premium**.\n\nUnfortunately, **Telegram Premium** is not available in your region.";
// Upgraded Stories.
"lng_premium_stories_subtitle_order" = "Priority Order";
"lng_premium_stories_about_order" = "Get more views as your stories are always displayed first.";
"lng_premium_stories_subtitle_stealth" = "Stealth Mode";
"lng_premium_stories_about_stealth" = "Hide the fact that you viewed other people's stories.";
"lng_premium_stories_subtitle_views" = "Permanent Views History";
"lng_premium_stories_about_views" = "Check who opens your stories even after they expire.";
"lng_premium_stories_subtitle_expiration" = "Expiration Durations*";
"lng_premium_stories_about_expiration" = "Set custom expiration durations like 6 or 48 hours for your stories.";
"lng_premium_stories_subtitle_download" = "Download Stories";
"lng_premium_stories_about_download" = "Save other people's unprotected stories to your disk.";
"lng_premium_stories_subtitle_caption" = "Longer Captions*";
"lng_premium_stories_about_caption" = "Add ten times longer captions to your stories up to 2048 symbols.";
"lng_premium_stories_subtitle_links" = "Links and Formatting*";
"lng_premium_stories_about_links" = "Add links and formatting in captions of your stories.";
"lng_premium_stories_about_mobile" = "* Available when posting stories from Telegram apps for iOS and Android.";
// Doubled Limits.
"lng_premium_double_limits_subtitle_channels" = "Groups and Channels";
"lng_premium_double_limits_about_channels#one" = "Join up to {count} channels and large groups";

View File

@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/padding_wrap.h"
#include "ui/boxes/confirm_box.h"
#include "ui/painter.h"
#include "settings/settings_common.h"
#include "settings/settings_premium.h"
#include "lottie/lottie_single_player.h"
#include "history/view/media/history_view_sticker.h"
@ -92,6 +93,10 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
[[nodiscard]] rpl::producer<QString> SectionTitle(PremiumPreview section) {
switch (section) {
case PremiumPreview::Stories:
return tr::lng_premium_summary_subtitle_stories();
case PremiumPreview::DoubleLimits:
return tr::lng_premium_summary_subtitle_double_limits();
case PremiumPreview::MoreUpload:
return tr::lng_premium_summary_subtitle_more_upload();
case PremiumPreview::FasterDownload:
@ -122,6 +127,10 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
[[nodiscard]] rpl::producer<QString> SectionAbout(PremiumPreview section) {
switch (section) {
case PremiumPreview::Stories:
return tr::lng_premium_summary_about_stories();
case PremiumPreview::DoubleLimits:
return tr::lng_premium_summary_about_double_limits();
case PremiumPreview::MoreUpload:
return tr::lng_premium_summary_about_more_upload();
case PremiumPreview::FasterDownload:
@ -1117,6 +1126,56 @@ void Show(std::shared_ptr<ChatHelpers::Show> show, QImage back) {
}
}
void DecorateListPromoBox(
not_null<Ui::GenericBox*> box,
std::shared_ptr<ChatHelpers::Show> show,
const Descriptor &descriptor) {
const auto session = &show->session();
box->addTopButton(st::boxTitleClose, [=] {
box->closeBox();
});
Data::AmPremiumValue(
session
) | rpl::skip(1) | rpl::start_with_next([=] {
box->closeBox();
}, box->lifetime());
if (const auto &hidden = descriptor.hiddenCallback) {
box->boxClosing() | rpl::start_with_next(hidden, box->lifetime());
}
if (session->premium()) {
box->addButton(tr::lng_close(), [=] {
box->closeBox();
});
} else {
const auto button = Settings::CreateSubscribeButton({
.parent = box,
.computeRef = [] { return u"double_limits"_q; },
.show = show,
});
box->setShowFinishedCallback([=] {
button->startGlareAnimation();
});
box->setStyle(st::premiumPreviewDoubledLimitsBox);
box->widthValue(
) | rpl::start_with_next([=](int width) {
const auto &padding =
st::premiumPreviewDoubledLimitsBox.buttonPadding;
button->resizeToWidth(width
- padding.left()
- padding.right());
button->moveToLeft(padding.left(), padding.top());
}, button->lifetime());
box->addButton(
object_ptr<Ui::AbstractButton>::fromRaw(button));
}
}
void Show(
std::shared_ptr<ChatHelpers::Show> show,
Descriptor &&descriptor) {
@ -1128,6 +1187,18 @@ void Show(
descriptor.shownCallback(raw);
}
return;
} else if (descriptor.section == PremiumPreview::DoubleLimits) {
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
DoubledLimitsPreviewBox(box, &show->session());
DecorateListPromoBox(box, show, descriptor);
}));
return;
} else if (descriptor.section == PremiumPreview::Stories) {
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
UpgradedStoriesPreviewBox(box, &show->session());
DecorateListPromoBox(box, show, descriptor);
}));
return;
}
auto &list = Preloads();
for (auto i = begin(list); i != end(list);) {
@ -1240,11 +1311,13 @@ void PremiumUnavailableBox(not_null<Ui::GenericBox*> box) {
void DoubledLimitsPreviewBox(
not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session) {
box->setTitle(tr::lng_premium_summary_subtitle_double_limits());
const auto limits = Data::PremiumLimits(session);
auto entries = std::vector<Ui::Premium::ListEntry>();
{
const auto premium = limits.channelsPremium();
entries.push_back(Ui::Premium::ListEntry{
entries.push_back({
tr::lng_premium_double_limits_subtitle_channels(),
tr::lng_premium_double_limits_about_channels(
lt_count,
@ -1256,7 +1329,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.dialogsPinnedPremium();
entries.push_back(Ui::Premium::ListEntry{
entries.push_back({
tr::lng_premium_double_limits_subtitle_pins(),
tr::lng_premium_double_limits_about_pins(
lt_count,
@ -1268,7 +1341,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.channelsPublicPremium();
entries.push_back(Ui::Premium::ListEntry{
entries.push_back({
tr::lng_premium_double_limits_subtitle_links(),
tr::lng_premium_double_limits_about_links(
lt_count,
@ -1280,7 +1353,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.gifsPremium();
entries.push_back(Ui::Premium::ListEntry{
entries.push_back({
tr::lng_premium_double_limits_subtitle_gifs(),
tr::lng_premium_double_limits_about_gifs(
lt_count,
@ -1292,7 +1365,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.stickersFavedPremium();
entries.push_back(Ui::Premium::ListEntry{
entries.push_back({
tr::lng_premium_double_limits_subtitle_stickers(),
tr::lng_premium_double_limits_about_stickers(
lt_count,
@ -1304,7 +1377,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.aboutLengthPremium();
entries.push_back(Ui::Premium::ListEntry{
entries.push_back({
tr::lng_premium_double_limits_subtitle_bio(),
tr::lng_premium_double_limits_about_bio(
Ui::Text::RichLangValue),
@ -1314,7 +1387,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.captionLengthPremium();
entries.push_back(Ui::Premium::ListEntry{
entries.push_back({
tr::lng_premium_double_limits_subtitle_captions(),
tr::lng_premium_double_limits_about_captions(
Ui::Text::RichLangValue),
@ -1324,7 +1397,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.dialogFiltersPremium();
entries.push_back(Ui::Premium::ListEntry{
entries.push_back({
tr::lng_premium_double_limits_subtitle_folders(),
tr::lng_premium_double_limits_about_folders(
lt_count,
@ -1336,7 +1409,7 @@ void DoubledLimitsPreviewBox(
}
{
const auto premium = limits.dialogFiltersChatsPremium();
entries.push_back(Ui::Premium::ListEntry{
entries.push_back({
tr::lng_premium_double_limits_subtitle_folder_chats(),
tr::lng_premium_double_limits_about_folder_chats(
lt_count,
@ -1350,7 +1423,7 @@ void DoubledLimitsPreviewBox(
const auto till = (nextMax >= Main::Domain::kPremiumMaxAccounts)
? QString::number(Main::Domain::kPremiumMaxAccounts)
: (QString::number(nextMax) + QChar('+'));
entries.push_back(Ui::Premium::ListEntry{
entries.push_back({
tr::lng_premium_double_limits_subtitle_accounts(),
tr::lng_premium_double_limits_about_accounts(
lt_count,
@ -1366,6 +1439,60 @@ void DoubledLimitsPreviewBox(
std::move(entries));
}
void UpgradedStoriesPreviewBox(
not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session) {
using namespace Ui::Text;
box->setTitle(tr::lng_premium_summary_subtitle_stories());
auto entries = std::vector<Ui::Premium::ListEntry>();
entries.push_back({
.title = tr::lng_premium_stories_subtitle_order(),
.about = tr::lng_premium_stories_about_order(WithEntities),
.icon = &st::settingsStoriesIconOrder,
});
entries.push_back({
.title = tr::lng_premium_stories_subtitle_stealth(),
.about = tr::lng_premium_stories_about_stealth(WithEntities),
.icon = &st::settingsStoriesIconStealth,
});
entries.push_back({
.title = tr::lng_premium_stories_subtitle_views(),
.about = tr::lng_premium_stories_about_views(WithEntities),
.icon = &st::settingsStoriesIconViews,
});
entries.push_back({
.title = tr::lng_premium_stories_subtitle_expiration(),
.about = tr::lng_premium_stories_about_expiration(WithEntities),
.icon = &st::settingsStoriesIconExpiration,
});
entries.push_back({
.title = tr::lng_premium_stories_subtitle_download(),
.about = tr::lng_premium_stories_about_download(WithEntities),
.icon = &st::settingsStoriesIconDownload,
});
entries.push_back({
.title = tr::lng_premium_stories_subtitle_caption(),
.about = tr::lng_premium_stories_about_caption(WithEntities),
.icon = &st::settingsStoriesIconCaption,
});
entries.push_back({
.title = tr::lng_premium_stories_subtitle_links(),
.about = tr::lng_premium_stories_about_links(WithEntities),
.icon = &st::settingsStoriesIconLinks,
});
Ui::Premium::ShowListBox(
box,
st::defaultPremiumLimits,
std::move(entries));
Settings::AddDividerText(
box->verticalLayout(),
tr::lng_premium_stories_about_mobile());
}
object_ptr<Ui::GradientButton> CreateUnlockButton(
QWidget *parent,
rpl::producer<QString> text) {

View File

@ -41,7 +41,13 @@ void DoubledLimitsPreviewBox(
not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session);
void UpgradedStoriesPreviewBox(
not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session);
enum class PremiumPreview {
Stories,
DoubleLimits,
MoreUpload,
FasterDownload,
VoiceToText,

View File

@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer_rpl.h"
#include "base/unixtime.h"
#include "boxes/premium_preview_box.h"
#include "chat_helpers/compose/compose_show.h"
#include "data/data_peer_values.h"
#include "data/data_session.h"
@ -295,7 +296,7 @@ struct Feature {
label->resizeToWidth(width);
label->move(added / 2, top);
const auto inner = std::min(label->textMaxWidth(), width);
const auto right = (added / 2) + (width - inner) / 2 + inner;
const auto right = (added / 2) + (outer - inner) / 2 + inner;
const auto lockTop = (label->height() - lock->height()) / 2;
lock->move(right + lockLeft, top + lockTop);
};
@ -351,9 +352,7 @@ struct Feature {
data->requested = false;
const auto usage = ChatHelpers::WindowUsage::PremiumPromo;
if (const auto window = show->resolveWindow(usage)) {
Settings::ShowPremium(
window,
u"stories__stealth_mode"_q);
ShowPremiumPreviewBox(window, PremiumPreview::Stories);
window->window().activate();
}
} else if (now.mode.cooldownTill > now.now) {

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_peer_photo.h"
#include "lang/lang_keys.h"
#include "mainwindow.h"
#include "boxes/premium_preview_box.h"
#include "core/application.h"
#include "core/click_handler_types.h"
#include "core/file_utilities.h"
@ -1252,8 +1253,8 @@ void OverlayWidget::showPremiumDownloadPromo() {
const auto filter = [=](const auto &...) {
const auto usage = ChatHelpers::WindowUsage::PremiumPromo;
if (const auto window = uiShow()->resolveWindow(usage)) {
const auto ref = u"stories__save_stories_to_gallery"_q;
Settings::ShowPremium(window, ref);
ShowPremiumPreviewBox(window, PremiumPreview::Stories);
window->window().activate();
}
return false;
};

View File

@ -109,6 +109,7 @@ settingsIconTopics: icon {{ "settings/topics", settingsIconFg }};
settingsIconTTL: icon {{ "settings/ttl", settingsIconFg }};
settingsIconPhoto: icon {{ "settings/photo", settingsIconFg }};
settingsPremiumIconStories: icon {{ "settings/stories", settingsIconFg }};
settingsPremiumIconChannelsOff: icon {{ "settings/premium/channels_off", settingsIconFg }};
settingsPremiumIconDouble: icon {{ "settings/premium/double", settingsIconFg }};
settingsPremiumIconStatus: icon {{ "settings/premium/status", settingsIconFg }};
@ -120,6 +121,14 @@ settingsPremiumIconVoice: icon {{ "settings/premium/voice", settingsIconFg }};
settingsPremiumIconFiles: icon {{ "settings/premium/files", settingsIconFg }};
settingsPremiumIconTranslations: icon {{ "settings/premium/translations", settingsIconFg }};
settingsStoriesIconOrder: icon {{ "settings/premium/stories_order", premiumButtonBg1 }};
settingsStoriesIconStealth: icon {{ "menu/stealth", premiumButtonBg1 }};
settingsStoriesIconViews: icon {{ "menu/show_in_chat", premiumButtonBg1 }};
settingsStoriesIconExpiration: icon {{ "settings/premium/timer", premiumButtonBg1 }};
settingsStoriesIconDownload: icon {{ "menu/download", premiumButtonBg1 }};
settingsStoriesIconCaption: icon {{ "settings/premium/stories_caption", premiumButtonBg1 }};
settingsStoriesIconLinks: icon {{ "settings/premium/stories_links", premiumButtonBg1 }};
settingsTTLChatsOff: icon {{ "settings/ttl/autodelete_off", windowSubTextFg }};
settingsTTLChatsOn: icon {{ "settings/ttl/autodelete_on", windowActiveTextFg }};
@ -473,6 +482,9 @@ settingsPremiumRowAboutPadding: margins(59px, 0px, 46px, 6px);
settingsPremiumPreviewTitlePadding: margins(24px, 13px, 24px, 3px);
settingsPremiumPreviewAboutPadding: margins(24px, 0px, 24px, 11px);
settingsPremiumPreviewLinePadding: margins(18px, 0px, 18px, 8px);
settingsPremiumPreviewIconTitlePadding: margins(62px, 13px, 24px, 1px);
settingsPremiumPreviewIconAboutPadding: margins(62px, 0px, 24px, 0px);
settingsPremiumPreviewIconPosition: point(20px, 7px);
settingsPremiumTitlePadding: margins(0px, 18px, 0px, 11px);
settingsPremiumAboutTextStyle: TextStyle(defaultTextStyle) {

View File

@ -203,13 +203,14 @@ struct Entry {
const style::icon *icon;
rpl::producer<QString> title;
rpl::producer<QString> description;
std::optional<PremiumPreview> section;
PremiumPreview section = PremiumPreview::DoubleLimits;
};
using Order = std::vector<QString>;
[[nodiscard]] Order FallbackOrder() {
return Order{
u"stories"_q,
u"double_limits"_q,
u"more_upload"_q,
u"faster_download"_q,
@ -228,12 +229,22 @@ using Order = std::vector<QString>;
[[nodiscard]] base::flat_map<QString, Entry> EntryMap() {
return base::flat_map<QString, Entry>{
{
u"stories"_q,
Entry{
&st::settingsPremiumIconStories,
tr::lng_premium_summary_subtitle_stories(),
tr::lng_premium_summary_about_stories(),
PremiumPreview::Stories,
},
},
{
u"double_limits"_q,
Entry{
&st::settingsPremiumIconDouble,
tr::lng_premium_summary_subtitle_double_limits(),
tr::lng_premium_summary_about_double_limits(),
PremiumPreview::DoubleLimits,
},
},
{
@ -1318,55 +1329,7 @@ void Premium::setupContent() {
_setPaused(false);
});
if (section) {
ShowPremiumPreviewToBuy(controller, *section, hidden);
return;
}
controller->show(Box([=](not_null<Ui::GenericBox*> box) {
DoubledLimitsPreviewBox(box, &controller->session());
box->addTopButton(st::boxTitleClose, [=] {
box->closeBox();
});
Data::AmPremiumValue(
&controller->session()
) | rpl::skip(1) | rpl::start_with_next([=] {
box->closeBox();
}, box->lifetime());
box->boxClosing(
) | rpl::start_with_next(hidden, box->lifetime());
if (controller->session().premium()) {
box->addButton(tr::lng_close(), [=] {
box->closeBox();
});
} else {
const auto button = CreateSubscribeButton({
controller,
box,
[] { return u"double_limits"_q; }
});
box->setShowFinishedCallback([=] {
button->startGlareAnimation();
});
box->setStyle(st::premiumPreviewDoubledLimitsBox);
box->widthValue(
) | rpl::start_with_next([=](int width) {
const auto &padding =
st::premiumPreviewDoubledLimitsBox.buttonPadding;
button->resizeToWidth(width
- padding.left()
- padding.right());
button->moveToLeft(padding.left(), padding.top());
}, button->lifetime());
box->addButton(
object_ptr<Ui::AbstractButton>::fromRaw(button));
}
}));
ShowPremiumPreviewToBuy(controller, section, hidden);
});
iconContainers.push_back(dummy);

View File

@ -1018,79 +1018,123 @@ QGradientStops GiftGradientStops() {
};
}
QGradientStops StoriesIconsGradientStops() {
return {
{ 0., st::premiumButtonBg1->c },
{ .33, st::premiumButtonBg2->c },
{ .66, st::premiumButtonBg3->c },
{ 1., st::premiumIconBg1->c },
};
}
void ShowListBox(
not_null<Ui::GenericBox*> box,
const style::PremiumLimits &st,
std::vector<ListEntry> entries) {
box->setWidth(st::boxWideWidth);
const auto &stLabel = st::defaultFlatLabel;
const auto &titlePadding = st::settingsPremiumPreviewTitlePadding;
const auto &descriptionPadding = st::settingsPremiumPreviewAboutPadding;
const auto &aboutPadding = st::settingsPremiumPreviewAboutPadding;
const auto iconTitlePadding = st::settingsPremiumPreviewIconTitlePadding;
const auto iconAboutPadding = st::settingsPremiumPreviewIconAboutPadding;
auto lines = std::vector<Line*>();
lines.reserve(int(entries.size()));
auto icons = std::shared_ptr<std::vector<QColor>>();
const auto content = box->verticalLayout();
for (auto &entry : entries) {
content->add(
const auto title = content->add(
object_ptr<Ui::FlatLabel>(
content,
base::take(entry.subtitle) | rpl::map(Ui::Text::Bold),
base::take(entry.title) | rpl::map(Ui::Text::Bold),
stLabel),
titlePadding);
entry.icon ? iconTitlePadding : titlePadding);
content->add(
object_ptr<Ui::FlatLabel>(
content,
base::take(entry.description),
base::take(entry.about),
st::boxDividerLabel),
descriptionPadding);
const auto limitRow = content->add(
object_ptr<Line>(
content,
st,
entry.rightNumber,
TextFactory([=, text = ProcessTextFactory(std::nullopt)](
int n) {
if (entry.customRightText && (n == entry.rightNumber)) {
return *entry.customRightText;
} else {
return text(n);
}
}),
entry.leftNumber,
kLimitRowRatio),
st::settingsPremiumPreviewLinePadding);
lines.push_back(limitRow);
entry.icon ? iconAboutPadding : aboutPadding);
if (const auto outlined = entry.icon) {
if (!icons) {
icons = std::make_shared<std::vector<QColor>>();
}
const auto index = int(icons->size());
icons->push_back(QColor());
const auto icon = Ui::CreateChild<Ui::RpWidget>(content.get());
icon->resize(outlined->size());
title->topValue() | rpl::start_with_next([=](int y) {
const auto shift = st::settingsPremiumPreviewIconPosition;
icon->move(QPoint(0, y) + shift);
}, icon->lifetime());
icon->paintRequest() | rpl::start_with_next([=] {
auto p = QPainter(icon);
outlined->paintInCenter(p, icon->rect(), (*icons)[index]);
}, icon->lifetime());
}
if (entry.leftNumber || entry.rightNumber) {
auto factory = [=, text = ProcessTextFactory({})](int n) {
if (entry.customRightText && (n == entry.rightNumber)) {
return *entry.customRightText;
} else {
return text(n);
}
};
const auto limitRow = content->add(
object_ptr<Line>(
content,
st,
entry.rightNumber,
TextFactory(std::move(factory)),
entry.leftNumber,
kLimitRowRatio),
st::settingsPremiumPreviewLinePadding);
lines.push_back(limitRow);
}
}
content->resizeToWidth(content->height());
// Color lines.
Assert(lines.size() > 2);
const auto from = lines.front()->y();
const auto to = lines.back()->y() + lines.back()->height();
// Colors for icons.
if (icons) {
box->addSkip(st::settingsPremiumPreviewLinePadding.bottom());
const auto partialGradient = [&] {
auto stops = Ui::Premium::FullHeightGradientStops();
// Reverse.
for (auto &stop : stops) {
stop.first = std::abs(stop.first - 1.);
const auto stops = Ui::Premium::StoriesIconsGradientStops();
for (auto i = 0, count = int(icons->size()); i != count; ++i) {
(*icons)[i] = anim::gradient_color_at(
stops,
(count > 1) ? (i / float64(count - 1)) : 0.);
}
return PartialGradient(from, to, std::move(stops));
}();
for (auto i = 0; i < int(lines.size()); i++) {
const auto &line = lines[i];
const auto brush = QBrush(
partialGradient.compute(line->y(), line->height()));
line->setColorOverride(brush);
}
box->addSkip(st::settingsPremiumPreviewLinePadding.bottom());
box->setTitle(tr::lng_premium_summary_subtitle_double_limits());
box->setWidth(st::boxWideWidth);
// Color lines.
if (!lines.empty()) {
box->addSkip(st::settingsPremiumPreviewLinePadding.bottom());
const auto from = lines.front()->y();
const auto to = lines.back()->y() + lines.back()->height();
const auto partialGradient = [&] {
auto stops = Ui::Premium::FullHeightGradientStops();
// Reverse.
for (auto &stop : stops) {
stop.first = std::abs(stop.first - 1.);
}
return PartialGradient(from, to, std::move(stops));
}();
for (auto i = 0; i < int(lines.size()); i++) {
const auto &line = lines[i];
const auto brush = QBrush(
partialGradient.compute(line->y(), line->height()));
line->setColorOverride(brush);
}
box->addSkip(st::settingsPremiumPreviewLinePadding.bottom());
}
}
void AddGiftOptions(

View File

@ -88,11 +88,12 @@ void AddAccountsRow(
[[nodiscard]] QGradientStops GiftGradientStops();
struct ListEntry final {
rpl::producer<QString> subtitle;
rpl::producer<TextWithEntities> description;
rpl::producer<QString> title;
rpl::producer<TextWithEntities> about;
int leftNumber = 0;
int rightNumber = 0;
std::optional<QString> customRightText;
const style::icon *icon = nullptr;
};
void ShowListBox(
not_null<Ui::GenericBox*> box,