Improve locked premium stickers design.

This commit is contained in:
John Preston 2022-06-06 16:08:11 +04:00
parent 0bf58936e3
commit 719190d570
3 changed files with 90 additions and 33 deletions

View file

@ -58,7 +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; constexpr auto kGrayLockOpacity = 0.3;
using Data::StickersSet; using Data::StickersSet;
using Data::StickersPack; using Data::StickersPack;
@ -69,6 +69,47 @@ using SetFlag = Data::StickersSetFlag;
return (flags & SetFlag::Installed) && !(flags & SetFlag::Archived); return (flags & SetFlag::Installed) && !(flags & SetFlag::Archived);
} }
[[nodiscard]] std::optional<QColor> ComputeImageColor(const QImage &frame) {
if (frame.isNull()
|| frame.format() != QImage::Format_ARGB32_Premultiplied) {
return {};
}
auto sr = int64();
auto sg = int64();
auto sb = int64();
auto sa = int64();
const auto factor = frame.devicePixelRatio();
const auto size = st::stickersPremiumLock.size() * factor;
const auto width = std::min(frame.width(), size.width());
const auto height = std::min(frame.height(), size.height());
const auto skipx = (frame.width() - width) / 2;
const auto radius = st::roundRadiusSmall;
const auto skipy = std::max(frame.height() - height - radius, 0);
const auto perline = frame.bytesPerLine();
const auto addperline = perline - (width * 4);
auto bits = static_cast<const uchar*>(frame.bits())
+ perline * skipy
+ sizeof(uint32) * skipx;
for (auto y = 0; y != height; ++y) {
for (auto x = 0; x != width; ++x) {
sb += int(*bits++);
sg += int(*bits++);
sr += int(*bits++);
sa += int(*bits++);
}
bits += addperline;
}
if (!sa) {
return {};
}
return QColor(sr * 255 / sa, sg * 255 / sa, sb * 255 / sa, 255);
}
[[nodiscard]] QColor ComputeLockColor(const QImage &frame) {
return ComputeImageColor(frame).value_or(st::windowSubTextFg->c);
}
} // namespace } // namespace
struct StickerIcon { struct StickerIcon {
@ -236,6 +277,7 @@ struct StickersListWidget::Sticker {
Media::Clip::ReaderPointer webm; Media::Clip::ReaderPointer webm;
QPixmap savedFrame; QPixmap savedFrame;
QSize savedFrameFor; QSize savedFrameFor;
QImage premiumLock;
void ensureMediaCreated(); void ensureMediaCreated();
}; };
@ -1182,7 +1224,7 @@ StickersListWidget::StickersListWidget(
style::PaletteChanged( style::PaletteChanged(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
_premiumLock = QImage(); _premiumLockGray = QImage();
}, lifetime()); }, lifetime());
Data::AmPremiumValue( Data::AmPremiumValue(
@ -2317,18 +2359,18 @@ 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) { auto lottieFrame = QImage();
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();
const auto frame = sticker.lottie->frame(request); lottieFrame = sticker.lottie->frame(request);
p.drawImage( p.drawImage(
QRect(ppos, frame.size() / cIntRetinaFactor()), QRect(ppos, lottieFrame.size() / cIntRetinaFactor()),
frame); lottieFrame);
if (sticker.savedFrame.isNull()) { if (sticker.savedFrame.isNull()) {
sticker.savedFrame = QPixmap::fromImage(frame, Qt::ColorOnly); sticker.savedFrame = QPixmap::fromImage(
lottieFrame,
Qt::ColorOnly);
sticker.savedFrame.setDevicePixelRatio(cRetinaFactor()); sticker.savedFrame.setDevicePixelRatio(cRetinaFactor());
sticker.savedFrameFor = _singleSize; sticker.savedFrameFor = _singleSize;
} }
@ -2358,6 +2400,10 @@ void StickersListWidget::paintSticker(
sticker.savedFrame = pixmap; sticker.savedFrame = pixmap;
sticker.savedFrameFor = _singleSize; sticker.savedFrameFor = _singleSize;
} }
if (locked) {
lottieFrame = pixmap.toImage().convertToFormat(
QImage::Format_ARGB32_Premultiplied);
}
} else { } else {
p.setOpacity(1.); p.setOpacity(1.);
PaintStickerThumbnailPath( PaintStickerThumbnailPath(
@ -2378,37 +2424,45 @@ void StickersListWidget::paintSticker(
} }
if (locked) { if (locked) {
p.setOpacity(1.); validatePremiumLock(set, index, lottieFrame);
const auto &bg = lottieFrame.isNull()
validatePremiumLock(); ? _premiumLockGray
: sticker.premiumLock;
const auto factor = style::DevicePixelRatio(); const auto factor = style::DevicePixelRatio();
const auto point = pos const auto radius = st::roundRadiusSmall;
+ QPoint( const auto point = pos + QPoint(
_singleSize.width() - (_premiumLock.width() / factor), (_singleSize.width() - (bg.width() / factor)) / 2,
_singleSize.height() - (_premiumLock.height() / factor)); _singleSize.height() - (bg.height() / factor) - radius);
p.drawImage(point, _premiumLock); p.drawImage(point, bg);
st::stickersPremiumLock.paint(p, point, width());
} }
} }
void StickersListWidget::validatePremiumLock() { const QImage &StickersListWidget::validatePremiumLock(
if (!_premiumLock.isNull()) { Set &set,
return; int index,
const QImage &frame) {
auto &sticker = set.stickers[index];
auto &image = frame.isNull() ? _premiumLockGray : sticker.premiumLock;
if (!image.isNull()) {
return image;
} }
const auto factor = style::DevicePixelRatio(); const auto factor = style::DevicePixelRatio();
const auto size = st::stickersPremiumLock.size(); const auto size = st::stickersPremiumLock.size();
_premiumLock = QImage( image = QImage(
size * factor, size * factor,
QImage::Format_ARGB32_Premultiplied); QImage::Format_ARGB32_Premultiplied);
_premiumLock.setDevicePixelRatio(factor); image.setDevicePixelRatio(factor);
auto p = QPainter(&_premiumLock); auto p = QPainter(&image);
auto gradient = QLinearGradient( const auto color = ComputeLockColor(frame);
QPoint(0, size.height()), p.fillRect(
QPoint(size.width(), 0)); QRect(QPoint(), size),
gradient.setStops(Ui::Premium::LockGradientStops()); anim::color(color, st::windowSubTextFg, kGrayLockOpacity));
p.fillRect(QRect(QPoint(), size), gradient);
st::stickersPremiumLock.paint(p, 0, 0, size.width());
p.end(); p.end();
_premiumLock = Images::Circle(std::move(_premiumLock));
image = Images::Circle(std::move(image));
return image;
} }
int StickersListWidget::stickersRight() const { int StickersListWidget::stickersRight() const {

View file

@ -330,7 +330,10 @@ private:
void addSearchRow(not_null<Data::StickersSet*> set); void addSearchRow(not_null<Data::StickersSet*> set);
void showPreview(); void showPreview();
void validatePremiumLock(); const QImage &validatePremiumLock(
Set &set,
int index,
const QImage &frame);
Ui::MessageSendingAnimationFrom messageSentAnimationInfo( Ui::MessageSendingAnimationFrom messageSentAnimationInfo(
int section, int section,
@ -391,7 +394,7 @@ private:
base::Timer _previewTimer; base::Timer _previewTimer;
bool _previewShown = false; bool _previewShown = false;
QImage _premiumLock; QImage _premiumLockGray;
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;

@ -1 +1 @@
Subproject commit 0a713c1c7b9d1890b98eb7c6d1e29bd199914ad7 Subproject commit 72940a25e30e34361c9ad294007a5d707404d856