Add top reactors to paid reaction details.

This commit is contained in:
John Preston 2024-08-06 16:08:55 +02:00
parent 9bb1fa8782
commit afe30da9f4
14 changed files with 301 additions and 58 deletions

View file

@ -2042,6 +2042,11 @@ auto MessageReactions::recent() const
return _recent; return _recent;
} }
auto MessageReactions::topPaid() const -> const std::vector<TopPaid> & {
static const auto kEmpty = std::vector<TopPaid>();
return _paid ? _paid->top : kEmpty;
}
bool MessageReactions::empty() const { bool MessageReactions::empty() const {
return _list.empty(); return _list.empty();
} }

View file

@ -379,6 +379,7 @@ public:
[[nodiscard]] const std::vector<MessageReaction> &list() const; [[nodiscard]] const std::vector<MessageReaction> &list() const;
[[nodiscard]] auto recent() const [[nodiscard]] auto recent() const
-> const base::flat_map<ReactionId, std::vector<RecentReaction>> &; -> const base::flat_map<ReactionId, std::vector<RecentReaction>> &;
[[nodiscard]] const std::vector<TopPaid> &topPaid() const;
[[nodiscard]] std::vector<ReactionId> chosen() const; [[nodiscard]] std::vector<ReactionId> chosen() const;
[[nodiscard]] bool empty() const; [[nodiscard]] bool empty() const;

View file

@ -2573,11 +2573,11 @@ const std::vector<Data::MessageReaction> &HistoryItem::reactions() const {
std::vector<Data::MessageReaction> HistoryItem::reactionsWithLocal() const { std::vector<Data::MessageReaction> HistoryItem::reactionsWithLocal() const {
auto result = reactions(); auto result = reactions();
const auto i = ranges::find(
result,
Data::ReactionId::Paid(),
&Data::MessageReaction::id);
if (const auto local = _reactions ? _reactions->localPaidCount() : 0) { if (const auto local = _reactions ? _reactions->localPaidCount() : 0) {
const auto i = ranges::find(
result,
Data::ReactionId::Paid(),
&Data::MessageReaction::id);
if (i != end(result)) { if (i != end(result)) {
i->my = true; i->my = true;
i->count += local; i->count += local;
@ -2591,10 +2591,16 @@ std::vector<Data::MessageReaction> HistoryItem::reactionsWithLocal() const {
.my = true, .my = true,
}); });
} }
} else if (i != end(result) && i != begin(result)) {
std::rotate(begin(result), i, i + 1);
} }
return result; return result;
} }
int HistoryItem::reactionsPaidScheduled() const {
return _reactions ? _reactions->scheduledPaid() : 0;
}
bool HistoryItem::reactionsAreTags() const { bool HistoryItem::reactionsAreTags() const {
return _flags & MessageFlag::ReactionsAreTags; return _flags & MessageFlag::ReactionsAreTags;
} }
@ -2609,6 +2615,12 @@ auto HistoryItem::recentReactions() const
return _reactions ? _reactions->recent() : kEmpty; return _reactions ? _reactions->recent() : kEmpty;
} }
auto HistoryItem::topPaidReactions() const
-> const std::vector<Data::MessageReactionsTopPaid> & {
static const auto kEmpty = std::vector<Data::MessageReactionsTopPaid>();
return _reactions ? _reactions->topPaid() : kEmpty;
}
bool HistoryItem::canViewReactions() const { bool HistoryItem::canViewReactions() const {
return (_flags & MessageFlag::CanViewReactions) return (_flags & MessageFlag::CanViewReactions)
&& _reactions && _reactions

View file

@ -57,6 +57,7 @@ struct RippleAnimation;
namespace Data { namespace Data {
struct MessagePosition; struct MessagePosition;
struct RecentReaction; struct RecentReaction;
struct MessageReactionsTopPaid;
struct ReactionId; struct ReactionId;
class Media; class Media;
struct MessageReaction; struct MessageReaction;
@ -456,6 +457,9 @@ public:
-> const base::flat_map< -> const base::flat_map<
Data::ReactionId, Data::ReactionId,
std::vector<Data::RecentReaction>> &; std::vector<Data::RecentReaction>> &;
[[nodiscard]] auto topPaidReactions() const
-> const std::vector<Data::MessageReactionsTopPaid> &;
[[nodiscard]] int reactionsPaidScheduled() const;
[[nodiscard]] bool canViewReactions() const; [[nodiscard]] bool canViewReactions() const;
[[nodiscard]] std::vector<Data::ReactionId> chosenReactions() const; [[nodiscard]] std::vector<Data::ReactionId> chosenReactions() const;
[[nodiscard]] Data::ReactionId lookupUnreadReaction( [[nodiscard]] Data::ReactionId lookupUnreadReaction(

View file

@ -55,6 +55,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h" #include "base/unixtime.h"
#include "base/call_delayed.h" #include "base/call_delayed.h"
#include "data/business/data_shortcut_messages.h" #include "data/business/data_shortcut_messages.h"
#include "data/components/credits.h"
#include "data/components/scheduled_messages.h" #include "data/components/scheduled_messages.h"
#include "data/components/sponsored_messages.h" #include "data/components/sponsored_messages.h"
#include "data/notify/data_notify_settings.h" #include "data/notify/data_notify_settings.h"
@ -869,6 +870,11 @@ HistoryWidget::HistoryWidget(
} }
if (flags & PeerUpdateFlag::FullInfo) { if (flags & PeerUpdateFlag::FullInfo) {
fullInfoUpdated(); fullInfoUpdated();
if (const auto channel = _peer ? _peer->asChannel() : nullptr) {
if (channel->allowedReactions().paidEnabled) {
session().credits().load();
}
}
} }
}, lifetime()); }, lifetime());

View file

@ -55,6 +55,7 @@ struct InlineList::Button {
int textWidth = 0; int textWidth = 0;
int count = 0; int count = 0;
bool chosen = false; bool chosen = false;
bool paid = false;
bool tag = false; bool tag = false;
}; };
@ -180,7 +181,7 @@ void InlineList::layoutButtons() {
} }
InlineList::Button InlineList::prepareButtonWithId(const ReactionId &id) { InlineList::Button InlineList::prepareButtonWithId(const ReactionId &id) {
auto result = Button{ .id = id }; auto result = Button{ .id = id, .paid = id.paid()};
if (const auto customId = id.custom()) { if (const auto customId = id.custom()) {
result.custom = _owner->owner().customEmojiManager().create( result.custom = _owner->owner().customEmojiManager().create(
customId, customId,
@ -421,14 +422,18 @@ void InlineList::paint(
} else if (!bubbleReady) { } else if (!bubbleReady) {
opacity = bubbleProgress; opacity = bubbleProgress;
} }
color = stm->msgFileBg->c; color = button.paid
? st->creditsBg3()->c
: stm->msgFileBg->c;
} else { } else {
if (!bubbleReady) { if (!bubbleReady) {
opacity = bubbleProgress; opacity = bubbleProgress;
} }
color = (chosen color = (!chosen
? st->msgServiceFg() ? st->msgServiceBg()
: st->msgServiceBg())->c; : button.paid
? st->creditsBg2()
: st->msgServiceFg())->c;
} }
const auto fill = geometry.marginsAdded({ const auto fill = geometry.marginsAdded({
@ -451,7 +456,7 @@ void InlineList::paint(
? QPen(AdaptChosenServiceFg(st->msgServiceBg()->c)) ? QPen(AdaptChosenServiceFg(st->msgServiceBg()->c))
: st->msgServiceFg()) : st->msgServiceFg())
: !chosen : !chosen
? stm->msgServiceFg ? (button.paid ? st->creditsFg() : stm->msgServiceFg)
: context.outbg : context.outbg
? (context.selected() ? (context.selected()
? st->historyFileOutIconFgSelected() ? st->historyFileOutIconFgSelected()

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/send_credits_box.h" // CreditsEmojiSmall. #include "boxes/send_credits_box.h" // CreditsEmojiSmall.
#include "core/ui_integration.h" // MarkedTextContext. #include "core/ui_integration.h" // MarkedTextContext.
#include "data/components/credits.h" #include "data/components/credits.h"
#include "data/data_message_reactions.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "history/view/history_view_element.h" #include "history/view/history_view_element.h"
@ -27,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/layers/generic_box.h" #include "ui/layers/generic_box.h"
#include "ui/layers/show.h" #include "ui/layers/show.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/dynamic_thumbnails.h"
namespace Payments { namespace Payments {
namespace { namespace {
@ -167,10 +169,26 @@ void ShowPaidReactionDetails(
}; };
}); });
}; };
auto top = std::vector<Ui::PaidReactionTop>();
const auto &topPaid = item->topPaidReactions();
top.reserve(topPaid.size());
for (const auto &entry : topPaid) {
if (!entry.top) {
continue;
}
top.push_back({
.name = entry.peer->shortName(),
.photo = Ui::MakeUserpicThumbnail(entry.peer),
.count = int(entry.count),
});
}
ranges::sort(top, ranges::greater(), &Ui::PaidReactionTop::count);
state->selectBox = show->show(Ui::MakePaidReactionBox({ state->selectBox = show->show(Ui::MakePaidReactionBox({
.min = min, .min = min,
.max = max, .max = max,
.chosen = chosen, .chosen = chosen,
.top = std::move(top),
.channel = item->history()->peer->name(), .channel = item->history()->peer->name(),
.submit = std::move(submitText), .submit = std::move(submitText),
.balanceValue = session->credits().balanceValue(), .balanceValue = session->credits().balanceValue(),

View file

@ -8,10 +8,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "payments/ui/payments_reaction_box.h" #include "payments/ui/payments_reaction_box.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "ui/boxes/boost_box.h" // MakeBoostFeaturesBadge.
#include "ui/layers/generic_box.h" #include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/continuous_sliders.h" #include "ui/widgets/continuous_sliders.h"
#include "ui/dynamic_image.h"
#include "ui/painter.h"
#include "styles/style_chat.h"
#include "styles/style_credits.h" #include "styles/style_credits.h"
#include "styles/style_layers.h" #include "styles/style_layers.h"
#include "styles/style_premium.h" #include "styles/style_premium.h"
@ -27,6 +31,8 @@ namespace Settings {
namespace Ui { namespace Ui {
namespace { namespace {
constexpr auto kMaxTopPaidShown = 3;
void PaidReactionSlider( void PaidReactionSlider(
not_null<VerticalLayout*> container, not_null<VerticalLayout*> container,
int min, int min,
@ -35,9 +41,9 @@ void PaidReactionSlider(
Fn<void(int)> changed) { Fn<void(int)> changed) {
const auto top = st::boxTitleClose.height + st::creditsHistoryRightSkip; const auto top = st::boxTitleClose.height + st::creditsHistoryRightSkip;
const auto slider = container->add( const auto slider = container->add(
object_ptr<MediaSlider>(container, st::settingsScale), object_ptr<MediaSlider>(container, st::paidReactSlider),
st::boxRowPadding + QMargins(0, top, 0, 0)); st::boxRowPadding + QMargins(0, top, 0, 0));
slider->resize(slider->width(), st::settingsScale.seekSize.height()); slider->resize(slider->width(), st::paidReactSlider.seekSize.height());
slider->setPseudoDiscrete( slider->setPseudoDiscrete(
max + 1 - min, max + 1 - min,
[=](int index) { return min + index; }, [=](int index) { return min + index; },
@ -46,13 +52,145 @@ void PaidReactionSlider(
changed); changed);
} }
[[nodiscard]] QImage GenerateBadgeImage(int count) {
const auto text = Lang::FormatCountDecimal(count);
const auto length = st::chatSimilarBadgeFont->width(text);
const auto contents = length
+ st::chatSimilarLockedIcon.width();
const auto badge = QRect(
st::chatSimilarBadgePadding.left(),
st::chatSimilarBadgePadding.top(),
contents,
st::chatSimilarBadgeFont->height);
const auto rect = badge.marginsAdded(st::chatSimilarBadgePadding);
auto result = QImage(
rect.size() * style::DevicePixelRatio(),
QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(style::DevicePixelRatio());
result.fill(Qt::transparent);
auto q = QPainter(&result);
const auto &font = st::chatSimilarBadgeFont;
const auto textTop = badge.y() + font->ascent;
const auto icon = &st::chatSimilarLockedIcon;
const auto position = st::chatSimilarLockedIconPosition;
auto hq = PainterHighQualityEnabler(q);
q.setBrush(st::creditsBg3);
q.setPen(Qt::NoPen);
const auto radius = rect.height() / 2.;
q.drawRoundedRect(rect, radius, radius);
auto textLeft = 0;
if (icon) {
icon->paint(
q,
badge.x() + position.x(),
badge.y() + position.y(),
rect.width());
textLeft += position.x() + icon->width();
}
q.setFont(font);
q.setPen(st::premiumButtonFg);
q.drawText(textLeft, textTop, text);
q.end();
return result;
}
[[nodiscard]] not_null<Ui::RpWidget*> MakeTopReactor(
not_null<QWidget*> parent,
const PaidReactionTop &data) {
const auto result = Ui::CreateChild<Ui::RpWidget>(parent);
result->show();
struct State {
QImage badge;
Ui::Text::String name;
};
const auto state = result->lifetime().make_state<State>();
state->name.setText(st::defaultTextStyle, data.name);
const auto count = data.count;
const auto photo = data.photo;
photo->subscribeToUpdates([=] {
result->update();
});
style::PaletteChanged(
) | rpl::start_with_next([=] {
state->badge = QImage();
}, result->lifetime());
result->paintRequest() | rpl::start_with_next([=] {
auto p = Painter(result);
const auto left = (result->width() - st::paidReactTopUserpic) / 2;
p.drawImage(left, 0, photo->image(st::paidReactTopUserpic));
if (state->badge.isNull()) {
state->badge = GenerateBadgeImage(count);
}
const auto bwidth = state->badge.width()
/ state->badge.devicePixelRatio();
p.drawImage(
(result->width() - bwidth) / 2,
st::paidReactTopBadgeSkip,
state->badge);
p.setPen(st::windowFg);
const auto skip = st::normalFont->spacew;
const auto nameTop = st::paidReactTopNameSkip;
const auto available = result->width() - skip * 2;
state->name.draw(p, skip, nameTop, available, style::al_top);
}, result->lifetime());
return result;
}
void FillTopReactors(
not_null<VerticalLayout*> container,
std::vector<PaidReactionTop> top) {
container->add(
MakeBoostFeaturesBadge(
container,
tr::lng_paid_react_top_title(),
[](QRect) { return st::creditsBg3->b; }),
st::boxRowPadding + st::paidReactTopTitleMargin);
const auto height = st::paidReactTopNameSkip + st::normalFont->height;
const auto wrap = container->add(
object_ptr<Ui::FixedHeightWidget>(container, height),
st::paidReactTopMargin);
struct State {
std::vector<not_null<Ui::RpWidget*>> widgets;
};
const auto state = wrap->lifetime().make_state<State>();
const auto topCount = std::min(int(top.size()), kMaxTopPaidShown);
for (auto i = 0; i != topCount; ++i) {
state->widgets.push_back(MakeTopReactor(wrap, top[i]));
}
wrap->widthValue() | rpl::start_with_next([=](int width) {
const auto single = width / 4;
if (single <= st::paidReactTopUserpic) {
return;
}
auto left = (width - single * topCount) / 2;
for (const auto widget : state->widgets) {
widget->setGeometry(left, 0, single, height);
left += single;
}
}, wrap->lifetime());
}
} // namespace } // namespace
void PaidReactionsBox( void PaidReactionsBox(
not_null<GenericBox*> box, not_null<GenericBox*> box,
PaidReactionBoxArgs &&args) { PaidReactionBoxArgs &&args) {
box->setWidth(st::boxWideWidth); box->setWidth(st::boxWideWidth);
box->setStyle(st::boostBox); box->setStyle(st::paidReactBox);
box->setNoContentMargin(true); box->setNoContentMargin(true);
struct State { struct State {
@ -77,7 +215,7 @@ void PaidReactionsBox(
box, box,
tr::lng_paid_react_title(), tr::lng_paid_react_title(),
st::boostCenteredTitle), st::boostCenteredTitle),
st::boxRowPadding + QMargins(0, st::boostTitleSkip, 0, 0)); st::boxRowPadding + QMargins(0, st::paidReactTitleSkip, 0, 0));
box->addRow( box->addRow(
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(
box, box,
@ -87,7 +225,11 @@ void PaidReactionsBox(
Text::RichLangValue), Text::RichLangValue),
st::boostText), st::boostText),
(st::boxRowPadding (st::boxRowPadding
+ QMargins(0, st::boostTextSkip, 0, st::boostBottomSkip))); + QMargins(0, st::lineWidth, 0, st::boostBottomSkip)));
if (!args.top.empty()) {
FillTopReactors(box->verticalLayout(), std::move(args.top));
}
const auto button = box->addButton(rpl::single(QString()), [=] { const auto button = box->addButton(rpl::single(QString()), [=] {
args.send(state->chosen.current()); args.send(state->chosen.current());
@ -117,7 +259,7 @@ void PaidReactionsBox(
box->widthValue( box->widthValue(
) | rpl::start_with_next([=](int width) { ) | rpl::start_with_next([=](int width) {
const auto &padding = st::boostBox.buttonPadding; const auto &padding = st::paidReactBox.buttonPadding;
button->resizeToWidth(width button->resizeToWidth(width
- padding.left() - padding.left()
- padding.right()); - padding.right());

View file

@ -13,17 +13,26 @@ namespace Ui {
class BoxContent; class BoxContent;
class GenericBox; class GenericBox;
class DynamicImage;
struct TextWithContext { struct TextWithContext {
TextWithEntities text; TextWithEntities text;
std::any context; std::any context;
}; };
struct PaidReactionTop {
QString name;
std::shared_ptr<DynamicImage> photo;
int count = 0;
};
struct PaidReactionBoxArgs { struct PaidReactionBoxArgs {
int min = 0; int min = 0;
int max = 0; int max = 0;
int chosen = 0; int chosen = 0;
std::vector<PaidReactionTop> top;
QString channel; QString channel;
Fn<rpl::producer<TextWithContext>(rpl::producer<int> amount)> submit; Fn<rpl::producer<TextWithContext>(rpl::producer<int> amount)> submit;
rpl::producer<uint64> balanceValue; rpl::producer<uint64> balanceValue;

View file

@ -111,48 +111,13 @@ namespace {
[[nodiscard]] object_ptr<Ui::FlatLabel> MakeFeaturesBadge( [[nodiscard]] object_ptr<Ui::FlatLabel> MakeFeaturesBadge(
not_null<QWidget*> parent, not_null<QWidget*> parent,
rpl::producer<QString> text) { rpl::producer<QString> text) {
auto result = object_ptr<Ui::FlatLabel>( return MakeBoostFeaturesBadge(parent, std::move(text), [](QRect rect) {
parent,
std::move(text),
st::boostLevelBadge);
const auto label = result.data();
label->show();
label->paintRequest() | rpl::start_with_next([=] {
const auto size = label->textMaxWidth();
const auto rect = QRect(
(label->width() - size) / 2,
st::boostLevelBadge.margin.top(),
size,
st::boostLevelBadge.style.font->height
).marginsAdded(st::boostLevelBadge.margin);
auto p = QPainter(label);
auto hq = PainterHighQualityEnabler(p);
auto gradient = QLinearGradient( auto gradient = QLinearGradient(
rect.topLeft(), rect.topLeft(),
rect.topRight()); rect.topRight());
gradient.setStops(Ui::Premium::GiftGradientStops()); gradient.setStops(Ui::Premium::GiftGradientStops());
p.setBrush(gradient); return QBrush(gradient);
p.setPen(Qt::NoPen); });
p.drawRoundedRect(rect, rect.height() / 2., rect.height() / 2.);
const auto &lineFg = st::windowBgRipple;
const auto line = st::boostLevelBadgeLine;
const auto top = st::boostLevelBadge.margin.top()
+ ((st::boostLevelBadge.style.font->height - line) / 2);
const auto left = 0;
const auto skip = st::boostLevelBadgeSkip;
if (const auto right = rect.x() - skip; right > left) {
p.fillRect(left, top, right - left, line, lineFg);
}
const auto right = label->width();
if (const auto left = rect.x() + rect.width() + skip
; left < right) {
p.fillRect(left, top, right - left, line, lineFg);
}
}, label->lifetime());
return result;
} }
void AddFeaturesList( void AddFeaturesList(
@ -885,4 +850,48 @@ void FillBoostLimit(
limitLinePadding); limitLinePadding);
} }
object_ptr<Ui::FlatLabel> MakeBoostFeaturesBadge(
not_null<QWidget*> parent,
rpl::producer<QString> text,
Fn<QBrush(QRect)> bg) {
auto result = object_ptr<Ui::FlatLabel>(
parent,
std::move(text),
st::boostLevelBadge);
const auto label = result.data();
label->show();
label->paintRequest() | rpl::start_with_next([=] {
const auto size = label->textMaxWidth();
const auto rect = QRect(
(label->width() - size) / 2,
st::boostLevelBadge.margin.top(),
size,
st::boostLevelBadge.style.font->height
).marginsAdded(st::boostLevelBadge.margin);
auto p = QPainter(label);
auto hq = PainterHighQualityEnabler(p);
p.setBrush(bg(rect));
p.setPen(Qt::NoPen);
p.drawRoundedRect(rect, rect.height() / 2., rect.height() / 2.);
const auto &lineFg = st::windowBgRipple;
const auto line = st::boostLevelBadgeLine;
const auto top = st::boostLevelBadge.margin.top()
+ ((st::boostLevelBadge.style.font->height - line) / 2);
const auto left = 0;
const auto skip = st::boostLevelBadgeSkip;
if (const auto right = rect.x() - skip; right > left) {
p.fillRect(left, top, right - left, line, lineFg);
}
const auto right = label->width();
if (const auto left = rect.x() + rect.width() + skip
; left < right) {
p.fillRect(left, top, right - left, line, lineFg);
}
}, label->lifetime());
return result;
}
} // namespace Ui } // namespace Ui

View file

@ -17,6 +17,7 @@ class Show;
class RpWidget; class RpWidget;
class GenericBox; class GenericBox;
class VerticalLayout; class VerticalLayout;
class FlatLabel;
struct BoostCounters { struct BoostCounters {
int level = 0; int level = 0;
@ -129,4 +130,9 @@ void FillBoostLimit(
rpl::producer<BoostCounters> data, rpl::producer<BoostCounters> data,
style::margins limitLinePadding); style::margins limitLinePadding);
[[nodiscard]] object_ptr<Ui::FlatLabel> MakeBoostFeaturesBadge(
not_null<QWidget*> parent,
rpl::producer<QString> text,
Fn<QBrush(QRect)> bg);
} // namespace Ui } // namespace Ui

View file

@ -46,7 +46,7 @@ creditsBoxButtonLabel: FlatLabel(defaultFlatLabel) {
} }
starIconSmall: icon{{ "payments/small_star", windowFg }}; starIconSmall: icon{{ "payments/small_star", windowFg }};
starIconSmallPadding: margins(0px, -2px, 0px, 0px); starIconSmallPadding: margins(0px, -3px, 0px, 0px);
creditsHistoryEntryTypeAds: icon {{ "folders/folders_channels", premiumButtonFg }}; creditsHistoryEntryTypeAds: icon {{ "folders/folders_channels", premiumButtonFg }};

View file

@ -340,13 +340,13 @@ showOrBox: Box(boostBox) {
boostBoxMaxHeight: 512px; boostBoxMaxHeight: 512px;
boostLevelBadge: FlatLabel(defaultFlatLabel) { boostLevelBadge: FlatLabel(defaultFlatLabel) {
margin: margins(12px, 4px, 12px, 4px); margin: margins(12px, 4px, 12px, 5px);
style: semiboldTextStyle; style: semiboldTextStyle;
textFg: premiumButtonFg; textFg: premiumButtonFg;
align: align(top); align: align(top);
} }
boostLevelBadgePadding: margins(30px, 12px, 32px, 12px); boostLevelBadgePadding: margins(30px, 12px, 32px, 12px);
boostLevelBadgeSkip: 8px; boostLevelBadgeSkip: 12px;
boostLevelBadgeLine: 1px; boostLevelBadgeLine: 1px;
boostFeatureLabel: FlatLabel(defaultFlatLabel) { boostFeatureLabel: FlatLabel(defaultFlatLabel) {
@ -365,3 +365,29 @@ boostFeatureName: icon{{ "settings/premium/features/feature_color_names", window
boostFeatureStories: icon{{ "settings/premium/features/feature_stories", windowBgActive }}; boostFeatureStories: icon{{ "settings/premium/features/feature_stories", windowBgActive }};
boostFeatureTranscribe: icon{{ "settings/premium/features/feature_voice", windowBgActive }}; boostFeatureTranscribe: icon{{ "settings/premium/features/feature_voice", windowBgActive }};
boostFeatureOffSponsored: icon{{ "settings/premium/features/feature_off_sponsored", windowBgActive }}; boostFeatureOffSponsored: icon{{ "settings/premium/features/feature_off_sponsored", windowBgActive }};
paidReactTitleSkip: 23px;
paidReactTopTitleMargin: margins(10px, 26px, 10px, 12px);
paidReactTopMargin: margins(0px, 12px, 0px, 11px);
paidReactTopUserpic: 42px;
paidReactTopNameSkip: 47px;
paidReactTopBadgeSkip: 32px;
paidReactSlider: MediaSlider(defaultContinuousSlider) {
activeFg: creditsBg3;
inactiveFg: creditsBg2;
activeFgOver: creditsBg3;
inactiveFgOver: creditsBg2;
activeFgDisabled: creditsBg3;
inactiveFgDisabled: creditsBg2;
width: 6px;
seekSize: size(16px, 16px);
}
paidReactBox: Box(boostBox) {
buttonPadding: margins(22px, 22px, 22px, 22px);
buttonHeight: 42px;
button: RoundButton(defaultActiveButton) {
height: 42px;
textTop: 12px;
font: font(13px semibold);
}
}

@ -1 +1 @@
Subproject commit 8db5d1aa533334c75ed2598ecf3607768ae9b418 Subproject commit a5b1266a8c340ed916466a83cbbc5793471c2438