mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 15:17:07 +02:00
Improve gift corner badge display.
This commit is contained in:
parent
549de7fa54
commit
e6060ea277
10 changed files with 295 additions and 153 deletions
Telegram/SourceFiles
|
@ -1528,7 +1528,7 @@ void SendGiftBox(
|
|||
bool sending = false;
|
||||
};
|
||||
const auto state = raw->lifetime().make_state<State>(State{
|
||||
.delegate = Delegate(window),
|
||||
.delegate = Delegate(window, GiftButtonMode::Full),
|
||||
});
|
||||
const auto single = state->delegate.buttonSize();
|
||||
const auto shadow = st::defaultDropdownMenu.wrap.shadow;
|
||||
|
@ -1575,7 +1575,7 @@ void SendGiftBox(
|
|||
for (auto i = 0; i != count; ++i) {
|
||||
const auto button = state->buttons[i].get();
|
||||
const auto &descriptor = gifts.list[order[i]];
|
||||
button->setDescriptor(descriptor);
|
||||
button->setDescriptor(descriptor, GiftButton::Mode::Full);
|
||||
|
||||
const auto last = !((i + 1) % perRow);
|
||||
if (last) {
|
||||
|
|
|
@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "settings/settings_credits_graphics.h"
|
||||
#include "settings/settings_credits_graphics.h" // GiftedCreditsBox
|
||||
#include "settings/settings_premium.h" // Settings::ShowGiftPremium
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
@ -300,20 +301,35 @@ void PremiumGift::draw(
|
|||
}
|
||||
}
|
||||
|
||||
QString PremiumGift::cornerTagText() {
|
||||
QImage PremiumGift::cornerTag(const PaintContext &context) {
|
||||
auto badge = Info::PeerGifts::GiftBadge();
|
||||
if (_data.unique) {
|
||||
return tr::lng_gift_collectible_tag(tr::now);
|
||||
badge = {
|
||||
.text = tr::lng_gift_collectible_tag(tr::now),
|
||||
.bg = _data.unique->backdrop.patternColor,
|
||||
.fg = QColor(255, 255, 255),
|
||||
};
|
||||
} else if (const auto count = _data.limitedCount) {
|
||||
return (count == 1)
|
||||
? tr::lng_gift_limited_of_one(tr::now)
|
||||
: tr::lng_gift_limited_of_count(
|
||||
tr::now,
|
||||
lt_amount,
|
||||
((count % 1000)
|
||||
? Lang::FormatCountDecimal(count)
|
||||
: Lang::FormatCountToShort(count).string));
|
||||
badge = {
|
||||
.text = ((count == 1)
|
||||
? tr::lng_gift_limited_of_one(tr::now)
|
||||
: tr::lng_gift_limited_of_count(
|
||||
tr::now,
|
||||
lt_amount,
|
||||
(((count % 1000) && (count < 10'000))
|
||||
? Lang::FormatCountDecimal(count)
|
||||
: Lang::FormatCountToShort(count).string))),
|
||||
.bg = context.st->msgServiceBg()->c,
|
||||
.fg = context.st->msgServiceFg()->c,
|
||||
};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
return QString();
|
||||
if (_badgeCache.isNull() || _badgeKey != badge) {
|
||||
_badgeKey = badge;
|
||||
_badgeCache = ValidateRotatedBadge(badge, 0);
|
||||
}
|
||||
return _badgeCache;
|
||||
}
|
||||
|
||||
bool PremiumGift::hideServiceText() {
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "history/view/media/history_view_sticker.h"
|
||||
#include "history/view/media/history_view_service_box.h"
|
||||
#include "info/peer_gifts/info_peer_gifts_common.h"
|
||||
|
||||
namespace Data {
|
||||
class MediaGiftBox;
|
||||
|
@ -30,7 +31,7 @@ public:
|
|||
TextWithEntities subtitle() override;
|
||||
rpl::producer<QString> button() override;
|
||||
bool buttonMinistars() override;
|
||||
QString cornerTagText() override;
|
||||
QImage cornerTag(const PaintContext &context) override;
|
||||
int buttonSkip() override;
|
||||
void draw(
|
||||
Painter &p,
|
||||
|
@ -60,6 +61,8 @@ private:
|
|||
const not_null<Element*> _parent;
|
||||
const not_null<Data::MediaGiftBox*> _gift;
|
||||
const Data::GiftCode &_data;
|
||||
QImage _badgeCache;
|
||||
Info::PeerGifts::GiftBadge _badgeKey;
|
||||
mutable std::optional<Sticker> _sticker;
|
||||
|
||||
};
|
||||
|
|
|
@ -199,28 +199,9 @@ void ServiceBox::draw(Painter &p, const PaintContext &context) const {
|
|||
|
||||
_content->draw(p, context, content);
|
||||
|
||||
if (const auto tag = _content->cornerTagText(); !tag.isEmpty()) {
|
||||
const auto font = st::semiboldFont;
|
||||
p.setFont(font);
|
||||
p.setPen(Qt::NoPen);
|
||||
const auto twidth = font->width(tag);
|
||||
const auto pos = QPoint(_innerSize.width() - twidth, font->height);
|
||||
const auto add = 0;// style::ConvertScale(2);
|
||||
p.save();
|
||||
p.setClipRect(
|
||||
-add,
|
||||
-add,
|
||||
_innerSize.width() + 2 * add,
|
||||
_innerSize.height() + 2 * add);
|
||||
p.translate(pos);
|
||||
p.rotate(45.);
|
||||
p.translate(-pos);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(context.st->msgServiceBg()); // ?
|
||||
p.drawRect(-5 * twidth, 0, twidth * 12, font->height);
|
||||
p.setPen(context.st->msgServiceFg());
|
||||
p.drawText(pos - QPoint(0, font->descent), tag);
|
||||
p.restore();
|
||||
if (const auto tag = _content->cornerTag(context); !tag.isNull()) {
|
||||
const auto width = tag.width() / tag.devicePixelRatio();
|
||||
p.drawImage(_innerSize.width() - width, 0, tag);
|
||||
}
|
||||
|
||||
p.translate(0, -st::msgServiceGiftBoxTopSkip);
|
||||
|
|
|
@ -11,11 +11,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Ui {
|
||||
class RippleAnimation;
|
||||
namespace Premium {
|
||||
class ColoredMiniStars;
|
||||
} // namespace Premium
|
||||
} // namespace Ui
|
||||
|
||||
namespace Ui::Premium {
|
||||
class ColoredMiniStars;
|
||||
} // namespace Ui::Premium
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
class ServiceBoxContent {
|
||||
|
@ -34,7 +35,7 @@ public:
|
|||
[[nodiscard]] virtual bool buttonMinistars() {
|
||||
return false;
|
||||
}
|
||||
[[nodiscard]] virtual QString cornerTagText() {
|
||||
[[nodiscard]] virtual QImage cornerTag(const PaintContext &context) {
|
||||
return {};
|
||||
}
|
||||
virtual void draw(
|
||||
|
|
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/history_view_element.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "info/peer_gifts/info_peer_gifts_common.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "settings/settings_credits_graphics.h"
|
||||
|
@ -490,6 +491,8 @@ Fn<void(Painter&, const Ui::ChatPaintContext &)> UniqueGiftBg(
|
|||
QImage bg;
|
||||
base::flat_map<float64, QImage> cache;
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> pattern;
|
||||
QImage badgeCache;
|
||||
Info::PeerGifts::GiftBadge badgeKey;
|
||||
};
|
||||
const auto state = std::make_shared<State>();
|
||||
state->pattern = view->history()->owner().customEmojiManager().create(
|
||||
|
@ -531,29 +534,28 @@ Fn<void(Painter&, const Ui::ChatPaintContext &)> UniqueGiftBg(
|
|||
Ui::PaintPoints(p, state->cache, state->pattern.get(), *gift, outer);
|
||||
p.setClipping(false);
|
||||
|
||||
p.save();
|
||||
p.translate(inner.topLeft());
|
||||
const auto tag = tr::lng_gift_collectible_tag(tr::now);
|
||||
const auto font = st::semiboldFont;
|
||||
p.setFont(font);
|
||||
p.setPen(Qt::NoPen);
|
||||
const auto twidth = font->width(tag);
|
||||
const auto pos = QPoint(inner.width() - twidth, font->height);
|
||||
const auto add = style::ConvertScale(2);
|
||||
p.setClipRect(
|
||||
-add,
|
||||
-add,
|
||||
inner.x() - add,
|
||||
inner.y() - add,
|
||||
inner.width() + 2 * add,
|
||||
inner.height() + 2 * add);
|
||||
p.translate(pos);
|
||||
p.rotate(45.);
|
||||
p.translate(-pos);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(gift->backdrop.patternColor);
|
||||
p.drawRect(-5 * twidth, 0, twidth * 12, font->height);
|
||||
p.setPen(gift->backdrop.textColor);
|
||||
p.drawText(pos - QPoint(0, font->descent), tag);
|
||||
p.restore();
|
||||
auto badge = Info::PeerGifts::GiftBadge{
|
||||
.text = tr::lng_gift_collectible_tag(tr::now),
|
||||
.bg = gift->backdrop.patternColor,
|
||||
.fg = gift->backdrop.textColor,
|
||||
};
|
||||
if (state->badgeCache.isNull() || state->badgeKey != badge) {
|
||||
state->badgeKey = badge;
|
||||
state->badgeCache = ValidateRotatedBadge(badge, add);
|
||||
}
|
||||
const auto badgeRatio = state->badgeCache.devicePixelRatio();
|
||||
const auto badgeWidth = state->badgeCache.width() / badgeRatio;
|
||||
p.drawImage(
|
||||
inner.x() + inner.width() + add - badgeWidth,
|
||||
inner.y() - add,
|
||||
state->badgeCache);
|
||||
p.setClipping(false);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -37,12 +37,23 @@ constexpr auto kGiftsPerRow = 3;
|
|||
|
||||
} // namespace
|
||||
|
||||
std::strong_ordering operator<=>(const GiftBadge &a, const GiftBadge &b) {
|
||||
const auto result1 = (a.text <=> b.text);
|
||||
if (result1 != std::strong_ordering::equal) {
|
||||
return result1;
|
||||
}
|
||||
const auto result2 = (a.bg.rgb() <=> b.bg.rgb());
|
||||
if (result2 != std::strong_ordering::equal) {
|
||||
return result2;
|
||||
}
|
||||
return a.fg.rgb() <=> b.fg.rgb();
|
||||
}
|
||||
|
||||
GiftButton::GiftButton(
|
||||
QWidget *parent,
|
||||
not_null<GiftButtonDelegate*> delegate)
|
||||
: AbstractButton(parent)
|
||||
, _delegate(delegate)
|
||||
, _stars(this, true, Ui::Premium::MiniStars::Type::SlowStars) {
|
||||
, _delegate(delegate) {
|
||||
}
|
||||
|
||||
GiftButton::~GiftButton() {
|
||||
|
@ -55,11 +66,12 @@ void GiftButton::unsubscribe() {
|
|||
}
|
||||
}
|
||||
|
||||
void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
|
||||
void GiftButton::setDescriptor(const GiftDescriptor &descriptor, Mode mode) {
|
||||
if (_descriptor == descriptor) {
|
||||
return;
|
||||
}
|
||||
auto player = base::take(_player);
|
||||
const auto starsType = Ui::Premium::MiniStars::Type::SlowStars;
|
||||
_mediaLifetime.destroy();
|
||||
_descriptor = descriptor;
|
||||
unsubscribe();
|
||||
|
@ -82,7 +94,10 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
|
|||
data.currency,
|
||||
true));
|
||||
_userpic = nullptr;
|
||||
_stars.setColorOverride(QGradientStops{
|
||||
if (!_stars) {
|
||||
_stars.emplace(this, true, starsType);
|
||||
}
|
||||
_stars->setColorOverride(QGradientStops{
|
||||
{ 0., anim::with_alpha(st::windowActiveTextFg->c, .3) },
|
||||
{ 1., st::windowActiveTextFg->c },
|
||||
});
|
||||
|
@ -91,6 +106,16 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
|
|||
const auto soldOut = data.info.limitedCount
|
||||
&& !data.userpic
|
||||
&& !data.info.limitedLeft;
|
||||
_userpic = !data.userpic
|
||||
? nullptr
|
||||
: data.from
|
||||
? Ui::MakeUserpicThumbnail(data.from)
|
||||
: Ui::MakeHiddenAuthorThumbnail();
|
||||
if (mode == Mode::Minimal) {
|
||||
_price = {};
|
||||
_stars.reset();
|
||||
return;
|
||||
}
|
||||
_price.setMarkedText(
|
||||
st::semiboldTextStyle,
|
||||
(unique
|
||||
|
@ -99,24 +124,20 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
|
|||
' ' + QString::number(data.info.stars))),
|
||||
kMarkupTextOptions,
|
||||
_delegate->textContext());
|
||||
_userpic = !data.userpic
|
||||
? nullptr
|
||||
: data.from
|
||||
? Ui::MakeUserpicThumbnail(data.from)
|
||||
: Ui::MakeHiddenAuthorThumbnail();
|
||||
if (!_stars) {
|
||||
_stars.emplace(this, true, starsType);
|
||||
}
|
||||
if (unique) {
|
||||
const auto white = QColor(255, 255, 255);
|
||||
_stars.setColorOverride(QGradientStops{
|
||||
_stars->setColorOverride(QGradientStops{
|
||||
{ 0., anim::with_alpha(white, .3) },
|
||||
{ 1., white },
|
||||
});
|
||||
} else if (soldOut) {
|
||||
_stars.setColorOverride(QGradientStops{
|
||||
{ 0., Qt::transparent },
|
||||
{ 1., Qt::transparent },
|
||||
});
|
||||
_stars.reset();
|
||||
} else {
|
||||
_stars.setColorOverride(Ui::Premium::CreditsIconGradientStops());
|
||||
_stars->setColorOverride(
|
||||
Ui::Premium::CreditsIconGradientStops());
|
||||
}
|
||||
});
|
||||
_delegate->sticker(
|
||||
|
@ -125,6 +146,10 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
|
|||
setDocument(document);
|
||||
}, lifetime());
|
||||
|
||||
if (mode != Mode::Full) {
|
||||
_button = QRect();
|
||||
return;
|
||||
}
|
||||
const auto buttonw = _price.maxWidth();
|
||||
const auto buttonh = st::semiboldFont->height;
|
||||
const auto inner = QRect(
|
||||
|
@ -137,9 +162,9 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) {
|
|||
const auto skipx = (width() - inner.width()) / 2;
|
||||
const auto outer = (width() - 2 * skipx);
|
||||
_button = QRect(skipx, skipy, outer, inner.height());
|
||||
{
|
||||
if (_stars) {
|
||||
const auto padding = _button.height() / 2;
|
||||
_stars.setCenter(_button - QMargins(padding, 0, padding, 0));
|
||||
_stars->setCenter(_button - QMargins(padding, 0, padding, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,8 +218,10 @@ void GiftButton::setGeometry(QRect inner, QMargins extend) {
|
|||
void GiftButton::resizeEvent(QResizeEvent *e) {
|
||||
if (!_button.isEmpty()) {
|
||||
_button.moveLeft((width() - _button.width()) / 2);
|
||||
const auto padding = _button.height() / 2;
|
||||
_stars.setCenter(_button - QMargins(padding, 0, padding, 0));
|
||||
if (_stars) {
|
||||
const auto padding = _button.height() / 2;
|
||||
_stars->setCenter(_button - QMargins(padding, 0, padding, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,76 +365,85 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
const auto singlew = width - _extend.left() - _extend.right();
|
||||
const auto font = st::semiboldFont;
|
||||
p.setFont(font);
|
||||
const auto text = v::match(_descriptor, [&](GiftTypePremium data) {
|
||||
|
||||
const auto badge = v::match(_descriptor, [&](GiftTypePremium data) {
|
||||
if (data.discountPercent > 0) {
|
||||
p.setBrush(st::attentionButtonFg);
|
||||
const auto kMinus = QChar(0x2212);
|
||||
return kMinus + QString::number(data.discountPercent) + '%';
|
||||
return GiftBadge{
|
||||
.text = kMinus + QString::number(data.discountPercent) + '%',
|
||||
.bg = st::attentionButtonFg->c,
|
||||
.fg = st::windowBg->c,
|
||||
};
|
||||
}
|
||||
return QString();
|
||||
return GiftBadge();
|
||||
}, [&](const GiftTypeStars &data) {
|
||||
if (const auto count = data.info.limitedCount) {
|
||||
const auto soldOut = !data.userpic && !data.info.limitedLeft;
|
||||
p.setBrush(unique
|
||||
? QBrush(unique->backdrop.patternColor)
|
||||
: soldOut
|
||||
? st::attentionButtonFg
|
||||
: st::windowActiveTextFg);
|
||||
return soldOut
|
||||
? tr::lng_gift_stars_sold_out(tr::now)
|
||||
: !data.userpic
|
||||
? tr::lng_gift_stars_limited(tr::now)
|
||||
: (count == 1)
|
||||
? tr::lng_gift_limited_of_one(tr::now)
|
||||
: tr::lng_gift_limited_of_count(
|
||||
tr::now,
|
||||
lt_amount,
|
||||
((count % 1000)
|
||||
? Lang::FormatCountDecimal(count)
|
||||
: Lang::FormatCountToShort(count).string));
|
||||
return GiftBadge{
|
||||
.text = (soldOut
|
||||
? tr::lng_gift_stars_sold_out(tr::now)
|
||||
: !data.userpic
|
||||
? tr::lng_gift_stars_limited(tr::now)
|
||||
: (count == 1)
|
||||
? tr::lng_gift_limited_of_one(tr::now)
|
||||
: tr::lng_gift_limited_of_count(
|
||||
tr::now,
|
||||
lt_amount,
|
||||
(((count % 1000) && (count < 10'000))
|
||||
? Lang::FormatCountDecimal(count)
|
||||
: Lang::FormatCountToShort(count).string))),
|
||||
.bg = (unique
|
||||
? unique->backdrop.patternColor
|
||||
: soldOut
|
||||
? st::attentionButtonFg->c
|
||||
: st::windowActiveTextFg->c),
|
||||
.fg = unique ? QColor(255, 255, 255) : st::windowBg->c,
|
||||
};
|
||||
}
|
||||
return QString();
|
||||
return GiftBadge();
|
||||
});
|
||||
if (!text.isEmpty()) {
|
||||
p.setPen(Qt::NoPen);
|
||||
const auto twidth = font->width(text);
|
||||
const auto pos = position + QPoint(singlew - twidth, font->height);
|
||||
p.save();
|
||||
|
||||
if (badge) {
|
||||
const auto rubberOut = _extend.top();
|
||||
const auto inner = rect().marginsRemoved(_extend);
|
||||
p.setClipRect(inner.marginsAdded(
|
||||
{ rubberOut, rubberOut, rubberOut, rubberOut }));
|
||||
p.translate(pos);
|
||||
p.rotate(45.);
|
||||
p.translate(-pos);
|
||||
p.drawRect(-5 * twidth, position.y(), twidth * 12, font->height);
|
||||
p.setPen(unique ? QPen(QColor(255, 255, 255)) : st::windowBg);
|
||||
p.drawText(pos - QPoint(0, font->descent), text);
|
||||
p.restore();
|
||||
|
||||
const auto cached = _delegate->cachedBadge(badge);
|
||||
const auto width = cached.width() / cached.devicePixelRatio();
|
||||
p.drawImage(
|
||||
position.x() + singlew + _extend.top() - width,
|
||||
position.y() - _extend.top(),
|
||||
cached);
|
||||
}
|
||||
p.setBrush(unique
|
||||
? QBrush(QColor(255, 255, 255, .2 * 255))
|
||||
: premium
|
||||
? st::lightButtonBgOver
|
||||
: st::creditsBg3);
|
||||
p.setPen(Qt::NoPen);
|
||||
if (!unique && !premium) {
|
||||
p.setOpacity(0.12);
|
||||
}
|
||||
const auto geometry = _button;
|
||||
const auto radius = geometry.height() / 2.;
|
||||
p.drawRoundedRect(geometry, radius, radius);
|
||||
if (!premium) {
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
if (unique) {
|
||||
_stars.paint(p);
|
||||
} else {
|
||||
auto clipPath = QPainterPath();
|
||||
clipPath.addRoundedRect(geometry, radius, radius);
|
||||
p.setClipPath(clipPath);
|
||||
_stars.paint(p);
|
||||
p.setClipping(false);
|
||||
if (!_button.isEmpty()) {
|
||||
p.setBrush(unique
|
||||
? QBrush(QColor(255, 255, 255, .2 * 255))
|
||||
: premium
|
||||
? st::lightButtonBgOver
|
||||
: st::creditsBg3);
|
||||
p.setPen(Qt::NoPen);
|
||||
if (!unique && !premium) {
|
||||
p.setOpacity(0.12);
|
||||
}
|
||||
const auto geometry = _button;
|
||||
const auto radius = geometry.height() / 2.;
|
||||
p.drawRoundedRect(geometry, radius, radius);
|
||||
if (!premium) {
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
if (_stars) {
|
||||
if (unique) {
|
||||
_stars->paint(p);
|
||||
} else {
|
||||
auto clipPath = QPainterPath();
|
||||
clipPath.addRoundedRect(geometry, radius, radius);
|
||||
p.setClipPath(clipPath);
|
||||
_stars->paint(p);
|
||||
p.setClipping(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_text.isEmpty()) {
|
||||
|
@ -420,25 +456,30 @@ void GiftButton::paintEvent(QPaintEvent *e) {
|
|||
});
|
||||
}
|
||||
|
||||
const auto padding = st::giftBoxButtonPadding;
|
||||
p.setPen(unique
|
||||
? QPen(QColor(255, 255, 255))
|
||||
: premium
|
||||
? st::windowActiveTextFg
|
||||
: st::creditsFg);
|
||||
_price.draw(p, {
|
||||
.position = (geometry.topLeft()
|
||||
+ QPoint(padding.left(), padding.top())),
|
||||
.availableWidth = _price.maxWidth(),
|
||||
});
|
||||
if (!_button.isEmpty()) {
|
||||
const auto padding = st::giftBoxButtonPadding;
|
||||
p.setPen(unique
|
||||
? QPen(QColor(255, 255, 255))
|
||||
: premium
|
||||
? st::windowActiveTextFg
|
||||
: st::creditsFg);
|
||||
_price.draw(p, {
|
||||
.position = (_button.topLeft()
|
||||
+ QPoint(padding.left(), padding.top())),
|
||||
.availableWidth = _price.maxWidth(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Delegate::Delegate(not_null<Window::SessionController*> window)
|
||||
Delegate::Delegate(
|
||||
not_null<Window::SessionController*> window,
|
||||
GiftButtonMode mode)
|
||||
: _window(window)
|
||||
, _hiddenMark(std::make_unique<StickerPremiumMark>(
|
||||
&window->session(),
|
||||
st::giftBoxHiddenMark,
|
||||
RectPart::Center)) {
|
||||
RectPart::Center))
|
||||
, _mode(mode) {
|
||||
}
|
||||
|
||||
Delegate::Delegate(Delegate &&other) = default;
|
||||
|
@ -466,7 +507,10 @@ QSize Delegate::buttonSize() {
|
|||
const auto available = width - padding.left() - padding.right();
|
||||
const auto singlew = (available - 2 * st::giftBoxGiftSkip.x())
|
||||
/ kGiftsPerRow;
|
||||
_single = QSize(singlew, st::giftBoxGiftHeight);
|
||||
const auto minimal = (_mode == GiftButtonMode::Minimal);
|
||||
_single = QSize(
|
||||
singlew,
|
||||
minimal ? st::giftBoxGiftSmall : st::giftBoxGiftHeight);
|
||||
return _single;
|
||||
}
|
||||
|
||||
|
@ -542,6 +586,15 @@ not_null<StickerPremiumMark*> Delegate::hiddenMark() {
|
|||
return _hiddenMark.get();
|
||||
}
|
||||
|
||||
QImage Delegate::cachedBadge(const GiftBadge &badge) {
|
||||
auto &image = _badges[badge];
|
||||
if (image.isNull()) {
|
||||
const auto &extend = buttonExtend();
|
||||
image = ValidateRotatedBadge(badge, extend.top());
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
DocumentData *LookupGiftSticker(
|
||||
not_null<Main::Session*> session,
|
||||
const GiftDescriptor &descriptor) {
|
||||
|
@ -577,7 +630,57 @@ rpl::producer<not_null<DocumentData*>> GiftStickerValue(
|
|||
}, [&](GiftTypeStars data) {
|
||||
return rpl::single(data.info.document) | rpl::type_erased();
|
||||
});
|
||||
}
|
||||
|
||||
QImage ValidateRotatedBadge(const GiftBadge &badge, int added) {
|
||||
const auto &font = st::semiboldFont;
|
||||
const auto twidth = font->width(badge.text) + 2 * added;
|
||||
const auto skip = int(std::ceil(twidth / M_SQRT2));
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
const auto multiplier = ratio * 3;
|
||||
const auto size = (twidth + font->height * 2);
|
||||
const auto textpos = QPoint(size - skip, added);
|
||||
auto image = QImage(
|
||||
QSize(size, size) * multiplier,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
image.fill(Qt::transparent);
|
||||
image.setDevicePixelRatio(multiplier);
|
||||
{
|
||||
auto p = QPainter(&image);
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.translate(textpos);
|
||||
p.rotate(45.);
|
||||
p.setFont(font);
|
||||
p.setPen(badge.fg);
|
||||
p.drawText(QPoint(added, font->ascent), badge.text);
|
||||
}
|
||||
|
||||
auto scaled = image.scaled(
|
||||
QSize(size, size) * ratio,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
scaled.setDevicePixelRatio(ratio);
|
||||
|
||||
auto result = QImage(
|
||||
QSize(size, size) * ratio,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(ratio);
|
||||
result.fill(Qt::transparent);
|
||||
{
|
||||
auto p = QPainter(&result);
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(badge.bg);
|
||||
|
||||
p.save();
|
||||
p.translate(textpos);
|
||||
p.rotate(45.);
|
||||
p.drawRect(-5 * twidth, 0, twidth * 12, font->height);
|
||||
p.restore();
|
||||
|
||||
p.drawImage(0, 0, scaled);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Info::PeerGifts
|
||||
|
|
|
@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/qt/qt_compare.h"
|
||||
#include "data/data_star_gift.h"
|
||||
#include "ui/abstract_button.h"
|
||||
#include "ui/effects/premium_stars_colored.h"
|
||||
|
@ -71,6 +72,29 @@ struct GiftDescriptor : std::variant<GiftTypePremium, GiftTypeStars> {
|
|||
const GiftDescriptor&) = default;
|
||||
};
|
||||
|
||||
struct GiftBadge {
|
||||
QString text;
|
||||
QColor bg;
|
||||
QColor fg;
|
||||
|
||||
explicit operator bool() const {
|
||||
return !text.isEmpty();
|
||||
}
|
||||
|
||||
friend std::strong_ordering operator<=>(
|
||||
const GiftBadge &a,
|
||||
const GiftBadge &b);
|
||||
|
||||
friend inline bool operator==(
|
||||
const GiftBadge &,
|
||||
const GiftBadge &) = default;
|
||||
};
|
||||
|
||||
enum class GiftButtonMode {
|
||||
Full,
|
||||
Minimal,
|
||||
};
|
||||
|
||||
class GiftButtonDelegate {
|
||||
public:
|
||||
[[nodiscard]] virtual TextWithEntities star() = 0;
|
||||
|
@ -85,6 +109,7 @@ public:
|
|||
[[nodiscard]] virtual rpl::producer<not_null<DocumentData*>> sticker(
|
||||
const GiftDescriptor &descriptor) = 0;
|
||||
[[nodiscard]] virtual not_null<StickerPremiumMark*> hiddenMark() = 0;
|
||||
[[nodiscard]] virtual QImage cachedBadge(const GiftBadge &badge) = 0;
|
||||
};
|
||||
|
||||
class GiftButton final : public Ui::AbstractButton {
|
||||
|
@ -92,7 +117,9 @@ public:
|
|||
GiftButton(QWidget *parent, not_null<GiftButtonDelegate*> delegate);
|
||||
~GiftButton();
|
||||
|
||||
void setDescriptor(const GiftDescriptor &descriptor);
|
||||
|
||||
using Mode = GiftButtonMode;
|
||||
void setDescriptor(const GiftDescriptor &descriptor, Mode mode);
|
||||
void setGeometry(QRect inner, QMargins extend);
|
||||
|
||||
private:
|
||||
|
@ -118,7 +145,7 @@ private:
|
|||
QImage _uniqueBackgroundCache;
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> _uniquePatternEmoji;
|
||||
base::flat_map<float64, QImage> _uniquePatternCache;
|
||||
Ui::Premium::ColoredMiniStars _stars;
|
||||
std::optional<Ui::Premium::ColoredMiniStars> _stars;
|
||||
bool _subscribed = false;
|
||||
bool _patterned = false;
|
||||
|
||||
|
@ -132,7 +159,9 @@ private:
|
|||
|
||||
class Delegate final : public GiftButtonDelegate {
|
||||
public:
|
||||
explicit Delegate(not_null<Window::SessionController*> window);
|
||||
Delegate(
|
||||
not_null<Window::SessionController*> window,
|
||||
GiftButtonMode mode);
|
||||
Delegate(Delegate &&other);
|
||||
~Delegate();
|
||||
|
||||
|
@ -148,12 +177,15 @@ public:
|
|||
rpl::producer<not_null<DocumentData*>> sticker(
|
||||
const GiftDescriptor &descriptor) override;
|
||||
not_null<StickerPremiumMark*> hiddenMark() override;
|
||||
QImage cachedBadge(const GiftBadge &badge) override;
|
||||
|
||||
private:
|
||||
const not_null<Window::SessionController*> _window;
|
||||
std::unique_ptr<StickerPremiumMark> _hiddenMark;
|
||||
base::flat_map<GiftBadge, QImage> _badges;
|
||||
QSize _single;
|
||||
QImage _bg;
|
||||
GiftButtonMode _mode = GiftButtonMode::Full;
|
||||
|
||||
};
|
||||
|
||||
|
@ -165,4 +197,6 @@ private:
|
|||
not_null<Main::Session*> session,
|
||||
const GiftDescriptor &descriptor);
|
||||
|
||||
[[nodiscard]] QImage ValidateRotatedBadge(const GiftBadge &badge, int added);
|
||||
|
||||
} // namespace Info::PeerGifts
|
||||
|
|
|
@ -116,7 +116,7 @@ InnerWidget::InnerWidget(
|
|||
not_null<UserData*> user)
|
||||
: BoxContentDivider(parent)
|
||||
, _window(controller->parentController())
|
||||
, _delegate(_window)
|
||||
, _delegate(_window, GiftButtonMode::Minimal)
|
||||
, _controller(controller)
|
||||
, _about(std::make_unique<Ui::FlatLabel>(
|
||||
this,
|
||||
|
@ -271,6 +271,7 @@ void InnerWidget::validateButtons() {
|
|||
const auto fullw = _perRow * (_single.width() + skipw) - skipw;
|
||||
const auto left = padding.left() + (available - fullw) / 2;
|
||||
const auto oneh = _single.height() + st::giftBoxGiftSkip.y();
|
||||
const auto mode = GiftButton::Mode::Minimal;
|
||||
auto x = left;
|
||||
auto y = vskip + fromRow * oneh;
|
||||
auto views = std::vector<View>();
|
||||
|
@ -301,7 +302,7 @@ void InnerWidget::validateButtons() {
|
|||
.entry = index,
|
||||
});
|
||||
}
|
||||
views.back().button->setDescriptor(descriptor);
|
||||
views.back().button->setDescriptor(descriptor, mode);
|
||||
views.back().button->setClickedCallback(callback);
|
||||
};
|
||||
for (auto j = fromRow; j != tillRow; ++j) {
|
||||
|
|
|
@ -112,6 +112,7 @@ giftBoxTabBgActive: windowBgRipple;
|
|||
giftBoxPadding: margins(20px, 4px, 20px, 24px);
|
||||
giftBoxGiftSkip: point(10px, 8px);
|
||||
giftBoxGiftHeight: 164px;
|
||||
giftBoxGiftSmall: 124px;
|
||||
giftBoxGiftRadius: 12px;
|
||||
giftBoxPremiumIconSize: 64px;
|
||||
giftBoxPremiumIconTop: 10px;
|
||||
|
|
Loading…
Add table
Reference in a new issue