Implement stories premium promo.
BIN
Telegram/Resources/icons/settings/premium/stories_caption.png
Normal file
After Width: | Height: | Size: 372 B |
BIN
Telegram/Resources/icons/settings/premium/stories_caption@2x.png
Normal file
After Width: | Height: | Size: 512 B |
BIN
Telegram/Resources/icons/settings/premium/stories_caption@3x.png
Normal file
After Width: | Height: | Size: 657 B |
BIN
Telegram/Resources/icons/settings/premium/stories_links.png
Normal file
After Width: | Height: | Size: 467 B |
BIN
Telegram/Resources/icons/settings/premium/stories_links@2x.png
Normal file
After Width: | Height: | Size: 883 B |
BIN
Telegram/Resources/icons/settings/premium/stories_links@3x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/settings/premium/stories_order.png
Normal file
After Width: | Height: | Size: 835 B |
BIN
Telegram/Resources/icons/settings/premium/stories_order@2x.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/settings/premium/stories_order@3x.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
Telegram/Resources/icons/settings/premium/timer.png
Normal file
After Width: | Height: | Size: 608 B |
BIN
Telegram/Resources/icons/settings/premium/timer@2x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Telegram/Resources/icons/settings/premium/timer@3x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
|
@ -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";
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|