Show premium mark in suggested stickers.

This commit is contained in:
John Preston 2022-08-02 16:47:53 +03:00
parent e3140a8a45
commit 4a5592e95d
5 changed files with 161 additions and 133 deletions

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_document_media.h"
#include "data/data_peer_values.h"
#include "data/stickers/data_stickers.h"
#include "data/stickers/data_custom_emoji.h"
#include "menu/menu_send.h"
@ -112,8 +113,99 @@ using SetFlag = Data::StickersSetFlag;
return ComputeImageColor(frame).value_or(st::windowSubTextFg->c);
}
void ValidatePremiumLockBg(QImage &image, const QImage &frame) {
if (!image.isNull()) {
return;
}
const auto factor = style::DevicePixelRatio();
const auto size = st::stickersPremiumLock.size();
image = QImage(
size * factor,
QImage::Format_ARGB32_Premultiplied);
image.setDevicePixelRatio(factor);
auto p = QPainter(&image);
const auto color = ComputeLockColor(frame);
p.fillRect(
QRect(QPoint(), size),
anim::color(color, st::windowSubTextFg, kGrayLockOpacity));
p.end();
image = Images::Circle(std::move(image));
}
void ValidatePremiumStarFg(QImage &image) {
if (!image.isNull()) {
return;
}
const auto factor = style::DevicePixelRatio();
const auto size = st::stickersPremiumLock.size();
image = QImage(
size * factor,
QImage::Format_ARGB32_Premultiplied);
image.setDevicePixelRatio(factor);
image.fill(Qt::transparent);
auto p = QPainter(&image);
auto star = QSvgRenderer(u":/gui/icons/settings/star.svg"_q);
const auto skip = size.width() / 5.;
const auto outer = QRectF(QPointF(), size).marginsRemoved(
{ skip, skip, skip, skip });
p.setBrush(st::premiumButtonFg);
p.setPen(Qt::NoPen);
star.render(&p, outer);
}
} // namespace
StickerPremiumMark::StickerPremiumMark(not_null<Main::Session*> session) {
style::PaletteChanged(
) | rpl::start_with_next([=] {
_lockGray = QImage();
_star = QImage();
}, _lifetime);
Data::AmPremiumValue(
session
) | rpl::start_with_next([=](bool premium) {
_premium = premium;
}, _lifetime);
}
void StickerPremiumMark::paint(
QPainter &p,
const QImage &frame,
QImage &backCache,
QPoint position,
QSize singleSize,
int outerWidth) {
validateLock(frame, backCache);
const auto &bg = frame.isNull() ? _lockGray : backCache;
const auto factor = style::DevicePixelRatio();
const auto radius = st::roundRadiusSmall;
const auto point = position + QPoint(
(_premium
? (singleSize.width() - (bg.width() / factor) - radius)
: (singleSize.width() - (bg.width() / factor)) / 2),
singleSize.height() - (bg.height() / factor) - radius);
p.drawImage(point, bg);
if (_premium) {
validateStar();
p.drawImage(point, _star);
} else {
st::stickersPremiumLock.paint(p, point, outerWidth);
}
}
void StickerPremiumMark::validateLock(
const QImage &frame,
QImage &backCache) {
auto &image = frame.isNull() ? _lockGray : backCache;
ValidatePremiumLockBg(image, frame);
}
void StickerPremiumMark::validateStar() {
ValidatePremiumStarFg(_star);
}
class StickerSetBox::Inner final : public Ui::RpWidget {
public:
Inner(
@ -204,8 +296,6 @@ private:
not_null<Lottie::MultiPlayer*> getLottiePlayer();
void showPreview();
void validatePremiumLock(int index, const QImage &frame) const;
void validatePremiumStar() const;
void updateItems();
void repaintItems(crl::time now = 0);
@ -237,8 +327,7 @@ private:
ImageWithLocation _setThumbnail;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
mutable QImage _premiumLockGray;
mutable QImage _premiumStar;
mutable StickerPremiumMark _premiumMark;
int _visibleTop = 0;
int _visibleBottom = 0;
@ -545,6 +634,7 @@ StickerSetBox::Inner::Inner(
st::windowBgRipple,
st::windowBgOver,
[=] { repaintItems(); }))
, _premiumMark(&controller->session())
, _updateItemsTimer([=] { updateItems(); })
, _input(set)
, _padding((type == Data::StickersType::Emoji)
@ -570,12 +660,6 @@ StickerSetBox::Inner::Inner(
updateItems();
}, lifetime());
style::PaletteChanged(
) | rpl::start_with_next([=] {
_premiumLockGray = QImage();
_premiumStar = QImage();
}, lifetime());
setMouseTracking(true);
}
@ -937,18 +1021,6 @@ void StickerSetBox::Inner::showPreview() {
}
}
void StickerSetBox::Inner::validatePremiumLock(
int index,
const QImage &frame) const {
auto &element = _elements[index];
auto &image = frame.isNull() ? _premiumLockGray : element.premiumLock;
ValidatePremiumLockBg(image, frame);
}
void StickerSetBox::Inner::validatePremiumStar() const {
ValidatePremiumStarFg(_premiumStar);
}
not_null<Lottie::MultiPlayer*> StickerSetBox::Inner::getLottiePlayer() {
if (!_lottiePlayer) {
_lottiePlayer = std::make_unique<Lottie::MultiPlayer>(
@ -1175,7 +1247,6 @@ void StickerSetBox::Inner::paintSticker(
const auto document = element.document;
const auto &media = element.documentMedia;
const auto sticker = document->sticker();
const auto premium = document->isPremiumSticker();
media->checkStickerSmall();
if (sticker->setType == Data::StickersType::Emoji) {
@ -1188,6 +1259,7 @@ void StickerSetBox::Inner::paintSticker(
}
}
const auto premium = document->isPremiumSticker();
const auto size = ChatHelpers::ComputeStickerSize(
document,
boundingBoxSize());
@ -1216,10 +1288,12 @@ void StickerSetBox::Inner::paintSticker(
.keepAlpha = true,
}, paused ? 0 : now));
} else if (const auto image = media->getStickerSmall()) {
p.drawPixmapLeft(
ppos,
width(),
image->pix(size));
const auto pixmap = image->pix(size);
p.drawPixmapLeft(ppos, width(), pixmap);
if (premium) {
lottieFrame = pixmap.toImage().convertToFormat(
QImage::Format_ARGB32_Premultiplied);
}
} else {
ChatHelpers::PaintStickerThumbnailPath(
p,
@ -1228,25 +1302,13 @@ void StickerSetBox::Inner::paintSticker(
_pathGradient.get());
}
if (premium) {
validatePremiumLock(index, lottieFrame);
const auto &bg = lottieFrame.isNull()
? _premiumLockGray
: element.premiumLock;
const auto factor = style::DevicePixelRatio();
const auto radius = st::roundRadiusSmall;
const auto amPremium = _controller->session().premium();
const auto point = position + QPoint(
(amPremium
? (_singleSize.width() - (bg.width() / factor) - radius)
: (_singleSize.width() - (bg.width() / factor)) / 2),
_singleSize.height() - (bg.height() / factor) - radius);
p.drawImage(point, bg);
if (amPremium) {
validatePremiumStar();
p.drawImage(point, _premiumStar);
} else {
st::stickersPremiumLock.paint(p, point, width());
}
_premiumMark.paint(
p,
lottieFrame,
element.premiumLock,
position,
_singleSize,
width());
}
}
@ -1340,44 +1402,3 @@ void StickerSetBox::Inner::repaintItems(crl::time now) {
}
StickerSetBox::Inner::~Inner() = default;
void ValidatePremiumLockBg(QImage &image, const QImage &frame) {
if (!image.isNull()) {
return;
}
const auto factor = style::DevicePixelRatio();
const auto size = st::stickersPremiumLock.size();
image = QImage(
size * factor,
QImage::Format_ARGB32_Premultiplied);
image.setDevicePixelRatio(factor);
auto p = QPainter(&image);
const auto color = ComputeLockColor(frame);
p.fillRect(
QRect(QPoint(), size),
anim::color(color, st::windowSubTextFg, kGrayLockOpacity));
p.end();
image = Images::Circle(std::move(image));
}
void ValidatePremiumStarFg(QImage &image) {
if (!image.isNull()) {
return;
}
const auto factor = style::DevicePixelRatio();
const auto size = st::stickersPremiumLock.size();
image = QImage(
size * factor,
QImage::Format_ARGB32_Premultiplied);
image.setDevicePixelRatio(factor);
image.fill(Qt::transparent);
auto p = QPainter(&image);
auto star = QSvgRenderer(u":/gui/icons/settings/star.svg"_q);
const auto skip = size.width() / 5.;
const auto outer = QRectF(QPointF(), size).marginsRemoved(
{ skip, skip, skip, skip });
p.setBrush(st::premiumButtonFg);
p.setPen(Qt::NoPen);
star.render(&p, outer);
}

View File

@ -23,6 +23,30 @@ namespace Data {
class StickersSet;
} // namespace Data
class StickerPremiumMark final {
public:
explicit StickerPremiumMark(not_null<Main::Session*> session);
void paint(
QPainter &p,
const QImage &frame,
QImage &backCache,
QPoint position,
QSize singleSize,
int outerWidth);
private:
void validateLock(const QImage &frame, QImage &backCache);
void validateStar();
QImage _lockGray;
QImage _star;
bool _premium = false;
rpl::lifetime _lifetime;
};
class StickerSetBox final : public Ui::BoxContent {
public:
StickerSetBox(
@ -63,6 +87,3 @@ private:
QPointer<Inner> _inner;
};
void ValidatePremiumLockBg(QImage &image, const QImage &frame);
void ValidatePremiumStarFg(QImage &image);

View File

@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h"
#include "base/random.h"
#include "base/qt/qt_common_adapters.h"
#include "boxes/sticker_set_box.h"
#include "window/window_adaptive.h"
#include "window/window_session_controller.h"
#include "styles/style_chat.h"
@ -135,6 +136,7 @@ private:
bool _isOneColumn = false;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
StickerPremiumMark _premiumMark;
Fn<SendMenu::Type()> _sendMenuType;
@ -153,6 +155,7 @@ struct FieldAutocomplete::StickerSuggestion {
std::shared_ptr<Data::DocumentMedia> documentMedia;
std::unique_ptr<Lottie::SinglePlayer> lottie;
Media::Clip::ReaderPointer webm;
QImage premiumLock;
};
FieldAutocomplete::FieldAutocomplete(
@ -790,6 +793,7 @@ FieldAutocomplete::Inner::Inner(
st::windowBgRipple,
st::windowBgOver,
[=] { update(); }))
, _premiumMark(&controller->session())
, _previewTimer([=] { showPreview(); }) {
controller->session().downloaderTaskFinished(
) | rpl::start_with_next([=] {
@ -868,11 +872,12 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) {
const auto ppos = pos + QPoint(
(st::stickerPanSize.width() - size.width()) / 2,
(st::stickerPanSize.height() - size.height()) / 2);
auto lottieFrame = QImage();
if (sticker.lottie && sticker.lottie->ready()) {
const auto frame = sticker.lottie->frame();
lottieFrame = sticker.lottie->frame();
p.drawImage(
QRect(ppos, frame.size() / cIntRetinaFactor()),
frame);
QRect(ppos, lottieFrame.size() / cIntRetinaFactor()),
lottieFrame);
if (!paused) {
sticker.lottie->markFrameShown();
}
@ -890,6 +895,16 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) {
QRect(ppos, size),
_pathGradient.get());
}
if (document->isPremiumSticker()) {
_premiumMark.paint(
p,
lottieFrame,
sticker.premiumLock,
pos,
st::stickerPanSize,
width());
}
}
}
} else {

View File

@ -180,6 +180,7 @@ StickersListWidget::StickersListWidget(
, _addWidth(st::stickersTrendingAdd.font->width(_addText))
, _settings(this, tr::lng_stickers_you_have(tr::now))
, _previewTimer([=] { showPreview(); })
, _premiumMark(std::make_unique<StickerPremiumMark>(&controller->session()))
, _searchRequestTimer([=] { sendSearchRequest(); }) {
setMouseTracking(true);
setAttribute(Qt::WA_OpaquePaintEvent);
@ -218,12 +219,6 @@ StickersListWidget::StickersListWidget(
TabbedSelector::Action::Update
) | rpl::start_to_stream(_choosingUpdated, lifetime());
style::PaletteChanged(
) | rpl::start_with_next([=] {
_premiumLockGray = QImage();
_premiumStar = QImage();
}, lifetime());
Data::AmPremiumValue(
&session()
) | rpl::start_with_next([=](bool premium) {
@ -1375,41 +1370,16 @@ void StickersListWidget::paintSticker(
}
if (premium) {
validatePremiumLock(set, index, lottieFrame);
const auto &bg = lottieFrame.isNull()
? _premiumLockGray
: sticker.premiumLock;
const auto factor = style::DevicePixelRatio();
const auto radius = st::roundRadiusSmall;
const auto amPremium = session().premium();
const auto point = pos + QPoint(
(amPremium
? (_singleSize.width() - (bg.width() / factor) - radius)
: (_singleSize.width() - (bg.width() / factor)) / 2),
_singleSize.height() - (bg.height() / factor) - radius);
p.drawImage(point, bg);
if (amPremium) {
validatePremiumStar();
p.drawImage(point, _premiumStar);
} else {
st::stickersPremiumLock.paint(p, point, width());
}
_premiumMark->paint(
p,
lottieFrame,
sticker.premiumLock,
pos,
_singleSize,
width());
}
}
void StickersListWidget::validatePremiumLock(
Set &set,
int index,
const QImage &frame) {
auto &sticker = set.stickers[index];
auto &image = frame.isNull() ? _premiumLockGray : sticker.premiumLock;
ValidatePremiumLockBg(image, frame);
}
void StickersListWidget::validatePremiumStar() {
ValidatePremiumStarFg(_premiumStar);
}
int StickersListWidget::stickersRight() const {
return stickersLeft() + (_columnCount * _singleSize.width());
}

View File

@ -12,6 +12,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/variant.h"
#include "base/timer.h"
class StickerPremiumMark;
namespace Main {
class Session;
} // namespace Main
@ -355,7 +357,6 @@ private:
int _rowsLeft = 0;
int _columnCount = 1;
QSize _singleSize;
QImage _premiumStar;
OverState _selected;
OverState _pressed;
@ -377,7 +378,7 @@ private:
base::Timer _previewTimer;
bool _previewShown = false;
QImage _premiumLockGray;
std::unique_ptr<StickerPremiumMark> _premiumMark;
std::map<QString, std::vector<uint64>> _searchCache;
std::vector<std::pair<uint64, QStringList>> _searchIndex;