Don't show premium stickers if premium blocked.

This commit is contained in:
John Preston 2022-06-08 10:28:45 +04:00
parent e925acc622
commit 86889cf1ef
7 changed files with 185 additions and 94 deletions

View File

@ -422,6 +422,7 @@ void ReactionsSettingsBox(
};
auto firstCheckedButton = (Ui::RpWidget*)(nullptr);
const auto premiumPossible = controller->session().premiumPossible();
for (const auto &r : reactions.list(Data::Reactions::Type::Active)) {
const auto button = Settings::AddButton(
container,
@ -429,7 +430,7 @@ void ReactionsSettingsBox(
st::settingsButton);
const auto premium = r.premium;
if (premium && !controller->session().premiumPossible()) {
if (premium && !premiumPossible) {
continue;
}

View File

@ -55,12 +55,54 @@ namespace {
constexpr auto kStickersPanelPerRow = 5;
constexpr auto kMinRepaintDelay = crl::time(33);
constexpr auto kMinAfterScrollDelay = crl::time(33);
constexpr auto kGrayLockOpacity = 0.3;
using Data::StickersSet;
using Data::StickersPack;
using Data::StickersByEmojiMap;
using SetFlag = Data::StickersSetFlag;
[[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
class StickerSetBox::Inner final : public Ui::RpWidget {
@ -106,6 +148,7 @@ private:
Lottie::Animation *lottie = nullptr;
Media::Clip::ReaderPointer webm;
Ui::Animations::Simple overAnimation;
mutable QImage premiumLock;
};
void visibleTopBottomUpdated(int visibleTop, int visibleBottom) override;
@ -138,6 +181,7 @@ private:
not_null<Lottie::MultiPlayer*> getLottiePlayer();
void showPreview();
const QImage &validatePremiumLock(int index, const QImage &frame) const;
void updateItems();
void repaintItems(crl::time now = 0);
@ -158,6 +202,7 @@ private:
ImageWithLocation _setThumbnail;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
mutable QImage _premiumLockGray;
int _visibleTop = 0;
int _visibleBottom = 0;
@ -416,6 +461,11 @@ StickerSetBox::Inner::Inner(
updateItems();
}, lifetime());
style::PaletteChanged(
) | rpl::start_with_next([=] {
_premiumLockGray = QImage();
}, lifetime());
setMouseTracking(true);
}
@ -425,18 +475,25 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
_elements.clear();
_selected = -1;
setCursor(style::cur_default);
const auto owner = &_controller->session().data();
const auto premiumPossible = _controller->session().premiumPossible();
set.match([&](const MTPDmessages_stickerSet &data) {
const auto &v = data.vdocuments().v;
_pack.reserve(v.size());
_elements.reserve(v.size());
for (const auto &item : v) {
const auto document = _controller->session().data().processDocument(item);
const auto document = owner->processDocument(item);
const auto sticker = document->sticker();
if (!sticker) {
continue;
}
_pack.push_back(document);
_elements.push_back({ document, document->createMediaView() });
if (!document->isPremiumSticker() || premiumPossible) {
_elements.push_back({
document,
document->createMediaView(),
});
}
}
for (const auto &pack : data.vpacks().v) {
pack.match([&](const MTPDstickerPack &pack) {
@ -756,6 +813,15 @@ void StickerSetBox::Inner::showPreview() {
}
}
const QImage &StickerSetBox::Inner::validatePremiumLock(
int index,
const QImage &frame) const {
auto &element = _elements[index];
auto &image = frame.isNull() ? _premiumLockGray : element.premiumLock;
ValidatePremiumLockBg(image, frame);
return image;
}
not_null<Lottie::MultiPlayer*> StickerSetBox::Inner::getLottiePlayer() {
if (!_lottiePlayer) {
_lottiePlayer = std::make_unique<Lottie::MultiPlayer>(
@ -939,6 +1005,8 @@ void StickerSetBox::Inner::paintSticker(
const auto document = element.document;
const auto &media = element.documentMedia;
const auto sticker = document->sticker();
const auto locked = document->isPremiumSticker()
&& !_controller->session().premium();
media->checkStickerSmall();
if (media->loaded()) {
@ -955,12 +1023,12 @@ void StickerSetBox::Inner::paintSticker(
const auto ppos = position + QPoint(
(st::stickersSize.width() - size.width()) / 2,
(st::stickersSize.height() - size.height()) / 2);
auto lottieFrame = QImage();
if (element.lottie && element.lottie->ready()) {
const auto frame = element.lottie->frame();
lottieFrame = element.lottie->frame();
p.drawImage(
QRect(ppos, frame.size() / cIntRetinaFactor()),
frame);
QRect(ppos, lottieFrame.size() / cIntRetinaFactor()),
lottieFrame);
_lottiePlayer->unpause(element.lottie);
} else if (element.webm && element.webm->started()) {
@ -980,6 +1048,20 @@ void StickerSetBox::Inner::paintSticker(
QRect(ppos, size),
_pathGradient.get());
}
if (locked) {
validatePremiumLock(index, lottieFrame);
const auto &bg = lottieFrame.isNull()
? _premiumLockGray
: element.premiumLock;
const auto factor = style::DevicePixelRatio();
const auto radius = st::roundRadiusSmall;
const auto point = position + QPoint(
(st::stickersSize.width() - (bg.width() / factor)) / 2,
st::stickersSize.height() - (bg.height() / factor) - radius);
p.drawImage(point, bg);
st::stickersPremiumLock.paint(p, point, width());
}
}
bool StickerSetBox::Inner::loaded() const {
@ -1066,3 +1148,23 @@ 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));
}

View File

@ -53,3 +53,5 @@ private:
QPointer<Inner> _inner;
};
void ValidatePremiumLockBg(QImage &image, const QImage &frame);

View File

@ -242,11 +242,11 @@ private:
[[nodiscard]] Data::StickersSetFlags fillSetFlags(
not_null<StickersSet*> set) const;
void rebuildMegagroupSet();
void fixupMegagroupSetAddress();
void handleMegagroupSetAddressChange();
void setMegagroupSelectedSet(const StickerSetIdentifier &set);
int countMaxNameWidth() const;
[[nodiscard]] bool skipPremium() const;
const not_null<Window::SessionController*> _controller;
MTP::Sender _api;
@ -2193,6 +2193,10 @@ bool StickersBox::Inner::appendSet(not_null<StickersSet*> set) {
return true;
}
bool StickersBox::Inner::skipPremium() const {
return !_controller->session().premiumPossible();
}
int StickersBox::Inner::countMaxNameWidth() const {
int namex = st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left();
if (!_megagroupSet && _isInstalled) {
@ -2317,23 +2321,39 @@ void StickersBox::Inner::fillSetCover(
}
int StickersBox::Inner::fillSetCount(not_null<StickersSet*> set) const {
const auto skipPremium = this->skipPremium();
int result = set->stickers.isEmpty()
? set->count
: set->stickers.size();
if (skipPremium && !set->stickers.isEmpty()) {
result -= ranges::count(
set->stickers,
true,
&DocumentData::isPremiumSticker);
}
auto added = 0;
if (set->id == Data::Stickers::CloudRecentSetId) {
const auto &sets = session().data().stickers().sets();
const auto &recent = session().data().stickers().getRecentPack();
auto customIt = sets.find(Data::Stickers::CustomSetId);
if (customIt != sets.cend()) {
added = customIt->second->stickers.size();
const auto &recent = session().data().stickers().getRecentPack();
auto &custom = customIt->second->stickers;
added = custom.size();
if (skipPremium) {
added -= ranges::count(
custom,
true,
&DocumentData::isPremiumSticker);
}
for (const auto &sticker : recent) {
if (customIt->second->stickers.indexOf(sticker.first) < 0) {
if (skipPremium && sticker.first->isPremiumSticker()) {
continue;
} else if (customIt->second->stickers.indexOf(sticker.first) < 0) {
++added;
}
}
} else {
added = session().data().stickers().getRecentPack().size();
added = recent.size();
}
}
return result + added;

View File

@ -58,7 +58,6 @@ constexpr auto kPreloadOfficialPages = 4;
constexpr auto kOfficialLoadLimit = 40;
constexpr auto kMinRepaintDelay = crl::time(33);
constexpr auto kMinAfterScrollDelay = crl::time(33);
constexpr auto kGrayLockOpacity = 0.3;
using Data::StickersSet;
using Data::StickersPack;
@ -69,47 +68,6 @@ using SetFlag = Data::StickersSetFlag;
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
struct StickerIcon {
@ -313,11 +271,14 @@ struct StickersListWidget::Set {
};
auto StickersListWidget::PrepareStickers(
const QVector<DocumentData*> &pack)
const QVector<DocumentData*> &pack,
bool skipPremium)
-> std::vector<Sticker> {
return ranges::views::all(
pack
) | ranges::views::transform([](DocumentData *document) {
) | ranges::views::filter([&](DocumentData *document) {
return !skipPremium || !document->isPremiumSticker();
}) | ranges::views::transform([](DocumentData *document) {
return Sticker{ document };
}) | ranges::to_vector;
}
@ -1673,6 +1634,10 @@ void StickersListWidget::fillCloudSearchRows(
}
void StickersListWidget::addSearchRow(not_null<StickersSet*> set) {
const auto skipPremium = !session().premiumPossible();
auto elements = PrepareStickers(
set->stickers.empty() ? set->covers : set->stickers,
skipPremium);
_searchSets.emplace_back(
set->id,
set,
@ -1681,9 +1646,7 @@ void StickersListWidget::addSearchRow(not_null<StickersSet*> set) {
set->shortName,
set->count,
!SetInMyList(set->flags),
PrepareStickers(set->stickers.empty()
? set->covers
: set->stickers));
std::move(elements));
}
void StickersListWidget::takeHeavyData(
@ -2445,23 +2408,7 @@ const QImage &StickersListWidget::validatePremiumLock(
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 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));
ValidatePremiumLockBg(image, frame);
return image;
}
@ -2996,13 +2943,15 @@ void StickersListWidget::refreshSearchSets() {
refreshSearchIndex();
const auto &sets = session().data().stickers().sets();
const auto skipPremium = !session().premiumPossible();
for (auto &entry : _searchSets) {
if (const auto it = sets.find(entry.id); it != sets.end()) {
const auto set = it->second.get();
entry.flags = set->flags;
if (!set->stickers.empty()) {
auto elements = PrepareStickers(set->stickers, skipPremium);
if (!elements.empty()) {
entry.lottiePlayer = nullptr;
entry.stickers = PrepareStickers(set->stickers);
entry.stickers = std::move(elements);
}
if (!SetInMyList(entry.flags)) {
_installedLocallySets.remove(entry.id);
@ -3077,6 +3026,15 @@ bool StickersListWidget::appendSet(
return false;
}
}
const auto skipPremium = !session().premiumPossible();
auto elements = PrepareStickers(
((set->stickers.empty() && externalLayout)
? set->covers
: set->stickers),
skipPremium);
if (elements.empty()) {
return false;
}
to.emplace_back(
set->id,
set,
@ -3085,9 +3043,7 @@ bool StickersListWidget::appendSet(
set->shortName,
set->count,
externalLayout,
PrepareStickers((set->stickers.empty() && externalLayout)
? set->covers
: set->stickers));
std::move(elements));
if (!externalLayout && _premiumsIndex >= 0 && session().premium()) {
for (const auto &sticker : to.back().stickers) {
const auto document = sticker.document;
@ -3232,12 +3188,17 @@ void StickersListWidget::refreshFavedStickers() {
clearSelection();
const auto &sets = session().data().stickers().sets();
const auto it = sets.find(Data::Stickers::FavedSetId);
if (it == sets.cend() || it->second->stickers.isEmpty()) {
if (it == sets.cend()) {
return;
}
const auto skipPremium = !session().premiumPossible();
const auto set = it->second.get();
const auto externalLayout = false;
const auto shortName = QString();
auto elements = PrepareStickers(set->stickers, skipPremium);
if (elements.empty()) {
return;
}
_mySets.insert(_mySets.begin(), Set{
Data::Stickers::FavedSetId,
nullptr,
@ -3246,7 +3207,7 @@ void StickersListWidget::refreshFavedStickers() {
shortName,
set->count,
externalLayout,
PrepareStickers(set->stickers)
std::move(elements)
});
_favedStickersMap = base::flat_set<not_null<DocumentData*>> {
set->stickers.begin(),
@ -3308,15 +3269,19 @@ void StickersListWidget::refreshMegagroupStickers(GroupStickersPlace place) {
} else if (isShownHere(hidden)) {
const auto shortName = QString();
const auto externalLayout = false;
_mySets.emplace_back(
Data::Stickers::MegagroupSetId,
set,
SetFlag::Special,
tr::lng_group_stickers(tr::now),
shortName,
set->count,
externalLayout,
PrepareStickers(set->stickers));
const auto skipPremium = !session().premiumPossible();
auto elements = PrepareStickers(set->stickers, skipPremium);
if (!elements.empty()) {
_mySets.emplace_back(
Data::Stickers::MegagroupSetId,
set,
SetFlag::Special,
tr::lng_group_stickers(tr::now),
shortName,
set->count,
externalLayout,
std::move(elements));
}
}
return;
} else if (!isShownHere(hidden) || _megagroupSetIdRequested == set.id) {

View File

@ -192,7 +192,8 @@ private:
};
static std::vector<Sticker> PrepareStickers(
const QVector<DocumentData*> &pack);
const QVector<DocumentData*> &pack,
bool skipPremium);
void preloadMoreOfficial();
QSize boundingBoxSize() const;

View File

@ -224,7 +224,7 @@ bool Session::premium() const {
}
bool Session::premiumPossible() const {
return !_account->appConfig().get<bool>(
return !premium() && !_account->appConfig().get<bool>(
"premium_purchase_blocked",
true);
}