Show premium stickers lock icon.

This commit is contained in:
John Preston 2022-05-20 18:57:01 +04:00
parent 5cd065ef6b
commit 853cafe195
19 changed files with 137 additions and 41 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -345,7 +345,7 @@ void EditCaptionBox::setupEditEventHandler() {
} }
return true; return true;
}; };
const auto premium = _controller->session().user()->isPremium(); const auto premium = _controller->session().premium();
auto list = Storage::PreparedFileFromFilesDialog( auto list = Storage::PreparedFileFromFilesDialog(
std::move(result), std::move(result),
checkResult, checkResult,
@ -524,7 +524,7 @@ void EditCaptionBox::updateEmojiPanelGeometry() {
} }
bool EditCaptionBox::fileFromClipboard(not_null<const QMimeData*> data) { bool EditCaptionBox::fileFromClipboard(not_null<const QMimeData*> data) {
const auto premium = _controller->session().user()->isPremium(); const auto premium = _controller->session().premium();
return setPreparedList(ListFromMimeData(data, premium)); return setPreparedList(ListFromMimeData(data, premium));
} }

View file

@ -104,7 +104,7 @@ private:
} }
[[nodiscard]] int Limit(not_null<Main::Session*> session) { [[nodiscard]] int Limit(not_null<Main::Session*> session) {
const auto premium = session->user()->isPremium(); const auto premium = session->premium();
return Limit(session, return Limit(session,
(premium (premium
? "dialog_filters_chats_limit_premium" ? "dialog_filters_chats_limit_premium"

View file

@ -454,7 +454,7 @@ void SimplePinsLimitBox(
int limitDefault, int limitDefault,
const QString &keyPremium, const QString &keyPremium,
int limitPremium) { int limitPremium) {
const auto premium = session->user()->isPremium(); const auto premium = session->premium();
const auto defaultLimit = Limit(session, keyDefault, limitDefault); const auto defaultLimit = Limit(session, keyDefault, limitDefault);
const auto premiumLimit = Limit(session, keyPremium, limitPremium); const auto premiumLimit = Limit(session, keyPremium, limitPremium);
@ -489,7 +489,7 @@ void SimplePinsLimitBox(
void ChannelsLimitBox( void ChannelsLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session) { not_null<Main::Session*> session) {
const auto premium = session->user()->isPremium(); const auto premium = session->premium();
const auto defaultLimit = Limit(session, "channels_limit_default", 500); const auto defaultLimit = Limit(session, "channels_limit_default", 500);
const auto premiumLimit = Limit(session, "channels_limit_premium", 1000); const auto premiumLimit = Limit(session, "channels_limit_premium", 1000);
@ -574,7 +574,7 @@ void PublicLinksLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Window::SessionNavigation*> navigation) { not_null<Window::SessionNavigation*> navigation) {
const auto session = &navigation->session(); const auto session = &navigation->session();
const auto premium = session->user()->isPremium(); const auto premium = session->premium();
const auto defaultLimit = Limit( const auto defaultLimit = Limit(
session, session,
@ -639,7 +639,7 @@ void PublicLinksLimitBox(
void FilterChatsLimitBox( void FilterChatsLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session) { not_null<Main::Session*> session) {
const auto premium = session->user()->isPremium(); const auto premium = session->premium();
const auto defaultLimit = Limit( const auto defaultLimit = Limit(
session, session,
@ -679,7 +679,7 @@ void FilterChatsLimitBox(
void FiltersLimitBox( void FiltersLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session) { not_null<Main::Session*> session) {
const auto premium = session->user()->isPremium(); const auto premium = session->premium();
const auto defaultLimit = Limit( const auto defaultLimit = Limit(
session, session,
@ -754,7 +754,7 @@ void PinsLimitBox(
void CaptionLimitBox( void CaptionLimitBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Main::Session*> session) { not_null<Main::Session*> session) {
const auto premium = session->user()->isPremium(); const auto premium = session->premium();
const auto defaultLimit = Limit( const auto defaultLimit = Limit(
session, session,
@ -795,7 +795,7 @@ void CaptionLimitReachedBox(
.text = tr::lng_caption_limit_reached(tr::now, lt_count, remove), .text = tr::lng_caption_limit_reached(tr::now, lt_count, remove),
.inform = true, .inform = true,
}); });
if (!session->user()->isPremium()) { if (!session->premium()) {
box->addLeftButton(tr::lng_limits_increase(), [=] { box->addLeftButton(tr::lng_limits_increase(), [=] {
box->getDelegate()->showBox( box->getDelegate()->showBox(
Box(CaptionLimitBox, session), Box(CaptionLimitBox, session),
@ -821,7 +821,7 @@ int CurrentPremiumLimit(
int limitDefault, int limitDefault,
const QString &keyPremium, const QString &keyPremium,
int limitPremium) { int limitPremium) {
const auto premium = session->user()->isPremium(); const auto premium = session->premium();
return AppConfigLimit( return AppConfigLimit(
session, session,
premium ? keyPremium : keyDefault, premium ? keyPremium : keyDefault,

View file

@ -447,7 +447,7 @@ void ReactionsSettingsBox(
&button->lifetime()); &button->lifetime());
button->setClickedCallback([=, emoji = r.emoji] { button->setClickedCallback([=, emoji = r.emoji] {
if (premium && !controller->session().user()->isPremium()) { if (premium && !controller->session().premium()) {
Settings::ShowPremium(&controller->session()); Settings::ShowPremium(&controller->session());
return; return;
} }

View file

@ -404,7 +404,7 @@ void SendFilesBox::openDialogToAddFileToAlbum() {
return true; return true;
}; };
const auto callback = [=](FileDialog::OpenResult &&result) { const auto callback = [=](FileDialog::OpenResult &&result) {
const auto premium = _controller->session().user()->isPremium(); const auto premium = _controller->session().premium();
FileDialogCallback( FileDialogCallback(
std::move(result), std::move(result),
checkResult, checkResult,
@ -575,7 +575,7 @@ void SendFilesBox::pushBlock(int from, int till) {
return true; return true;
}; };
const auto callback = [=](FileDialog::OpenResult &&result) { const auto callback = [=](FileDialog::OpenResult &&result) {
const auto premium = _controller->session().user()->isPremium(); const auto premium = _controller->session().premium();
FileDialogCallback( FileDialogCallback(
std::move(result), std::move(result),
checkResult, checkResult,
@ -773,7 +773,7 @@ bool SendFilesBox::canAddFiles(not_null<const QMimeData*> data) const {
} }
bool SendFilesBox::addFiles(not_null<const QMimeData*> data) { bool SendFilesBox::addFiles(not_null<const QMimeData*> data) {
const auto premium = _controller->session().user()->isPremium(); const auto premium = _controller->session().premium();
auto list = [&] { auto list = [&] {
const auto urls = data->hasUrls() ? data->urls() : QList<QUrl>(); const auto urls = data->hasUrls() ? data->urls() : QList<QUrl>();
auto result = CanAddUrls(urls) auto result = CanAddUrls(urls)

View file

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h" #include "main/main_session.h"
#include "ui/chat/chat_theme.h" #include "ui/chat/chat_theme.h"
#include "ui/layers/generic_box.h" #include "ui/layers/generic_box.h"
#include "ui/effects/premium_graphics.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/gradient_round_button.h" #include "ui/widgets/gradient_round_button.h"
#include "ui/wrap/padding_wrap.h" #include "ui/wrap/padding_wrap.h"
@ -149,11 +150,7 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
[[nodiscard]] object_ptr<Ui::AbstractButton> CreatePremiumButton( [[nodiscard]] object_ptr<Ui::AbstractButton> CreatePremiumButton(
QWidget *parent) { QWidget *parent) {
return CreateGradientButton(parent, { return CreateGradientButton(parent, Ui::Premium::ButtonGradientStops());
{ 0., st::premiumButtonBg1->c },
{ 0.6, st::premiumButtonBg2->c },
{ 1., st::premiumButtonBg3->c },
});
} }
[[nodiscard]] object_ptr<Ui::AbstractButton> CreateUnlockButton( [[nodiscard]] object_ptr<Ui::AbstractButton> CreateUnlockButton(
@ -167,6 +164,7 @@ void PreloadSticker(const std::shared_ptr<Data::DocumentMedia> &media) {
result.data(), result.data(),
tr::lng_sticker_premium_button(), tr::lng_sticker_premium_button(),
st::premiumPreviewButtonLabel); st::premiumPreviewButtonLabel);
label->setAttribute(Qt::WA_TransparentForMouseEvents);
rpl::combine( rpl::combine(
result->widthValue(), result->widthValue(),
label->widthValue() label->widthValue()

View file

@ -298,3 +298,5 @@ premiumPreviewButtonLabel: FlatLabel(defaultFlatLabel) {
textFg: premiumButtonFg; textFg: premiumButtonFg;
style: semiboldTextStyle; style: semiboldTextStyle;
} }
stickersPremiumLock: icon{{ "emoji/premium_lock", premiumButtonFg }};

View file

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "data/data_cloud_file.h" #include "data/data_cloud_file.h"
#include "data/data_changes.h" #include "data/data_changes.h"
#include "data/data_peer_values.h"
#include "menu/menu_send.h" // SendMenu::FillSendMenu #include "menu/menu_send.h" // SendMenu::FillSendMenu
#include "chat_helpers/stickers_lottie.h" #include "chat_helpers/stickers_lottie.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
@ -21,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "ui/effects/path_shift_gradient.h" #include "ui/effects/path_shift_gradient.h"
#include "ui/effects/premium_graphics.h"
#include "ui/image/image.h" #include "ui/image/image.h"
#include "ui/cached_round_corners.h" #include "ui/cached_round_corners.h"
#include "lottie/lottie_multi_player.h" #include "lottie/lottie_multi_player.h"
@ -56,6 +58,7 @@ constexpr auto kPreloadOfficialPages = 4;
constexpr auto kOfficialLoadLimit = 40; constexpr auto kOfficialLoadLimit = 40;
constexpr auto kMinRepaintDelay = crl::time(33); constexpr auto kMinRepaintDelay = crl::time(33);
constexpr auto kMinAfterScrollDelay = crl::time(33); constexpr auto kMinAfterScrollDelay = crl::time(33);
constexpr auto kPremiumLockedOpacity = 0.5;
using Data::StickersSet; using Data::StickersSet;
using Data::StickersPack; using Data::StickersPack;
@ -1176,6 +1179,17 @@ StickersListWidget::StickersListWidget(
) | rpl::skip(1) | rpl::map_to( ) | rpl::skip(1) | rpl::map_to(
TabbedSelector::Action::Update TabbedSelector::Action::Update
) | rpl::start_to_stream(_choosingUpdated, lifetime()); ) | rpl::start_to_stream(_choosingUpdated, lifetime());
style::PaletteChanged(
) | rpl::start_with_next([=] {
_premiumLock = QImage();
}, lifetime());
Data::AmPremiumValue(
&session()
) | rpl::start_with_next([=](bool premium) {
refreshStickers();
}, lifetime());
} }
Main::Session &StickersListWidget::session() const { Main::Session &StickersListWidget::session() const {
@ -2276,6 +2290,7 @@ void StickersListWidget::paintSticker(
return; return;
} }
const auto locked = document->isPremiumSticker() && !session().premium();
const auto isLottie = document->sticker()->isLottie(); const auto isLottie = document->sticker()->isLottie();
const auto isWebm = document->sticker()->isWebm(); const auto isWebm = document->sticker()->isWebm();
if (isLottie if (isLottie
@ -2302,6 +2317,9 @@ void StickersListWidget::paintSticker(
(_singleSize.width() - size.width()) / 2, (_singleSize.width() - size.width()) / 2,
(_singleSize.height() - size.height()) / 2); (_singleSize.height() - size.height()) / 2);
if (locked) {
p.setOpacity(kPremiumLockedOpacity);
}
if (sticker.lottie && sticker.lottie->ready()) { if (sticker.lottie && sticker.lottie->ready()) {
auto request = Lottie::FrameRequest(); auto request = Lottie::FrameRequest();
request.box = boundingBoxSize() * cIntRetinaFactor(); request.box = boundingBoxSize() * cIntRetinaFactor();
@ -2341,6 +2359,7 @@ void StickersListWidget::paintSticker(
sticker.savedFrameFor = _singleSize; sticker.savedFrameFor = _singleSize;
} }
} else { } else {
p.setOpacity(1.);
PaintStickerThumbnailPath( PaintStickerThumbnailPath(
p, p,
media.get(), media.get(),
@ -2358,16 +2377,40 @@ void StickersListWidget::paintSticker(
p.setOpacity(1.); p.setOpacity(1.);
} }
if (document->isPremiumSticker()) { if (locked) {
p.setOpacity(1.);
validatePremiumLock();
const auto factor = style::DevicePixelRatio();
const auto point = pos const auto point = pos
+ QPoint( + QPoint(
_singleSize.width() - st::stickerPanDeleteIconBg.width(), _singleSize.width() - (_premiumLock.width() / factor),
_singleSize.height() - st::stickerPanDeleteIconBg.height()); _singleSize.height() - (_premiumLock.height() / factor));
st::stickerPanDeleteIconBg.paint(p, point, width()); p.drawImage(point, _premiumLock);
st::stickerPanDeleteIconFg.paint(p, point, width());
} }
} }
void StickersListWidget::validatePremiumLock() {
if (!_premiumLock.isNull()) {
return;
}
const auto factor = style::DevicePixelRatio();
const auto size = st::stickersPremiumLock.size();
_premiumLock = QImage(
size * factor,
QImage::Format_ARGB32_Premultiplied);
_premiumLock.setDevicePixelRatio(factor);
auto p = QPainter(&_premiumLock);
auto gradient = QLinearGradient(
QPoint(0, size.height()),
QPoint(size.width(), 0));
gradient.setStops(Ui::Premium::LockGradientStops());
p.fillRect(QRect(QPoint(), size), gradient);
st::stickersPremiumLock.paint(p, 0, 0, size.width());
p.end();
_premiumLock = Images::Circle(std::move(_premiumLock));
}
int StickersListWidget::stickersRight() const { int StickersListWidget::stickersRight() const {
return stickersLeft() + (_columnCount * _singleSize.width()); return stickersLeft() + (_columnCount * _singleSize.width());
} }
@ -2991,7 +3034,7 @@ bool StickersListWidget::appendSet(
PrepareStickers((set->stickers.empty() && externalLayout) PrepareStickers((set->stickers.empty() && externalLayout)
? set->covers ? set->covers
: set->stickers)); : set->stickers));
if (!externalLayout && _premiumsIndex >= 0) { if (!externalLayout && _premiumsIndex >= 0 && session().premium()) {
for (const auto &sticker : to.back().stickers) { for (const auto &sticker : to.back().stickers) {
const auto document = sticker.document; const auto document = sticker.document;
if (document->isPremiumSticker()) { if (document->isPremiumSticker()) {

View file

@ -330,6 +330,7 @@ private:
void addSearchRow(not_null<Data::StickersSet*> set); void addSearchRow(not_null<Data::StickersSet*> set);
void showPreview(); void showPreview();
void validatePremiumLock();
Ui::MessageSendingAnimationFrom messageSentAnimationInfo( Ui::MessageSendingAnimationFrom messageSentAnimationInfo(
int section, int section,
@ -390,6 +391,8 @@ private:
base::Timer _previewTimer; base::Timer _previewTimer;
bool _previewShown = false; bool _previewShown = false;
QImage _premiumLock;
std::map<QString, std::vector<uint64>> _searchCache; std::map<QString, std::vector<uint64>> _searchCache;
std::vector<std::pair<uint64, QStringList>> _searchIndex; std::vector<std::pair<uint64, QStringList>> _searchIndex;
base::Timer _searchRequestTimer; base::Timer _searchRequestTimer;

View file

@ -94,18 +94,25 @@ void EmojiInteractions::play(
void EmojiInteractions::playPremiumEffect( void EmojiInteractions::playPremiumEffect(
not_null<const Element*> view, not_null<const Element*> view,
Element *replacing) { Element *replacing) {
const auto already = ranges::contains(_plays, view, &Play::view);
if (replacing) { if (replacing) {
const auto i = ranges::find(_plays, replacing, &Play::view); const auto i = ranges::find(_plays, replacing, &Play::view);
if (i != end(_plays)) { if (i != end(_plays)) {
//if (i->premium) { //if (i->premium) {
// replacing->externalLottieProgressing(false); // replacing->externalLottieProgressing(false);
//} //}
i->view = view; if (already) {
_plays.erase(i);
} else {
i->view = view;
}
//if (i->premium) { //if (i->premium) {
// view->externalLottieProgressing(true); // view->externalLottieProgressing(true);
//} //}
return; return;
} }
} else if (already) {
return;
} }
if (const auto media = view->media()) { if (const auto media = view->media()) {
if (const auto document = media->getDocument()) { if (const auto document = media->getDocument()) {

View file

@ -255,6 +255,7 @@ void Sticker::paintLottie(
_lottieOncePlayed = true; _lottieOncePlayed = true;
_parent->delegate()->elementStartStickerLoop(_parent); _parent->delegate()->elementStartStickerLoop(_parent);
} }
checkPremiumEffectStart();
} }
bool Sticker::paintPixmap( bool Sticker::paintPixmap(
@ -362,7 +363,16 @@ void Sticker::refreshLink() {
} }
}); });
} else if (sticker && sticker->set) { } else if (sticker && sticker->set) {
_link = ShowSetHandler(_data); if (_data->isPremiumSticker()) {
const auto weak = base::make_weak(this);
_link = std::make_shared<LambdaClickHandler>([weak] {
if (const auto that = weak.get()) {
that->premiumStickerClicked();
}
});
} else {
_link = ShowSetHandler(_data);
}
} else if (sticker } else if (sticker
&& (_data->dimensions.width() > kStickerSideSize && (_data->dimensions.width() > kStickerSideSize
|| _data->dimensions.height() > kStickerSideSize) || _data->dimensions.height() > kStickerSideSize)
@ -388,6 +398,11 @@ void Sticker::emojiStickerClicked() {
_parent->history()->owner().requestViewRepaint(_parent); _parent->history()->owner().requestViewRepaint(_parent);
} }
void Sticker::premiumStickerClicked() {
_premiumEffectPlayed = false;
_parent->history()->owner().requestViewRepaint(_parent);
}
void Sticker::ensureDataMediaCreated() const { void Sticker::ensureDataMediaCreated() const {
if (_dataMedia) { if (_dataMedia) {
return; return;
@ -423,12 +438,15 @@ void Sticker::setupLottie() {
ChatHelpers::StickerLottieSize::MessageHistory, ChatHelpers::StickerLottieSize::MessageHistory,
size() * style::DevicePixelRatio(), size() * style::DevicePixelRatio(),
Lottie::Quality::High); Lottie::Quality::High);
if (_data->isPremiumSticker() checkPremiumEffectStart();
&& !_premiumEffectPlayed) { lottieCreated();
}
void Sticker::checkPremiumEffectStart() {
if (!_premiumEffectPlayed && _data->isPremiumSticker()) {
_premiumEffectPlayed = true; _premiumEffectPlayed = true;
_parent->delegate()->elementStartPremium(_parent, nullptr); _parent->delegate()->elementStartPremium(_parent, nullptr);
} }
lottieCreated();
} }
void Sticker::lottieCreated() { void Sticker::lottieCreated() {

View file

@ -100,6 +100,8 @@ private:
void lottieCreated(); void lottieCreated();
void unloadLottie(); void unloadLottie();
void emojiStickerClicked(); void emojiStickerClicked();
void premiumStickerClicked();
void checkPremiumEffectStart();
//bool markFramesTillExternal(); //bool markFramesTillExternal();
const not_null<Element*> _parent; const not_null<Element*> _parent;

View file

@ -218,6 +218,10 @@ rpl::producer<> Session::downloaderTaskFinished() const {
return downloader().taskFinished(); return downloader().taskFinished();
} }
bool Session::premium() const {
return _user->isPremium();
}
uint64 Session::uniqueId() const { uint64 Session::uniqueId() const {
// See also Account::willHaveSessionUniqueId. // See also Account::willHaveSessionUniqueId.
return userId().bare return userId().bare

View file

@ -80,6 +80,7 @@ public:
[[nodiscard]] Domain &domain() const; [[nodiscard]] Domain &domain() const;
[[nodiscard]] Storage::Domain &domainLocal() const; [[nodiscard]] Storage::Domain &domainLocal() const;
[[nodiscard]] bool premium() const;
[[nodiscard]] uint64 uniqueId() const; // userId() with TestDC shift. [[nodiscard]] uint64 uniqueId() const; // userId() with TestDC shift.
[[nodiscard]] UserId userId() const; [[nodiscard]] UserId userId() const;
[[nodiscard]] PeerId userPeerId() const; [[nodiscard]] PeerId userPeerId() const;

View file

@ -29,15 +29,6 @@ constexpr auto kStepBeforeDeflection = 0.75;
constexpr auto kStepAfterDeflection = kStepBeforeDeflection constexpr auto kStepAfterDeflection = kStepBeforeDeflection
+ (1. - kStepBeforeDeflection) / 2.; + (1. - kStepBeforeDeflection) / 2.;
[[nodiscard]] QGradientStops GradientStops() {
return QGradientStops{
QGradientStop(0.0, st::premiumButtonBg1->c),
QGradientStop(.25, st::premiumButtonBg1->c),
QGradientStop(.85, st::premiumButtonBg2->c),
QGradientStop(1.0, st::premiumButtonBg3->c),
};
}
[[nodiscard]] QLinearGradient ComputeGradient( [[nodiscard]] QLinearGradient ComputeGradient(
not_null<QWidget*> content, not_null<QWidget*> content,
int left, int left,
@ -46,7 +37,7 @@ constexpr auto kStepAfterDeflection = kStepBeforeDeflection
// Take a full width of parent box without paddings. // Take a full width of parent box without paddings.
const auto fullGradientWidth = content->parentWidget()->width(); const auto fullGradientWidth = content->parentWidget()->width();
auto fullGradient = QLinearGradient(0, 0, fullGradientWidth, 0); auto fullGradient = QLinearGradient(0, 0, fullGradientWidth, 0);
fullGradient.setStops(GradientStops()); fullGradient.setStops(ButtonGradientStops());
auto gradient = QLinearGradient(0, 0, width, 0); auto gradient = QLinearGradient(0, 0, width, 0);
const auto fullFinal = float64(fullGradient.finalStop().x()); const auto fullFinal = float64(fullGradient.finalStop().x());
@ -506,5 +497,26 @@ void AddLimitRow(not_null<Ui::VerticalLayout*> parent, int max) {
st::boxRowPadding); st::boxRowPadding);
} }
QGradientStops LimitGradientStops() {
return {
{ 0.0, st::premiumButtonBg1->c },
{ .25, st::premiumButtonBg1->c },
{ .85, st::premiumButtonBg2->c },
{ 1.0, st::premiumButtonBg3->c },
};
}
QGradientStops ButtonGradientStops() {
return {
{ 0., st::premiumButtonBg1->c },
{ 0.6, st::premiumButtonBg2->c },
{ 1., st::premiumButtonBg3->c },
};
}
QGradientStops LockGradientStops() {
return ButtonGradientStops();
}
} // namespace Premium } // namespace Premium
} // namespace Ui } // namespace Ui

View file

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include <QtGui/QBrush>
namespace tr { namespace tr {
template <typename ...> template <typename ...>
struct phrase; struct phrase;
@ -31,5 +33,9 @@ void AddBubbleRow(
void AddLimitRow(not_null<Ui::VerticalLayout*> parent, int max); void AddLimitRow(not_null<Ui::VerticalLayout*> parent, int max);
[[nodiscard]] QGradientStops LimitGradientStops();
[[nodiscard]] QGradientStops ButtonGradientStops();
[[nodiscard]] QGradientStops LockGradientStops();
} // namespace Premium } // namespace Premium
} // namespace Ui } // namespace Ui