Implement nice unique gifts in the list.

This commit is contained in:
John Preston 2024-12-27 22:26:10 +04:00
parent 5df632264f
commit 2113a2b634
3 changed files with 124 additions and 9 deletions

View file

@ -469,7 +469,7 @@ auto GenerateUniqueGiftMedia(
st::chatUniqueButtonPadding,
[=] { parent->repaint(); },
std::move(link),
gift->backdrop.patternColor));
anim::with_alpha(gift->backdrop.patternColor, 0.75)));
}
};
}

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "info/peer_gifts/info_peer_gifts_common.h"
#include "boxes/star_gift_box.h"
#include "boxes/sticker_set_box.h"
#include "chat_helpers/stickers_gift_box_pack.h"
#include "chat_helpers/stickers_lottie.h"
@ -86,12 +87,16 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
{ 1., st::windowActiveTextFg->c },
});
}, [&](const GiftTypeStars &data) {
const auto unique = data.info.unique.get();
const auto soldOut = data.info.limitedCount
&& !data.userpic
&& !data.info.limitedLeft;
_price.setMarkedText(
st::semiboldTextStyle,
_delegate->star().append(' ' + QString::number(data.info.stars)),
(unique
? tr::lng_gift_price_unique(tr::now, Ui::Text::WithEntities)
: _delegate->star().append(
' ' + QString::number(data.info.stars))),
kMarkupTextOptions,
_delegate->textContext());
_userpic = !data.userpic
@ -99,7 +104,13 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
: data.from
? Ui::MakeUserpicThumbnail(data.from)
: Ui::MakeHiddenAuthorThumbnail();
if (soldOut) {
if (unique) {
const auto white = QColor(255, 255, 255);
_stars.setColorOverride(QGradientStops{
{ 0., anim::with_alpha(white, .3) },
{ 1., white },
});
} else if (soldOut) {
_stars.setColorOverride(QGradientStops{
{ 0., Qt::transparent },
{ 1., Qt::transparent },
@ -187,8 +198,61 @@ void GiftButton::resizeEvent(QResizeEvent *e) {
}
}
void GiftButton::cacheUniqueBackground(
not_null<Data::UniqueGift*> unique,
int width,
int height) {
if (!_uniquePatternEmoji) {
_uniquePatternEmoji = _delegate->buttonPatternEmoji(unique, [=] {
update();
});
[[maybe_unused]] const auto preload = _uniquePatternEmoji->ready();
}
const auto outer = QRect(0, 0, width, height);
const auto inner = outer.marginsRemoved(
_extend
).translated(-_extend.left(), -_extend.top());
const auto ratio = style::DevicePixelRatio();
if (_uniqueBackgroundCache.size() != inner.size() * ratio) {
_uniqueBackgroundCache = QImage(
inner.size() * ratio,
QImage::Format_ARGB32_Premultiplied);
_uniqueBackgroundCache.fill(Qt::transparent);
_uniqueBackgroundCache.setDevicePixelRatio(ratio);
const auto radius = st::giftBoxGiftRadius;
auto p = QPainter(&_uniqueBackgroundCache);
auto hq = PainterHighQualityEnabler(p);
auto gradient = QRadialGradient(inner.center(), inner.width() / 2);
gradient.setStops({
{ 0., unique->backdrop.centerColor },
{ 1., unique->backdrop.edgeColor },
});
p.setBrush(gradient);
p.setPen(Qt::NoPen);
p.drawRoundedRect(inner, radius, radius);
_patterned = false;
}
if (!_patterned && _uniquePatternEmoji->ready()) {
_patterned = true;
auto p = QPainter(&_uniqueBackgroundCache);
p.setOpacity(0.5);
p.setClipRect(inner);
const auto skip = inner.width() / 3;
Ui::PaintPoints(
p,
_uniquePatternCache,
_uniquePatternEmoji.get(),
*unique,
QRect(-skip, 0, inner.width() + 2 * skip, inner.height()));
}
}
void GiftButton::paintEvent(QPaintEvent *e) {
auto p = QPainter(this);
const auto unique = v::is<GiftTypeStars>(_descriptor)
? v::get<GiftTypeStars>(_descriptor).info.unique.get()
: nullptr;
const auto hidden = v::is<GiftTypeStars>(_descriptor)
&& v::get<GiftTypeStars>(_descriptor).hidden;;
const auto position = QPoint(_extend.left(), _extend.top());
@ -214,6 +278,10 @@ void GiftButton::paintEvent(QPaintEvent *e) {
background,
QRect(half, 0, 1, height));
}
if (unique) {
cacheUniqueBackground(unique, width, background.height() / dpr);
p.drawImage(_extend.left(), _extend.top(), _uniqueBackgroundCache);
}
if (_userpic) {
if (!_subscribed) {
@ -280,7 +348,9 @@ void GiftButton::paintEvent(QPaintEvent *e) {
}, [&](const GiftTypeStars &data) {
if (const auto count = data.info.limitedCount) {
const auto soldOut = !data.userpic && !data.info.limitedLeft;
p.setBrush(soldOut
p.setBrush(unique
? QBrush(unique->backdrop.patternColor)
: soldOut
? st::attentionButtonFg
: st::windowActiveTextFg);
return soldOut
@ -311,13 +381,17 @@ void GiftButton::paintEvent(QPaintEvent *e) {
p.rotate(45.);
p.translate(-pos);
p.drawRect(-5 * twidth, position.y(), twidth * 12, font->height);
p.setPen(st::windowBg);
p.setPen(unique ? QPen(QColor(255, 255, 255)) : st::windowBg);
p.drawText(pos - QPoint(0, font->descent), text);
p.restore();
}
p.setBrush(premium ? st::lightButtonBgOver : st::creditsBg3);
p.setBrush(unique
? QBrush(QColor(255, 255, 255, .2 * 255))
: premium
? st::lightButtonBgOver
: st::creditsBg3);
p.setPen(Qt::NoPen);
if (!premium) {
if (!unique && !premium) {
p.setOpacity(0.12);
}
const auto geometry = _button;
@ -326,7 +400,9 @@ void GiftButton::paintEvent(QPaintEvent *e) {
if (!premium) {
p.setOpacity(1.);
}
{
if (unique) {
_stars.paint(p);
} else {
auto clipPath = QPainterPath();
clipPath.addRoundedRect(geometry, radius, radius);
p.setClipPath(clipPath);
@ -345,7 +421,11 @@ void GiftButton::paintEvent(QPaintEvent *e) {
}
const auto padding = st::giftBoxButtonPadding;
p.setPen(premium ? st::windowActiveTextFg : st::creditsFg);
p.setPen(unique
? QPen(QColor(255, 255, 255))
: premium
? st::windowActiveTextFg
: st::creditsFg);
_price.draw(p, {
.position = (geometry.topLeft()
+ QPoint(padding.left(), padding.top())),
@ -394,6 +474,16 @@ QMargins Delegate::buttonExtend() {
return st::defaultDropdownMenu.wrap.shadow.extend;
}
auto Delegate::buttonPatternEmoji(
not_null<Data::UniqueGift*> unique,
Fn<void()> repaint)
-> std::unique_ptr<Ui::Text::CustomEmoji> {
return _window->session().data().customEmojiManager().create(
unique->pattern.document,
repaint,
Data::CustomEmojiSizeTag::Large);
}
QImage Delegate::background() {
if (!_bg.isNull()) {
return _bg;

View file

@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class StickerPremiumMark;
namespace Data {
struct UniqueGift;
} // namespace Data
namespace HistoryView {
class StickerPlayer;
} // namespace HistoryView
@ -26,6 +30,10 @@ namespace Ui {
class DynamicImage;
} // namespace Ui
namespace Ui::Text {
class CustomEmoji;
} // namespace Ui::Text
namespace Window {
class SessionController;
} // namespace Window
@ -69,6 +77,10 @@ public:
[[nodiscard]] virtual std::any textContext() = 0;
[[nodiscard]] virtual QSize buttonSize() = 0;
[[nodiscard]] virtual QMargins buttonExtend() = 0;
[[nodiscard]] virtual auto buttonPatternEmoji(
not_null<Data::UniqueGift*> unique,
Fn<void()> repaint)
-> std::unique_ptr<Ui::Text::CustomEmoji> = 0;
[[nodiscard]] virtual QImage background() = 0;
[[nodiscard]] virtual rpl::producer<not_null<DocumentData*>> sticker(
const GiftDescriptor &descriptor) = 0;
@ -87,6 +99,11 @@ private:
void paintEvent(QPaintEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void cacheUniqueBackground(
not_null<Data::UniqueGift*> unique,
int width,
int height);
void setDocument(not_null<DocumentData*> document);
[[nodiscard]] bool documentResolved() const;
@ -98,8 +115,12 @@ private:
Ui::Text::String _text;
Ui::Text::String _price;
std::shared_ptr<Ui::DynamicImage> _userpic;
QImage _uniqueBackgroundCache;
std::unique_ptr<Ui::Text::CustomEmoji> _uniquePatternEmoji;
base::flat_map<float64, QImage> _uniquePatternCache;
Ui::Premium::ColoredMiniStars _stars;
bool _subscribed = false;
bool _patterned = false;
QRect _button;
QMargins _extend;
@ -119,6 +140,10 @@ public:
std::any textContext() override;
QSize buttonSize() override;
QMargins buttonExtend() override;
auto buttonPatternEmoji(
not_null<Data::UniqueGift*> unique,
Fn<void()> repaint)
-> std::unique_ptr<Ui::Text::CustomEmoji> override;
QImage background() override;
rpl::producer<not_null<DocumentData*>> sticker(
const GiftDescriptor &descriptor) override;