mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-14 05:07:10 +02:00
Improve stars in collectible emoji status.
This commit is contained in:
parent
6d7abd1718
commit
e3517aceab
2 changed files with 221 additions and 73 deletions
|
@ -2387,8 +2387,6 @@ not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomEmoji(
|
|||
EmojiStatusId id,
|
||||
not_null<DocumentData*> document,
|
||||
uint64 setId) {
|
||||
Expects(document->sticker() != nullptr);
|
||||
|
||||
const auto documentId = document->id;
|
||||
const auto i = _customEmoji.find(id);
|
||||
const auto recentOnly = (i != end(_customEmoji)) && i->second.recentOnly;
|
||||
|
@ -2469,9 +2467,6 @@ void EmojiListWidget::refreshEmojiStatusCollectibles() {
|
|||
}
|
||||
const auto type = Data::EmojiStatuses::Type::Collectibles;
|
||||
const auto &list = session().data().emojiStatuses().list(type);
|
||||
if (list.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto setId = Data::Stickers::CollectibleSetId;
|
||||
auto set = std::vector<CustomOne>();
|
||||
set.reserve(list.size());
|
||||
|
@ -2480,14 +2475,16 @@ void EmojiListWidget::refreshEmojiStatusCollectibles() {
|
|||
? status.collectible->documentId
|
||||
: status.documentId;
|
||||
const auto document = session().data().document(documentId);
|
||||
if (const auto sticker = document->sticker()) {
|
||||
set.push_back({
|
||||
.collectible = status.collectible,
|
||||
.custom = resolveCustomEmoji(status, document, setId),
|
||||
.document = document,
|
||||
.emoji = Ui::Emoji::Find(sticker->alt),
|
||||
});
|
||||
}
|
||||
const auto sticker = document->sticker();
|
||||
set.push_back({
|
||||
.collectible = status.collectible,
|
||||
.custom = resolveCustomEmoji(status, document, setId),
|
||||
.document = document,
|
||||
.emoji = sticker ? Ui::Emoji::Find(sticker->alt) : nullptr,
|
||||
});
|
||||
}
|
||||
if (set.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto collectibles = session().data().stickers().collectibleSet();
|
||||
_custom.push_back({
|
||||
|
|
|
@ -7,11 +7,221 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "ui/effects/premium_stars_colored.h"
|
||||
|
||||
#include "base/random.h"
|
||||
#include "ui/effects/premium_graphics.h" // GiftGradientStops.
|
||||
#include "ui/text/text_custom_emoji.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
namespace Ui::Premium {
|
||||
namespace {
|
||||
|
||||
constexpr auto kStarsCount = 16;
|
||||
constexpr auto kTravelMax = 0.5;
|
||||
constexpr auto kExcludeRadius = 0.7;
|
||||
constexpr auto kFading = crl::time(200);
|
||||
constexpr auto kLifetimeMin = crl::time(1000);
|
||||
constexpr auto kLifetimeMax = 3 * kLifetimeMin;
|
||||
constexpr auto kSizeMin = 0.1;
|
||||
constexpr auto kSizeMax = 0.15;
|
||||
|
||||
[[nodiscard]] crl::time ChooseLife(base::BufferedRandom<uint32> &random) {
|
||||
return kLifetimeMin
|
||||
+ base::RandomIndex(kLifetimeMax - kLifetimeMin, random);
|
||||
}
|
||||
|
||||
class CollectibleEmoji final : public Text::CustomEmoji {
|
||||
public:
|
||||
CollectibleEmoji(
|
||||
QStringView entityData,
|
||||
QColor centerColor,
|
||||
QColor edgeColor,
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> inner,
|
||||
Fn<void()> update,
|
||||
int size);
|
||||
|
||||
int width() override;
|
||||
QString entityData() override;
|
||||
void paint(QPainter &p, const Context &context) override;
|
||||
void unload() override;
|
||||
bool ready() override;
|
||||
bool readyInDefaultState() override;
|
||||
|
||||
private:
|
||||
struct Star {
|
||||
QPointF start;
|
||||
QPointF delta;
|
||||
float64 size = 0.;
|
||||
crl::time birthTime = 0;
|
||||
crl::time deathTime = 0;
|
||||
};
|
||||
|
||||
void fill();
|
||||
void refill(Star &star, base::BufferedRandom<uint32> &random);
|
||||
void prepareFrame();
|
||||
|
||||
QString _entityData;
|
||||
QSvgRenderer _svg;
|
||||
std::vector<Star> _stars;
|
||||
QColor _centerColor;
|
||||
QColor _edgeColor;
|
||||
std::unique_ptr<Text::CustomEmoji> _inner;
|
||||
Ui::Animations::Basic _animation;
|
||||
QImage _frame;
|
||||
int _size = 0;
|
||||
|
||||
};
|
||||
|
||||
CollectibleEmoji::CollectibleEmoji(
|
||||
QStringView entityData,
|
||||
QColor centerColor,
|
||||
QColor edgeColor,
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> inner,
|
||||
Fn<void()> update,
|
||||
int size)
|
||||
: _entityData(entityData.toString())
|
||||
, _svg(u":/gui/icons/settings/starmini.svg"_q)
|
||||
, _centerColor(centerColor)
|
||||
, _edgeColor(edgeColor)
|
||||
, _inner(std::move(inner))
|
||||
, _animation(std::move(update))
|
||||
, _size(size) {
|
||||
fill();
|
||||
}
|
||||
|
||||
void CollectibleEmoji::fill() {
|
||||
_stars.reserve(kStarsCount);
|
||||
const auto now = crl::now();
|
||||
auto random = base::BufferedRandom<uint32>(kStarsCount * 12);
|
||||
for (auto i = 0; i != kStarsCount; ++i) {
|
||||
const auto life = ChooseLife(random);
|
||||
const auto shift = base::RandomIndex(life - kFading, random);
|
||||
_stars.push_back({
|
||||
.birthTime = now - crl::time(shift),
|
||||
.deathTime = now - crl::time(shift) + crl::time(life),
|
||||
});
|
||||
refill(_stars.back(), random);
|
||||
}
|
||||
}
|
||||
|
||||
void CollectibleEmoji::refill(
|
||||
Star &star,
|
||||
base::BufferedRandom<uint32> &random) {
|
||||
const auto take = [&] {
|
||||
return base::RandomIndex(_size * 16, random) / (_size * 15.);
|
||||
};
|
||||
const auto stake = [&] {
|
||||
return take() * 2. - 1.;
|
||||
};
|
||||
const auto exclude = kExcludeRadius * kExcludeRadius;
|
||||
auto square = 0.;
|
||||
while (true) {
|
||||
const auto start = QPointF(stake(), stake());
|
||||
square = start.x() * start.x() + start.y() * start.y();
|
||||
if (square > exclude) {
|
||||
star.start = start * _size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
square *= _size * _size;
|
||||
while (true) {
|
||||
const auto delta = QPointF(stake(), stake()) * kTravelMax * _size;
|
||||
const auto end = star.start + delta;
|
||||
if (end.x() * end.x() + end.y() * end.y() > square) {
|
||||
star.delta = delta;
|
||||
break;
|
||||
}
|
||||
}
|
||||
star.start = (star.start + QPointF(_size, _size)) / 2.;
|
||||
star.size = (kSizeMin + (kSizeMax - kSizeMin) * take()) * _size;
|
||||
}
|
||||
|
||||
int CollectibleEmoji::width() {
|
||||
return _inner->width();
|
||||
}
|
||||
|
||||
QString CollectibleEmoji::entityData() {
|
||||
return _entityData;
|
||||
}
|
||||
|
||||
void CollectibleEmoji::prepareFrame() {
|
||||
const auto clip = QSize(_size, _size);
|
||||
if (_frame.isNull()) {
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
_frame = QImage(clip * ratio, QImage::Format_ARGB32_Premultiplied);
|
||||
_frame.setDevicePixelRatio(ratio);
|
||||
}
|
||||
_frame.fill(Qt::transparent);
|
||||
auto p = QPainter(&_frame);
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
auto random = std::optional<base::BufferedRandom<uint32>>();
|
||||
const auto now = crl::now();
|
||||
for (auto &star : _stars) {
|
||||
if (star.deathTime <= now) {
|
||||
if (!random) {
|
||||
random.emplace(kStarsCount * 10);
|
||||
}
|
||||
const auto life = ChooseLife(*random);
|
||||
star.birthTime = now;
|
||||
star.deathTime = now + crl::time(life);
|
||||
refill(star, *random);
|
||||
}
|
||||
Assert(star.birthTime <= now && now <= star.deathTime);
|
||||
|
||||
const auto time = (now - star.birthTime)
|
||||
/ float64(star.deathTime - star.birthTime);
|
||||
const auto position = star.start + star.delta * time;
|
||||
const auto scale = ((now - star.birthTime) < kFading)
|
||||
? ((now - star.birthTime) / float64(kFading))
|
||||
: ((star.deathTime - now) < kFading)
|
||||
? ((star.deathTime - now) / float64(kFading))
|
||||
: 1.;
|
||||
if (scale > 0.) {
|
||||
const auto size = star.size * scale;
|
||||
const auto rect = QRectF(
|
||||
position - QPointF(size, size),
|
||||
QSizeF(size, size) * 2);
|
||||
_svg.render(&p, rect);
|
||||
}
|
||||
}
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
||||
auto gradient = QRadialGradient(
|
||||
QRect(QPoint(), clip).center(),
|
||||
clip.height() / 2);
|
||||
gradient.setStops({
|
||||
{ 0., _centerColor },
|
||||
{ 1., _edgeColor },
|
||||
});
|
||||
p.setBrush(gradient);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.drawRect(QRect(QPoint(), clip));
|
||||
}
|
||||
|
||||
void CollectibleEmoji::paint(QPainter &p, const Context &context) {
|
||||
prepareFrame();
|
||||
p.drawImage(context.position, _frame);
|
||||
if (context.paused) {
|
||||
_animation.stop();
|
||||
} else if (!_animation.animating()) {
|
||||
_animation.start();
|
||||
}
|
||||
_inner->paint(p, context);
|
||||
}
|
||||
|
||||
void CollectibleEmoji::unload() {
|
||||
_inner->unload();
|
||||
}
|
||||
|
||||
bool CollectibleEmoji::ready() {
|
||||
return _inner->ready();
|
||||
}
|
||||
|
||||
bool CollectibleEmoji::readyInDefaultState() {
|
||||
return _inner->readyInDefaultState();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ColoredMiniStars::ColoredMiniStars(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
|
@ -113,66 +323,7 @@ std::unique_ptr<Text::CustomEmoji> MakeCollectibleEmoji(
|
|||
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>(
|
||||
return std::make_unique<CollectibleEmoji>(
|
||||
entityData,
|
||||
centerColor,
|
||||
edgeColor,
|
||||
|
|
Loading…
Add table
Reference in a new issue