diff --git a/Telegram/SourceFiles/settings/settings_premium.cpp b/Telegram/SourceFiles/settings/settings_premium.cpp
index b515e8fa1..ba0acc981 100644
--- a/Telegram/SourceFiles/settings/settings_premium.cpp
+++ b/Telegram/SourceFiles/settings/settings_premium.cpp
@@ -33,10 +33,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "settings/settings_premium.h"
#include "ui/abstract_button.h"
#include "ui/basic_click_handlers.h"
-#include "ui/color_contrast.h"
#include "ui/effects/gradient.h"
#include "ui/effects/premium_graphics.h"
#include "ui/effects/premium_stars_colored.h"
+#include "ui/effects/premium_top_bar.h"
#include "ui/layers/generic_box.h"
#include "ui/text/format_values.h"
#include "ui/text/text_utilities.h"
@@ -67,41 +67,6 @@ namespace {
using SectionCustomTopBarData = Info::Settings::SectionCustomTopBarData;
-constexpr auto kBodyAnimationPart = 0.90;
-constexpr auto kTitleAdditionalScale = 0.15;
-constexpr auto kMinAcceptableContrast = 4.5; // 1.14;
-
-[[nodiscard]] QString Svg() {
- return u":/gui/icons/settings/star.svg"_q;
-}
-
-[[nodiscard]] QByteArray ColorizedSvg() {
- auto f = QFile(Svg());
- if (!f.open(QIODevice::ReadOnly)) {
- return QByteArray();
- }
- auto content = qs(f.readAll());
- auto stops = [] {
- auto s = QString();
- for (const auto &stop : Ui::Premium::ButtonGradientStops()) {
- s += QString("")
- .arg(QString::number(stop.first), stop.second.name());
- }
- return s;
- }();
- const auto color = QString("%5")
- .arg(0)
- .arg(1)
- .arg(1)
- .arg(0)
- .arg(std::move(stops));
- content.replace(u"gradientPlaceholder"_q, color);
- content.replace(u"#fff"_q, u"url(#Gradient2)"_q);
- f.close();
- return content.toUtf8();
-}
-
[[nodiscard]] Data::SubscriptionOptions SubscriptionOptionsForRows(
Data::SubscriptionOptions result) {
for (auto &option : result) {
@@ -412,85 +377,6 @@ void SendScreenAccept(not_null controller) {
MTP_jsonNull());
}
-class TopBarAbstract : public Ui::RpWidget {
-public:
- using Ui::RpWidget::RpWidget;
-
- void setRoundEdges(bool value);
-
- virtual void setPaused(bool paused) = 0;
- virtual void setTextPosition(int x, int y) = 0;
-
- [[nodiscard]] virtual rpl::producer additionalHeight() const = 0;
-
-protected:
- void paintEdges(QPainter &p, const QBrush &brush) const;
- void paintEdges(QPainter &p) const;
-
- [[nodiscard]] QRectF starRect(
- float64 topProgress,
- float64 sizeProgress) const;
-
- [[nodiscard]] bool isDark() const;
- void computeIsDark();
-
-private:
- bool _roundEdges = true;
- bool _isDark = false;
-
-};
-
-void TopBarAbstract::setRoundEdges(bool value) {
- _roundEdges = value;
- update();
-}
-
-void TopBarAbstract::paintEdges(QPainter &p, const QBrush &brush) const {
- const auto r = rect();
- if (_roundEdges) {
- PainterHighQualityEnabler hq(p);
- const auto radius = st::boxRadius;
- p.setPen(Qt::NoPen);
- p.setBrush(brush);
- p.drawRoundedRect(
- r + QMargins{ 0, 0, 0, radius + 1 },
- radius,
- radius);
- } else {
- p.fillRect(r, brush);
- }
-}
-
-void TopBarAbstract::paintEdges(QPainter &p) const {
- paintEdges(p, st::boxBg);
- if (isDark()) {
- paintEdges(p, st::shadowFg);
- paintEdges(p, st::shadowFg);
- }
-}
-
-QRectF TopBarAbstract::starRect(
- float64 topProgress,
- float64 sizeProgress) const {
- const auto starSize = st::settingsPremiumStarSize * sizeProgress;
- return QRectF(
- QPointF(
- (width() - starSize.width()) / 2,
- st::settingsPremiumStarTopSkip * topProgress),
- starSize);
-};
-
-bool TopBarAbstract::isDark() const {
- return _isDark;
-}
-
-void TopBarAbstract::computeIsDark() {
- const auto contrast = Ui::CountContrast(
- st::boxBg->c,
- st::premiumButtonFg->c);
- _isDark = (contrast > kMinAcceptableContrast);
-}
-
class EmojiStatusTopBar final {
public:
EmojiStatusTopBar(
@@ -583,7 +469,7 @@ void EmojiStatusTopBar::paint(QPainter &p) {
}
}
-class TopBarUser final : public TopBarAbstract {
+class TopBarUser final : public Ui::Premium::TopBarAbstract {
public:
TopBarUser(
not_null parent,
@@ -674,38 +560,8 @@ TopBarUser::TopBarUser(
HistoryView::Sticker::EmojiSize());
_imageStar = QImage();
} else {
- auto svg = QSvgRenderer(Svg());
-
- const auto size = _starRect.size().toSize();
- auto frame = QImage(
- size * style::DevicePixelRatio(),
- QImage::Format_ARGB32_Premultiplied);
- frame.setDevicePixelRatio(style::DevicePixelRatio());
-
- auto mask = frame;
- mask.fill(Qt::transparent);
- {
- auto p = QPainter(&mask);
- auto gradient = QLinearGradient(
- 0,
- size.height(),
- size.width(),
- 0);
- gradient.setStops(Ui::Premium::ButtonGradientStops());
- p.setPen(Qt::NoPen);
- p.setBrush(gradient);
- p.drawRect(0, 0, size.width(), size.height());
- }
- frame.fill(Qt::transparent);
- {
- auto q = QPainter(&frame);
- svg.render(&q, QRect(QPoint(), size));
- q.setCompositionMode(QPainter::CompositionMode_SourceIn);
- q.drawImage(0, 0, mask);
- }
- _imageStar = std::move(frame);
-
_emojiStatus = nullptr;
+ _imageStar = Ui::Premium::GenerateStarForLightTopBar(_starRect);
}
updateTitle(document, { name }, controller);
@@ -925,194 +781,6 @@ void TopBarUser::resizeEvent(QResizeEvent *e) {
}
}
-class TopBar final : public TopBarAbstract {
-public:
- TopBar(
- not_null parent,
- not_null controller,
- rpl::producer title,
- rpl::producer about);
-
- void setPaused(bool paused) override;
- void setTextPosition(int x, int y) override;
-
- rpl::producer additionalHeight() const override;
-
-protected:
- void paintEvent(QPaintEvent *e) override;
- void resizeEvent(QResizeEvent *e) override;
-
-private:
- const style::font &_titleFont;
- const style::margins &_titlePadding;
- object_ptr _about;
- Ui::Premium::ColoredMiniStars _ministars;
- QSvgRenderer _star;
-
- struct {
- float64 top = 0.;
- float64 body = 0.;
- float64 title = 0.;
- float64 scaleTitle = 0.;
- } _progress;
-
- QRectF _starRect;
-
- QPoint _titlePosition;
- QPainterPath _titlePath;
-
-};
-
-TopBar::TopBar(
- not_null parent,
- not_null controller,
- rpl::producer title,
- rpl::producer about)
-: TopBarAbstract(parent)
-, _titleFont(st::boxTitle.style.font)
-, _titlePadding(st::settingsPremiumTitlePadding)
-, _about(this, std::move(about), st::settingsPremiumAbout)
-, _ministars(this) {
- std::move(
- title
- ) | rpl::start_with_next([=](QString text) {
- _titlePath = QPainterPath();
- _titlePath.addText(0, _titleFont->ascent, _titleFont, text);
- update();
- }, lifetime());
-
- _about->setClickHandlerFilter([=](
- const ClickHandlerPtr &handler,
- Qt::MouseButton button) {
- ActivateClickHandler(_about, handler, {
- button,
- QVariant::fromValue(ClickHandlerContext{
- .sessionWindow = base::make_weak(controller),
- .botStartAutoSubmit = true,
- })
- });
- return false;
- });
-
- rpl::single() | rpl::then(
- style::PaletteChanged()
- ) | rpl::start_with_next([=] {
- TopBarAbstract::computeIsDark();
-
- if (!TopBarAbstract::isDark()) {
- _star.load(Svg());
- _ministars.setColorOverride(st::premiumButtonFg->c);
- } else {
- _star.load(ColorizedSvg());
- _ministars.setColorOverride(std::nullopt);
- }
- auto event = QResizeEvent(size(), size());
- resizeEvent(&event);
- }, lifetime());
-}
-
-void TopBar::setPaused(bool paused) {
- _ministars.setPaused(paused);
-}
-
-void TopBar::setTextPosition(int x, int y) {
- _titlePosition = { x, y };
-}
-
-rpl::producer TopBar::additionalHeight() const {
- return _about->heightValue(
- ) | rpl::map([l = st::settingsPremiumAbout.style.lineHeight](int height) {
- return std::max(height - l * 2, 0);
- });
-}
-
-void TopBar::resizeEvent(QResizeEvent *e) {
- const auto progress = (e->size().height() - minimumHeight())
- / float64(maximumHeight() - minimumHeight());
- _progress.top = 1. -
- std::clamp(
- (1. - progress) / kBodyAnimationPart,
- 0.,
- 1.);
- _progress.body = _progress.top;
- _progress.title = 1. - progress;
- _progress.scaleTitle = 1. + kTitleAdditionalScale * progress;
-
- _ministars.setCenter(starRect(_progress.top, 1.).toRect());
-
- _starRect = starRect(_progress.top, _progress.body);
-
- const auto &padding = st::boxRowPadding;
- const auto availableWidth = width() - padding.left() - padding.right();
- const auto titleTop = _starRect.top()
- + _starRect.height()
- + _titlePadding.top();
- const auto titlePathRect = _titlePath.boundingRect();
- const auto aboutTop = titleTop
- + titlePathRect.height()
- + _titlePadding.bottom();
- _about->resizeToWidth(availableWidth);
- _about->moveToLeft(padding.left(), aboutTop);
- _about->setOpacity(_progress.body);
-
- Ui::RpWidget::resizeEvent(e);
-}
-
-void TopBar::paintEvent(QPaintEvent *e) {
- auto p = QPainter(this);
-
- p.fillRect(e->rect(), Qt::transparent);
-
- const auto r = rect();
-
- if (!TopBarAbstract::isDark()) {
- const auto gradientPointTop = r.height() / 3. * 2.;
- auto gradient = QLinearGradient(
- QPointF(0, gradientPointTop),
- QPointF(r.width(), r.height() - gradientPointTop));
- gradient.setStops(Ui::Premium::ButtonGradientStops());
-
- TopBarAbstract::paintEdges(p, gradient);
- } else {
- TopBarAbstract::paintEdges(p);
- }
-
- p.setOpacity(_progress.body);
- p.translate(_starRect.center());
- p.scale(_progress.body, _progress.body);
- p.translate(-_starRect.center());
- if (_progress.top) {
- _ministars.paint(p);
- }
- p.resetTransform();
-
- _star.render(&p, _starRect);
-
- p.setPen(st::premiumButtonFg);
-
- const auto titlePathRect = _titlePath.boundingRect();
-
- // Title.
- PainterHighQualityEnabler hq(p);
- p.setOpacity(1.);
- p.setFont(_titleFont);
- const auto fullStarRect = starRect(1., 1.);
- const auto fullTitleTop = fullStarRect.top()
- + fullStarRect.height()
- + _titlePadding.top();
- p.translate(
- anim::interpolate(
- (width() - titlePathRect.width()) / 2,
- _titlePosition.x(),
- _progress.title),
- anim::interpolate(fullTitleTop, _titlePosition.y(), _progress.title));
-
- p.translate(titlePathRect.center());
- p.scale(_progress.scaleTitle, _progress.scaleTitle);
- p.translate(-titlePathRect.center());
- p.fillPath(_titlePath, st::premiumButtonFg);
-}
-
class Premium : public Section {
public:
Premium(
@@ -1488,7 +1156,7 @@ QPointer Premium::createPinnedToTop(
return nullptr;
}();
- const auto content = [&]() -> TopBarAbstract* {
+ const auto content = [&]() -> Ui::Premium::TopBarAbstract* {
if (peerWithPremium) {
return Ui::CreateChild(
parent.get(),
@@ -1496,9 +1164,16 @@ QPointer Premium::createPinnedToTop(
peerWithPremium,
_showFinished.events());
}
- return Ui::CreateChild(
+ const auto weak = base::make_weak(_controller);
+ const auto clickContextOther = [=] {
+ return QVariant::fromValue(ClickHandlerContext{
+ .sessionWindow = weak,
+ .botStartAutoSubmit = true,
+ });
+ };
+ return Ui::CreateChild(
parent.get(),
- _controller,
+ clickContextOther,
std::move(title),
std::move(about));
}();
diff --git a/Telegram/SourceFiles/ui/effects/premium_top_bar.cpp b/Telegram/SourceFiles/ui/effects/premium_top_bar.cpp
new file mode 100644
index 000000000..ba8ed602b
--- /dev/null
+++ b/Telegram/SourceFiles/ui/effects/premium_top_bar.cpp
@@ -0,0 +1,315 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#include "ui/effects/premium_top_bar.h"
+
+#include "ui/color_contrast.h"
+#include "ui/painter.h"
+#include "ui/effects/premium_graphics.h"
+#include "ui/widgets/labels.h"
+#include "ui/wrap/fade_wrap.h"
+#include "styles/style_layers.h"
+#include "styles/style_settings.h"
+
+namespace Ui::Premium {
+namespace {
+
+constexpr auto kBodyAnimationPart = 0.90;
+constexpr auto kTitleAdditionalScale = 0.15;
+constexpr auto kMinAcceptableContrast = 4.5; // 1.14;
+
+} // namespace
+
+QString Svg() {
+ return u":/gui/icons/settings/star.svg"_q;
+}
+
+QByteArray ColorizedSvg() {
+ auto f = QFile(Svg());
+ if (!f.open(QIODevice::ReadOnly)) {
+ return QByteArray();
+ }
+ auto content = QString::fromUtf8(f.readAll());
+ auto stops = [] {
+ auto s = QString();
+ for (const auto &stop : Ui::Premium::ButtonGradientStops()) {
+ s += QString("")
+ .arg(QString::number(stop.first), stop.second.name());
+ }
+ return s;
+ }();
+ const auto color = QString("%5")
+ .arg(0)
+ .arg(1)
+ .arg(1)
+ .arg(0)
+ .arg(std::move(stops));
+ content.replace(u"gradientPlaceholder"_q, color);
+ content.replace(u"#fff"_q, u"url(#Gradient2)"_q);
+ f.close();
+ return content.toUtf8();
+}
+
+QImage GenerateStarForLightTopBar(QRectF rect) {
+ auto svg = QSvgRenderer(Ui::Premium::Svg());
+
+ const auto size = rect.size().toSize();
+ auto frame = QImage(
+ size * style::DevicePixelRatio(),
+ QImage::Format_ARGB32_Premultiplied);
+ frame.setDevicePixelRatio(style::DevicePixelRatio());
+
+ auto mask = frame;
+ mask.fill(Qt::transparent);
+ {
+ auto p = QPainter(&mask);
+ auto gradient = QLinearGradient(
+ 0,
+ size.height(),
+ size.width(),
+ 0);
+ gradient.setStops(Ui::Premium::ButtonGradientStops());
+ p.setPen(Qt::NoPen);
+ p.setBrush(gradient);
+ p.drawRect(0, 0, size.width(), size.height());
+ }
+ frame.fill(Qt::transparent);
+ {
+ auto q = QPainter(&frame);
+ svg.render(&q, QRect(QPoint(), size));
+ q.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ q.drawImage(0, 0, mask);
+ }
+ return frame;
+}
+
+void TopBarAbstract::setRoundEdges(bool value) {
+ _roundEdges = value;
+ update();
+}
+
+void TopBarAbstract::paintEdges(QPainter &p, const QBrush &brush) const {
+ const auto r = rect();
+ if (_roundEdges) {
+ PainterHighQualityEnabler hq(p);
+ const auto radius = st::boxRadius;
+ p.setPen(Qt::NoPen);
+ p.setBrush(brush);
+ p.drawRoundedRect(
+ r + QMargins{ 0, 0, 0, radius + 1 },
+ radius,
+ radius);
+ } else {
+ p.fillRect(r, brush);
+ }
+}
+
+void TopBarAbstract::paintEdges(QPainter &p) const {
+ paintEdges(p, st::boxBg);
+ if (isDark()) {
+ paintEdges(p, st::shadowFg);
+ paintEdges(p, st::shadowFg);
+ }
+}
+
+QRectF TopBarAbstract::starRect(
+ float64 topProgress,
+ float64 sizeProgress) const {
+ const auto starSize = st::settingsPremiumStarSize * sizeProgress;
+ return QRectF(
+ QPointF(
+ (width() - starSize.width()) / 2,
+ st::settingsPremiumStarTopSkip * topProgress),
+ starSize);
+};
+
+bool TopBarAbstract::isDark() const {
+ return _isDark;
+}
+
+void TopBarAbstract::computeIsDark() {
+ const auto contrast = CountContrast(
+ st::boxBg->c,
+ st::premiumButtonFg->c);
+ _isDark = (contrast > kMinAcceptableContrast);
+}
+
+TopBar::TopBar(
+ not_null parent,
+ Fn clickContextOther,
+ rpl::producer title,
+ rpl::producer about,
+ bool light)
+: TopBarAbstract(parent)
+, _light(light)
+, _titleFont(st::boxTitle.style.font)
+, _titlePadding(st::settingsPremiumTitlePadding)
+, _about(
+ this,
+ std::move(about),
+ _light ? st::settingsPremiumUserAbout : st::settingsPremiumAbout)
+, _ministars(this) {
+ std::move(
+ title
+ ) | rpl::start_with_next([=](QString text) {
+ _titlePath = QPainterPath();
+ _titlePath.addText(0, _titleFont->ascent, _titleFont, text);
+ update();
+ }, lifetime());
+
+ if (clickContextOther) {
+ _about->setClickHandlerFilter([=](
+ const ClickHandlerPtr &handler,
+ Qt::MouseButton button) {
+ ActivateClickHandler(_about, handler, {
+ button,
+ clickContextOther()
+ });
+ return false;
+ });
+ }
+
+ rpl::single() | rpl::then(
+ style::PaletteChanged()
+ ) | rpl::start_with_next([=] {
+ TopBarAbstract::computeIsDark();
+
+ if (!_light && !TopBarAbstract::isDark()) {
+ _star.load(Svg());
+ _ministars.setColorOverride(st::premiumButtonFg->c);
+ } else {
+ _star.load(ColorizedSvg());
+ _ministars.setColorOverride(std::nullopt);
+ }
+ auto event = QResizeEvent(size(), size());
+ resizeEvent(&event);
+ }, lifetime());
+
+ if (_light) {
+ const auto smallTopShadow = CreateChild(this);
+ smallTopShadow->setDuration(st::fadeWrapDuration);
+ sizeValue(
+ ) | rpl::start_with_next([=](QSize size) {
+ smallTopShadow->resizeToWidth(size.width());
+ smallTopShadow->moveToLeft(
+ 0,
+ height() - smallTopShadow->height());
+ const auto shown = (minimumHeight() * 2 > size.height());
+ smallTopShadow->toggle(shown, anim::type::normal);
+ }, lifetime());
+ }
+}
+
+TopBar::~TopBar() = default;
+
+void TopBar::setPaused(bool paused) {
+ _ministars.setPaused(paused);
+}
+
+void TopBar::setTextPosition(int x, int y) {
+ _titlePosition = { x, y };
+}
+
+rpl::producer TopBar::additionalHeight() const {
+ return _about->heightValue(
+ ) | rpl::map([l = st::settingsPremiumAbout.style.lineHeight](int height) {
+ return std::max(height - l * 2, 0);
+ });
+}
+
+void TopBar::resizeEvent(QResizeEvent *e) {
+ const auto progress = (e->size().height() - minimumHeight())
+ / float64(maximumHeight() - minimumHeight());
+ _progress.top = 1. -
+ std::clamp(
+ (1. - progress) / kBodyAnimationPart,
+ 0.,
+ 1.);
+ _progress.body = _progress.top;
+ _progress.title = 1. - progress;
+ _progress.scaleTitle = 1. + kTitleAdditionalScale * progress;
+
+ _ministars.setCenter(starRect(_progress.top, 1.).toRect());
+
+ _starRect = starRect(_progress.top, _progress.body);
+
+ const auto &padding = st::boxRowPadding;
+ const auto availableWidth = width() - padding.left() - padding.right();
+ const auto titleTop = _starRect.top()
+ + _starRect.height()
+ + _titlePadding.top();
+ const auto titlePathRect = _titlePath.boundingRect();
+ const auto aboutTop = titleTop
+ + titlePathRect.height()
+ + _titlePadding.bottom();
+ _about->resizeToWidth(availableWidth);
+ _about->moveToLeft(padding.left(), aboutTop);
+ _about->setOpacity(_progress.body);
+
+ RpWidget::resizeEvent(e);
+}
+
+void TopBar::paintEvent(QPaintEvent *e) {
+ auto p = QPainter(this);
+
+ p.fillRect(e->rect(), Qt::transparent);
+
+ const auto r = rect();
+
+ if (!_light && !TopBarAbstract::isDark()) {
+ const auto gradientPointTop = r.height() / 3. * 2.;
+ auto gradient = QLinearGradient(
+ QPointF(0, gradientPointTop),
+ QPointF(r.width(), r.height() - gradientPointTop));
+ gradient.setStops(ButtonGradientStops());
+
+ TopBarAbstract::paintEdges(p, gradient);
+ } else {
+ TopBarAbstract::paintEdges(p);
+ }
+
+ p.setOpacity(_progress.body);
+ p.translate(_starRect.center());
+ p.scale(_progress.body, _progress.body);
+ p.translate(-_starRect.center());
+ if (_progress.top) {
+ _ministars.paint(p);
+ }
+ p.resetTransform();
+
+ _star.render(&p, _starRect);
+
+ const auto color = _light
+ ? st::settingsPremiumUserTitle.textFg
+ : st::premiumButtonFg;
+ p.setPen(color);
+
+ const auto titlePathRect = _titlePath.boundingRect();
+
+ // Title.
+ PainterHighQualityEnabler hq(p);
+ p.setOpacity(1.);
+ p.setFont(_titleFont);
+ const auto fullStarRect = starRect(1., 1.);
+ const auto fullTitleTop = fullStarRect.top()
+ + fullStarRect.height()
+ + _titlePadding.top();
+ p.translate(
+ anim::interpolate(
+ (width() - titlePathRect.width()) / 2,
+ _titlePosition.x(),
+ _progress.title),
+ anim::interpolate(fullTitleTop, _titlePosition.y(), _progress.title));
+
+ p.translate(titlePathRect.center());
+ p.scale(_progress.scaleTitle, _progress.scaleTitle);
+ p.translate(-titlePathRect.center());
+ p.fillPath(_titlePath, color);
+}
+
+} // namespace Ui::Premium
diff --git a/Telegram/SourceFiles/ui/effects/premium_top_bar.h b/Telegram/SourceFiles/ui/effects/premium_top_bar.h
new file mode 100644
index 000000000..0cef38dc5
--- /dev/null
+++ b/Telegram/SourceFiles/ui/effects/premium_top_bar.h
@@ -0,0 +1,93 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#pragma once
+
+#include "base/object_ptr.h"
+#include "ui/rp_widget.h"
+#include "ui/effects/premium_stars_colored.h"
+
+namespace Ui {
+class FlatLabel;
+} // namespace Ui
+
+namespace Ui::Premium {
+
+[[nodiscard]] QString Svg();
+[[nodiscard]] QByteArray ColorizedSvg();
+[[nodiscard]] QImage GenerateStarForLightTopBar(QRectF rect);
+
+class TopBarAbstract : public RpWidget {
+public:
+ using RpWidget::RpWidget;
+
+ void setRoundEdges(bool value);
+
+ virtual void setPaused(bool paused) = 0;
+ virtual void setTextPosition(int x, int y) = 0;
+
+ [[nodiscard]] virtual rpl::producer additionalHeight() const = 0;
+
+protected:
+ void paintEdges(QPainter &p, const QBrush &brush) const;
+ void paintEdges(QPainter &p) const;
+
+ [[nodiscard]] QRectF starRect(
+ float64 topProgress,
+ float64 sizeProgress) const;
+
+ [[nodiscard]] bool isDark() const;
+ void computeIsDark();
+
+private:
+ bool _roundEdges = true;
+ bool _isDark = false;
+
+};
+
+class TopBar final : public TopBarAbstract {
+public:
+ TopBar(
+ not_null parent,
+ Fn clickContextOther,
+ rpl::producer title,
+ rpl::producer about,
+ bool light = false);
+ ~TopBar();
+
+ void setPaused(bool paused) override;
+ void setTextPosition(int x, int y) override;
+
+ rpl::producer additionalHeight() const override;
+
+protected:
+ void paintEvent(QPaintEvent *e) override;
+ void resizeEvent(QResizeEvent *e) override;
+
+private:
+ const bool _light = false;
+ const style::font &_titleFont;
+ const style::margins &_titlePadding;
+ object_ptr _about;
+ ColoredMiniStars _ministars;
+ QSvgRenderer _star;
+
+ struct {
+ float64 top = 0.;
+ float64 body = 0.;
+ float64 title = 0.;
+ float64 scaleTitle = 0.;
+ } _progress;
+
+ QRectF _starRect;
+
+ QPoint _titlePosition;
+ QPainterPath _titlePath;
+
+};
+
+} // namespace Ui::Premium
diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake
index f7617ca22..7e2955ac1 100644
--- a/Telegram/cmake/td_ui.cmake
+++ b/Telegram/cmake/td_ui.cmake
@@ -279,6 +279,8 @@ PRIVATE
ui/effects/premium_stars.h
ui/effects/premium_stars_colored.cpp
ui/effects/premium_stars_colored.h
+ ui/effects/premium_top_bar.cpp
+ ui/effects/premium_top_bar.h
ui/effects/round_checkbox.cpp
ui/effects/round_checkbox.h
ui/effects/scroll_content_shadow.cpp