From 86889cf1ef2454f08e9b9dc968f2e74a1ba935c1 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 8 Jun 2022 10:28:45 +0400 Subject: [PATCH] Don't show premium stickers if premium blocked. --- .../boxes/reactions_settings_box.cpp | 3 +- .../SourceFiles/boxes/sticker_set_box.cpp | 114 +++++++++++++++- Telegram/SourceFiles/boxes/sticker_set_box.h | 2 + Telegram/SourceFiles/boxes/stickers_box.cpp | 30 ++++- .../chat_helpers/stickers_list_widget.cpp | 125 +++++++----------- .../chat_helpers/stickers_list_widget.h | 3 +- Telegram/SourceFiles/main/main_session.cpp | 2 +- 7 files changed, 185 insertions(+), 94 deletions(-) diff --git a/Telegram/SourceFiles/boxes/reactions_settings_box.cpp b/Telegram/SourceFiles/boxes/reactions_settings_box.cpp index e13779561..166c4797e 100644 --- a/Telegram/SourceFiles/boxes/reactions_settings_box.cpp +++ b/Telegram/SourceFiles/boxes/reactions_settings_box.cpp @@ -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; } diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.cpp b/Telegram/SourceFiles/boxes/sticker_set_box.cpp index aa65215d8..a67c1bf9d 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.cpp +++ b/Telegram/SourceFiles/boxes/sticker_set_box.cpp @@ -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 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(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 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 _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 StickerSetBox::Inner::getLottiePlayer() { if (!_lottiePlayer) { _lottiePlayer = std::make_unique( @@ -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)); +} diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.h b/Telegram/SourceFiles/boxes/sticker_set_box.h index a4be4c680..a53bcafdc 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.h +++ b/Telegram/SourceFiles/boxes/sticker_set_box.h @@ -53,3 +53,5 @@ private: QPointer _inner; }; + +void ValidatePremiumLockBg(QImage &image, const QImage &frame); diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index 3a4eaca8b..0665387c5 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -242,11 +242,11 @@ private: [[nodiscard]] Data::StickersSetFlags fillSetFlags( not_null set) const; void rebuildMegagroupSet(); - void fixupMegagroupSetAddress(); void handleMegagroupSetAddressChange(); void setMegagroupSelectedSet(const StickerSetIdentifier &set); int countMaxNameWidth() const; + [[nodiscard]] bool skipPremium() const; const not_null _controller; MTP::Sender _api; @@ -2193,6 +2193,10 @@ bool StickersBox::Inner::appendSet(not_null 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 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; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index dce3c91ce..f8a22348d 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -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 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(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 &pack) + const QVector &pack, + bool skipPremium) -> std::vector { 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 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 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> { 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) { diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h index e2567970c..2748cf7ce 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h @@ -192,7 +192,8 @@ private: }; static std::vector PrepareStickers( - const QVector &pack); + const QVector &pack, + bool skipPremium); void preloadMoreOfficial(); QSize boundingBoxSize() const; diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index f0c5a4891..bf12fcbb4 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -224,7 +224,7 @@ bool Session::premium() const { } bool Session::premiumPossible() const { - return !_account->appConfig().get( + return !premium() && !_account->appConfig().get( "premium_purchase_blocked", true); }