Use a custom animated emoji for collectible status.

This commit is contained in:
John Preston 2025-01-13 17:41:16 +04:00
parent d2be10cd4e
commit c25adf8b57
13 changed files with 195 additions and 89 deletions

View file

@ -935,13 +935,9 @@ int ColorSelector::resizeGetHeight(int newWidth) {
const auto session = &show->session(); const auto session = &show->session();
std::move(statusIdValue) | rpl::start_with_next([=](EmojiStatusId id) { std::move(statusIdValue) | rpl::start_with_next([=](EmojiStatusId id) {
state->statusId = id; state->statusId = id;
state->emoji = id.collectible // todo collectibles state->emoji = id
? session->data().customEmojiManager().create( ? session->data().customEmojiManager().create(
id.collectible->documentId, Data::EmojiStatusCustomId(id),
[=] { right->update(); })
: id.documentId
? session->data().customEmojiManager().create(
id.documentId,
[=] { right->update(); }) [=] { right->update(); })
: nullptr; : nullptr;
right->resize( right->resize(

View file

@ -1129,17 +1129,16 @@ void EmojiListWidget::fillRecentFrom(
}); });
_recentCustomIds.emplace(fakeId); _recentCustomIds.emplace(fakeId);
} else { } else {
const auto documentId = id.collectible
? id.collectible->documentId
: id.documentId;
_recent.push_back({ _recent.push_back({
.collectible = id.collectible, .collectible = id.collectible,
.custom = resolveCustomRecent(documentId), .custom = resolveCustomRecent(id),
.id = { .id = {
RecentEmojiDocument{ .id = documentId, .test = test }, RecentEmojiDocument{ .id = id.documentId, .test = test },
}, },
}); });
_recentCustomIds.emplace(documentId); _recentCustomIds.emplace(id.collectible
? id.collectible->documentId
: id.documentId);
} }
} }
} }
@ -1490,27 +1489,6 @@ void EmojiListWidget::drawCollapsedBadge(
text); text);
} }
void EmojiListWidget::drawCollectible(
QPainter &p,
QPoint position,
Data::EmojiStatusCollectible *collectible) {
if (!collectible) {
return;
}
const auto inner = QRect(position, st::emojiPanArea);
auto gradient = QRadialGradient(inner.center(), inner.height() / 2);
gradient.setStops({
{ 0., collectible->centerColor },
{ 1., collectible->edgeColor },
});
p.setBrush(gradient);
p.setPen(Qt::NoPen);
p.drawRoundedRect(
inner,
st::emojiPanRadius,
st::emojiPanRadius);
}
void EmojiListWidget::drawRecent( void EmojiListWidget::drawRecent(
QPainter &p, QPainter &p,
const ExpandingContext &context, const ExpandingContext &context,
@ -1547,14 +1525,12 @@ void EmojiListWidget::drawRecent(
auto q = Painter(&_premiumMarkFrameCache); auto q = Painter(&_premiumMarkFrameCache);
_emojiPaintContext->position = QPoint(); _emojiPaintContext->position = QPoint();
drawCollectible(q, position, recent.collectible.get());
custom->paint(q, *_emojiPaintContext); custom->paint(q, *_emojiPaintContext);
q.end(); q.end();
p.drawImage(exactPosition, _premiumMarkFrameCache); p.drawImage(exactPosition, _premiumMarkFrameCache);
} else { } else {
_emojiPaintContext->position = exactPosition; _emojiPaintContext->position = exactPosition;
drawCollectible(p, position, recent.collectible.get());
custom->paint(p, *_emojiPaintContext); custom->paint(p, *_emojiPaintContext);
} }
} else if (const auto emoji = std::get_if<EmojiPtr>(&recent.id.data)) { } else if (const auto emoji = std::get_if<EmojiPtr>(&recent.id.data)) {
@ -1609,7 +1585,6 @@ void EmojiListWidget::drawCustom(
_emojiPaintContext->position = position _emojiPaintContext->position = position
+ _innerPosition + _innerPosition
+ _customPosition; + _customPosition;
drawCollectible(p, position, entry.collectible.get());
entry.custom->paint(p, *_emojiPaintContext); entry.custom->paint(p, *_emojiPaintContext);
} }
@ -1643,8 +1618,15 @@ EmojiListWidget::ResolvedCustom EmojiListWidget::lookupCustomEmoji(
} }
return {}; return {};
} else if (section == int(Section::Recent) && index < _recent.size()) { } else if (section == int(Section::Recent) && index < _recent.size()) {
const auto &recent = _recent[index];
if (recent.collectible) {
return {
session().data().document(recent.collectible->documentId),
recent.collectible,
};
}
const auto document = std::get_if<RecentEmojiDocument>( const auto document = std::get_if<RecentEmojiDocument>(
&_recent[index].id.data); &recent.id.data);
if (document) { if (document) {
return { session().data().document(document->id) }; return { session().data().document(document->id) };
} }
@ -2342,11 +2324,12 @@ void EmojiListWidget::refreshCustom() {
auto set = std::vector<CustomOne>(); auto set = std::vector<CustomOne>();
set.reserve(list.size()); set.reserve(list.size());
for (const auto document : list) { for (const auto document : list) {
if (_restrictedCustomList.contains(document->id)) { const auto id = EmojiStatusId{ document->id };
if (_restrictedCustomList.contains(id.documentId)) {
continue; continue;
} else if (const auto sticker = document->sticker()) { } else if (const auto sticker = document->sticker()) {
set.push_back({ set.push_back({
.custom = resolveCustomEmoji(document, lookupId), .custom = resolveCustomEmoji(id, document, lookupId),
.document = document, .document = document,
.emoji = Ui::Emoji::Find(sticker->alt), .emoji = Ui::Emoji::Find(sticker->alt),
}); });
@ -2401,18 +2384,19 @@ Fn<void()> EmojiListWidget::repaintCallback(
} }
not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomEmoji( not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomEmoji(
EmojiStatusId id,
not_null<DocumentData*> document, not_null<DocumentData*> document,
uint64 setId) { uint64 setId) {
Expects(document->sticker() != nullptr); Expects(document->sticker() != nullptr);
const auto documentId = document->id; const auto documentId = document->id;
const auto i = _customEmoji.find(documentId); const auto i = _customEmoji.find(id);
const auto recentOnly = (i != end(_customEmoji)) && i->second.recentOnly; const auto recentOnly = (i != end(_customEmoji)) && i->second.recentOnly;
if (i != end(_customEmoji) && !recentOnly) { if (i != end(_customEmoji) && !recentOnly) {
return i->second.emoji.get(); return i->second.emoji.get();
} }
auto instance = document->owner().customEmojiManager().create( auto instance = document->owner().customEmojiManager().create(
document, Data::EmojiStatusCustomId(id),
repaintCallback(documentId, setId), repaintCallback(documentId, setId),
Data::CustomEmojiManager::SizeTag::Large); Data::CustomEmojiManager::SizeTag::Large);
if (recentOnly) { if (recentOnly) {
@ -2426,7 +2410,7 @@ not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomEmoji(
return i->second.emoji.get(); return i->second.emoji.get();
} }
return _customEmoji.emplace( return _customEmoji.emplace(
documentId, id,
CustomEmojiInstance{ .emoji = std::move(instance) } CustomEmojiInstance{ .emoji = std::move(instance) }
).first->second.emoji.get(); ).first->second.emoji.get();
} }
@ -2444,27 +2428,37 @@ Ui::Text::CustomEmoji *EmojiListWidget::resolveCustomRecent(
not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomRecent( not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomRecent(
DocumentId documentId) { DocumentId documentId) {
const auto i = _customRecent.find(documentId); return resolveCustomRecent(EmojiStatusId{ documentId });
}
not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomRecent(
EmojiStatusId id) {
const auto i = id.collectible
? end(_customRecent)
: _customRecent.find(id.documentId);
if (i != end(_customRecent)) { if (i != end(_customRecent)) {
return i->second.get(); return i->second.get();
} }
const auto j = _customEmoji.find(documentId); const auto j = _customEmoji.find(id);
if (j != end(_customEmoji)) { if (j != end(_customEmoji)) {
return j->second.emoji.get(); return j->second.emoji.get();
} }
const auto documentId = id.collectible
? id.collectible->documentId
: id.documentId;
auto repaint = repaintCallback(documentId, RecentEmojiSectionSetId()); auto repaint = repaintCallback(documentId, RecentEmojiSectionSetId());
if (_customRecentFactory) { if (_customRecentFactory && !id.collectible) {
return _customRecent.emplace( return _customRecent.emplace(
documentId, id.documentId,
_customRecentFactory(documentId, std::move(repaint)) _customRecentFactory(id.documentId, std::move(repaint))
).first->second.get(); ).first->second.get();
} }
auto custom = session().data().customEmojiManager().create( auto custom = session().data().customEmojiManager().create(
documentId, Data::EmojiStatusCustomId(id),
std::move(repaint), std::move(repaint),
Data::CustomEmojiManager::SizeTag::Large); Data::CustomEmojiManager::SizeTag::Large);
return _customEmoji.emplace( return _customEmoji.emplace(
documentId, id,
CustomEmojiInstance{ .emoji = std::move(custom), .recentOnly = true } CustomEmojiInstance{ .emoji = std::move(custom), .recentOnly = true }
).first->second.emoji.get(); ).first->second.emoji.get();
} }
@ -2489,7 +2483,7 @@ void EmojiListWidget::refreshEmojiStatusCollectibles() {
if (const auto sticker = document->sticker()) { if (const auto sticker = document->sticker()) {
set.push_back({ set.push_back({
.collectible = status.collectible, .collectible = status.collectible,
.custom = resolveCustomEmoji(document, setId), .custom = resolveCustomEmoji(status, document, setId),
.document = document, .document = document,
.emoji = Ui::Emoji::Find(sticker->alt), .emoji = Ui::Emoji::Find(sticker->alt),
}); });

View file

@ -325,10 +325,6 @@ private:
void selectCustom(FileChosen data); void selectCustom(FileChosen data);
void paint(Painter &p, ExpandingContext context, QRect clip); void paint(Painter &p, ExpandingContext context, QRect clip);
void drawCollapsedBadge(QPainter &p, QPoint position, int count); void drawCollapsedBadge(QPainter &p, QPoint position, int count);
void drawCollectible(
QPainter &p,
QPoint position,
Data::EmojiStatusCollectible *collectible);
void drawRecent( void drawRecent(
QPainter &p, QPainter &p,
const ExpandingContext &context, const ExpandingContext &context,
@ -389,12 +385,15 @@ private:
void fillRecent(); void fillRecent();
void fillRecentFrom(const std::vector<EmojiStatusId> &list); void fillRecentFrom(const std::vector<EmojiStatusId> &list);
[[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomEmoji( [[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomEmoji(
EmojiStatusId id,
not_null<DocumentData*> document, not_null<DocumentData*> document,
uint64 setId); uint64 setId);
[[nodiscard]] Ui::Text::CustomEmoji *resolveCustomRecent( [[nodiscard]] Ui::Text::CustomEmoji *resolveCustomRecent(
Core::RecentEmojiId customId); Core::RecentEmojiId customId);
[[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomRecent( [[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomRecent(
DocumentId documentId); DocumentId documentId);
[[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomRecent(
EmojiStatusId id);
[[nodiscard]] Fn<void()> repaintCallback( [[nodiscard]] Fn<void()> repaintCallback(
DocumentId documentId, DocumentId documentId,
uint64 setId); uint64 setId);
@ -432,7 +431,7 @@ private:
QVector<EmojiPtr> _emoji[kEmojiSectionCount]; QVector<EmojiPtr> _emoji[kEmojiSectionCount];
std::vector<CustomSet> _custom; std::vector<CustomSet> _custom;
base::flat_set<DocumentId> _restrictedCustomList; base::flat_set<DocumentId> _restrictedCustomList;
base::flat_map<DocumentId, CustomEmojiInstance> _customEmoji; base::flat_map<EmojiStatusId, CustomEmojiInstance> _customEmoji;
base::flat_map< base::flat_map<
DocumentId, DocumentId,
std::unique_ptr<Ui::Text::CustomEmoji>> _customRecent; std::unique_ptr<Ui::Text::CustomEmoji>> _customRecent;

View file

@ -559,4 +559,9 @@ EmojiStatusId EmojiStatuses::fromUniqueGift(
return { .collectible = collectible }; return { .collectible = collectible };
} }
EmojiStatusCollectible *EmojiStatuses::collectibleInfo(CollectibleId id) {
const auto i = _collectibleData.find(id);
return (i != end(_collectibleData)) ? i->second.get() : nullptr;
}
} // namespace Data } // namespace Data

View file

@ -81,6 +81,7 @@ public:
void set(EmojiStatusId id, TimeId until = 0); void set(EmojiStatusId id, TimeId until = 0);
void set(not_null<PeerData*> peer, EmojiStatusId id, TimeId until = 0); void set(not_null<PeerData*> peer, EmojiStatusId id, TimeId until = 0);
[[nodiscard]] EmojiStatusId fromUniqueGift(const Data::UniqueGift &gift); [[nodiscard]] EmojiStatusId fromUniqueGift(const Data::UniqueGift &gift);
[[nodiscard]] EmojiStatusCollectible *collectibleInfo(CollectibleId id);
void registerAutomaticClear(not_null<PeerData*> peer, TimeId until); void registerAutomaticClear(not_null<PeerData*> peer, TimeId until);

View file

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_document_media.h" #include "data/data_document_media.h"
#include "data/data_emoji_statuses.h"
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "data/data_forum_topic.h" // ParseTopicIconEmojiEntity. #include "data/data_forum_topic.h" // ParseTopicIconEmojiEntity.
#include "data/data_peer.h" #include "data/data_peer.h"
@ -28,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/stickers_lottie.h" #include "chat_helpers/stickers_lottie.h"
#include "storage/file_download.h" // kMaxFileInMemory #include "storage/file_download.h" // kMaxFileInMemory
#include "ui/chat/chats_filter_tag.h" #include "ui/chat/chats_filter_tag.h"
#include "ui/effects/premium_stars_colored.h"
#include "ui/effects/credits_graphics.h" #include "ui/effects/credits_graphics.h"
#include "ui/widgets/fields/input_field.h" #include "ui/widgets/fields/input_field.h"
#include "ui/text/custom_emoji_instance.h" #include "ui/text/custom_emoji_instance.h"
@ -117,6 +119,10 @@ private:
return u"force-static:"_q; return u"force-static:"_q;
} }
[[nodiscard]] QString CollectiblePrefix() {
return u"collectible:"_q;
}
[[nodiscard]] QString InternalPadding(QMargins value) { [[nodiscard]] QString InternalPadding(QMargins value) {
return value.isNull() ? QString() : QString(",%1,%2,%3,%4" return value.isNull() ? QString() : QString(",%1,%2,%3,%4"
).arg(value.left() ).arg(value.left()
@ -568,6 +574,20 @@ std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
const auto ratio = style::DevicePixelRatio(); const auto ratio = style::DevicePixelRatio();
const auto size = EmojiSizeFromTag(tag) / ratio; const auto size = EmojiSizeFromTag(tag) / ratio;
return userpic(data, std::move(update), size); return userpic(data, std::move(update), size);
} else if (data.startsWith(CollectiblePrefix())) {
const auto id = data.mid(CollectiblePrefix().size()).toULongLong();
const auto emojiStatuses = &session().data().emojiStatuses();
auto info = emojiStatuses->collectibleInfo(id);
Assert(info != nullptr);
const auto documentId = info->documentId;
auto inner = create(documentId, base::duplicate(update), tag);
return Ui::Premium::MakeCollectibleEmoji(
data,
info->centerColor,
info->edgeColor,
std::move(inner),
std::move(update),
FrameSizeFromTag(tag) / style::DevicePixelRatio());
} else if (const auto parsed = Data::ParseTopicIconEmojiEntity(data)) { } else if (const auto parsed = Data::ParseTopicIconEmojiEntity(data)) {
return MakeTopicIconEmoji(parsed, std::move(update), tag); return MakeTopicIconEmoji(parsed, std::move(update), tag);
} }
@ -1147,4 +1167,14 @@ Ui::Text::CustomEmojiFactory ReactedMenuFactory(
}; };
} }
QString CollectibleCustomEmojiId(Data::EmojiStatusCollectible &data) {
return CollectiblePrefix() + QString::number(data.id);
}
QString EmojiStatusCustomId(const EmojiStatusId &id) {
return id.collectible
? CollectibleCustomEmojiId(*id.collectible)
: SerializeCustomEmojiId(id.documentId);
}
} // namespace Data } // namespace Data

View file

@ -223,4 +223,8 @@ void InsertCustomEmoji(
[[nodiscard]] Ui::Text::CustomEmojiFactory ReactedMenuFactory( [[nodiscard]] Ui::Text::CustomEmojiFactory ReactedMenuFactory(
not_null<Main::Session*> session); not_null<Main::Session*> session);
[[nodiscard]] QString CollectibleCustomEmojiId(
Data::EmojiStatusCollectible &data);
[[nodiscard]] QString EmojiStatusCustomId(const EmojiStatusId &id);
} // namespace Data } // namespace Data

View file

@ -113,11 +113,11 @@ namespace {
Data::PeerUpdate::Flag::EmojiStatus Data::PeerUpdate::Flag::EmojiStatus
) | rpl::map([=] { ) | rpl::map([=] {
const auto id = peer->emojiStatusId(); const auto id = peer->emojiStatusId();
const auto documentId = id.collectible return id.collectible
? id.collectible->documentId ? rpl::single(Ui::Text::SingleCustomEmoji(
: id.documentId; Data::EmojiStatusCustomId(id)))
return documentId : id.documentId
? ResolveIsCustom(owner, documentId) ? ResolveIsCustom(owner, id.documentId)
: rpl::single(TextWithEntities()); : rpl::single(TextWithEntities());
}) | rpl::flatten_latest() | rpl::distinct_until_changed(); }) | rpl::flatten_latest() | rpl::distinct_until_changed();
} }

View file

@ -371,7 +371,7 @@ struct Message::CommentsButton {
}; };
struct Message::FromNameStatus { struct Message::FromNameStatus {
DocumentId id = 0; EmojiStatusId id;
std::unique_ptr<Ui::Text::CustomEmoji> custom; std::unique_ptr<Ui::Text::CustomEmoji> custom;
int skip = 0; int skip = 0;
}; };
@ -1767,14 +1767,14 @@ void Message::paintFromName(
+ std::min(availableWidth - statusWidth, nameText->maxWidth()); + std::min(availableWidth - statusWidth, nameText->maxWidth());
const auto y = trect.top(); const auto y = trect.top();
auto color = nameFg; auto color = nameFg;
color.setAlpha(115); // todo collectibles color.setAlpha(115);
const auto id = from ? from->emojiStatusId().documentId : 0; const auto id = from ? from->emojiStatusId() : EmojiStatusId();
if (_fromNameStatus->id != id) { if (_fromNameStatus->id != id) {
const auto that = const_cast<Message*>(this); const auto that = const_cast<Message*>(this);
_fromNameStatus->custom = id _fromNameStatus->custom = id
? std::make_unique<Ui::Text::LimitedLoopsEmoji>( ? std::make_unique<Ui::Text::LimitedLoopsEmoji>(
history()->owner().customEmojiManager().create( history()->owner().customEmojiManager().create(
id, Data::EmojiStatusCustomId(id),
[=] { that->customEmojiRepaint(); }), [=] { that->customEmojiRepaint(); }),
kPlayStatusLimit) kPlayStatusLimit)
: nullptr; : nullptr;
@ -2379,7 +2379,7 @@ void Message::unloadHeavyPart() {
_comments = nullptr; _comments = nullptr;
if (_fromNameStatus) { if (_fromNameStatus) {
_fromNameStatus->custom = nullptr; _fromNameStatus->custom = nullptr;
_fromNameStatus->id = 0; _fromNameStatus->id = EmojiStatusId();
} }
} }

View file

@ -130,12 +130,9 @@ void Badge::setContent(Content content) {
: id : id
? nullptr ? nullptr
: &_st.premium; : &_st.premium;
const auto documentId = id.collectible if (id) {
? id.collectible->documentId
: id.documentId;
if (documentId) {
_emojiStatus = _session->data().customEmojiManager().create( _emojiStatus = _session->data().customEmojiManager().create(
documentId, Data::EmojiStatusCustomId(id),
[raw = _view.data()] { raw->update(); }, [raw = _view.data()] { raw->update(); },
sizeTag()); sizeTag());
if (_customStatusLoopsLimit > 0) { if (_customStatusLoopsLimit > 0) {

View file

@ -8,10 +8,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/premium_stars_colored.h" #include "ui/effects/premium_stars_colored.h"
#include "ui/effects/premium_graphics.h" // GiftGradientStops. #include "ui/effects/premium_graphics.h" // GiftGradientStops.
#include "ui/text/text_custom_emoji.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
namespace Ui { namespace Ui::Premium {
namespace Premium {
ColoredMiniStars::ColoredMiniStars( ColoredMiniStars::ColoredMiniStars(
not_null<Ui::RpWidget*> parent, not_null<Ui::RpWidget*> parent,
@ -106,5 +106,79 @@ void ColoredMiniStars::setCenter(const QRect &rect) {
setSize(ministarsRect.size()); setSize(ministarsRect.size());
} }
} // namespace Premium std::unique_ptr<Text::CustomEmoji> MakeCollectibleEmoji(
} // namespace Ui QStringView entityData,
QColor centerColor,
QColor edgeColor,
std::unique_ptr<Text::CustomEmoji> inner,
Fn<void()> update,
int size) {
class Emoji final : public Text::CustomEmoji {
public:
Emoji(
QStringView entityData,
QColor centerColor,
QColor edgeColor,
std::unique_ptr<Ui::Text::CustomEmoji> inner,
Fn<void()> update,
int size)
: _entityData(entityData.toString())
, _stars([=](QRect) { update(); }, MiniStars::Type::SlowStars)
, _centerColor(centerColor)
, _edgeColor(edgeColor)
, _inner(std::move(inner))
, _size(size) {
_stars.setColorOverride(QGradientStops{
{ 0., edgeColor },
{ 1., centerColor },
});
_stars.setSize(QSize(size, size));
}
int width() override {
return _inner->width();
}
QString entityData() override {
return _entityData;
}
void paint(QPainter &p, const Context &context) override {
_stars.setPosition(context.position);
_stars.paint(p);
_inner->paint(p, context);
}
void unload() override {
_inner->unload();
}
bool ready() override {
return _inner->ready();
}
bool readyInDefaultState() override {
return _inner->readyInDefaultState();
}
private:
QString _entityData;
ColoredMiniStars _stars;
QColor _centerColor;
QColor _edgeColor;
std::unique_ptr<Text::CustomEmoji> _inner;
int _size = 0;
};
return std::make_unique<Emoji>(
entityData,
centerColor,
edgeColor,
std::move(inner),
std::move(update),
size);
}
} // namespace Ui::Premium

View file

@ -11,8 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui { namespace Ui {
class RpWidget; class RpWidget;
} // namespace Ui
namespace Premium { namespace Ui::Text {
class CustomEmoji;
} // namespace Ui::Text
namespace Ui::Premium {
class ColoredMiniStars final { class ColoredMiniStars final {
public: public:
@ -32,7 +37,7 @@ public:
void setPaused(bool paused); void setPaused(bool paused);
private: private:
Ui::Premium::MiniStars _ministars; MiniStars _ministars;
QRectF _ministarsRect; QRectF _ministarsRect;
QImage _frame; QImage _frame;
QImage _mask; QImage _mask;
@ -42,5 +47,12 @@ private:
}; };
} // namespace Premium [[nodiscard]] std::unique_ptr<Text::CustomEmoji> MakeCollectibleEmoji(
} // namespace Ui QStringView entityData,
QColor centerColor,
QColor edgeColor,
std::unique_ptr<Text::CustomEmoji> inner,
Fn<void()> update,
int size);
} // namespace Ui::Premium

View file

@ -239,17 +239,11 @@ int PeerBadge::drawPremiumEmojiStatus(
using namespace Ui::Text; using namespace Ui::Text;
auto &manager = peer->session().data().customEmojiManager(); auto &manager = peer->session().data().customEmojiManager();
_emojiStatus->id = id; _emojiStatus->id = id;
_emojiStatus->emoji = id.collectible // todo collectibles _emojiStatus->emoji = std::make_unique<LimitedLoopsEmoji>(
? std::make_unique<LimitedLoopsEmoji>( manager.create(
manager.create( Data::EmojiStatusCustomId(id),
id.collectible->documentId, descriptor.customEmojiRepaint),
descriptor.customEmojiRepaint), kPlayStatusLimit);
kPlayStatusLimit)
: std::make_unique<LimitedLoopsEmoji>(
manager.create(
id.documentId,
descriptor.customEmojiRepaint),
kPlayStatusLimit);
} }
_emojiStatus->emoji->paint(p, { _emojiStatus->emoji->paint(p, {
.textColor = (*descriptor.premiumFg)->c, .textColor = (*descriptor.premiumFg)->c,