Add quantity badge to giveaway message.

This commit is contained in:
John Preston 2023-10-06 12:07:27 +04:00
parent b08869abdb
commit caca679336
4 changed files with 98 additions and 5 deletions

View File

@ -2102,6 +2102,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_prizes_how_when_new_of_one#other" = "On {date}, Telegram will automatically select {count} random users that joined {channel} after {start_date}";
"lng_prizes_how_when_new_of_many#one" = "On {date}, Telegram will automatically select {count} random user that joined {channel} or other listed channels after {start_date}";
"lng_prizes_how_when_new_of_many#other" = "On {date}, Telegram will automatically select {count} random users that joined {channel} or other listed channels after {start_date}";
"lng_prizes_badge" = "x{amount}";
"lng_gift_link_title" = "Gift Link";
"lng_gift_link_about" = "This link allows you to activate\na **Telegram Premium** subscription.";

View File

@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "ui/chat/chat_style.h"
#include "ui/chat/message_bubble.h"
#include "ui/text/text_utilities.h"
#include "ui/widgets/tooltip.h"
#include "ui/painter.h"
@ -83,21 +84,22 @@ Giveaway::~Giveaway() {
void Giveaway::fillFromData(not_null<Data::Giveaway*> giveaway) {
_months = giveaway->months;
_quantity = giveaway->quantity;
_prizesTitle.setText(
st::semiboldTextStyle,
tr::lng_prizes_title(tr::now, lt_count, giveaway->quantity),
tr::lng_prizes_title(tr::now, lt_count, _quantity),
kDefaultTextOptions);
const auto duration = (giveaway->months < 12)
? tr::lng_months(tr::now, lt_count, giveaway->months)
: tr::lng_years(tr::now, lt_count, giveaway->months / 12);
const auto duration = (_months < 12)
? tr::lng_months(tr::now, lt_count, _months)
: tr::lng_years(tr::now, lt_count, _months / 12);
_prizes.setMarkedText(
st::defaultTextStyle,
tr::lng_prizes_about(
tr::now,
lt_count,
giveaway->quantity,
_quantity,
lt_duration,
Ui::Text::Bold(duration),
Ui::Text::RichLangValue),
@ -242,6 +244,7 @@ void Giveaway::draw(Painter &p, const PaintContext &context) const {
if (_sticker) {
_sticker->draw(p, context, sticker);
paintBadge(p, context);
} else {
ensureStickerCreated();
}
@ -268,6 +271,41 @@ void Giveaway::draw(Painter &p, const PaintContext &context) const {
paintChannels(p, context);
}
void Giveaway::paintBadge(Painter &p, const PaintContext &context) const {
validateBadge(context);
const auto badge = _badge.size() / _badge.devicePixelRatio();
const auto left = (width() - badge.width()) / 2;
const auto top = st::chatGiveawayBadgeTop;
const auto rect = QRect(left, top, badge.width(), badge.height());
const auto paintContent = [&](QPainter &q) {
q.drawImage(rect.topLeft(), _badge);
};
{
auto hq = PainterHighQualityEnabler(p);
p.setPen(Qt::NoPen);
p.setBrush(context.messageStyle()->msgFileBg);
const auto half = st::chatGiveawayBadgeStroke / 2.;
const auto inner = QRectF(rect).marginsRemoved(
{ half, half, half, half });
const auto radius = inner.height() / 2.;
p.drawRoundedRect(inner, radius, radius);
}
if (!usesBubblePattern(context)) {
paintContent(p);
} else {
Ui::PaintPatternBubblePart(
p,
context.viewport,
context.bubblesPattern->pixmap,
rect,
paintContent,
_badgeCache);
}
}
void Giveaway::paintChannels(
Painter &p,
const PaintContext &context) const {
@ -333,6 +371,49 @@ void Giveaway::ensureStickerCreated() const {
}
}
void Giveaway::validateBadge(const PaintContext &context) const {
const auto stm = context.messageStyle();
const auto &badgeFg = stm->historyFileRadialFg->c;
const auto &badgeBorder = stm->msgBg->c;
if (!_badge.isNull()
&& _badgeFg == badgeFg
&& _badgeBorder == badgeBorder) {
return;
}
const auto &font = st::chatGiveawayBadgeFont;
_badgeFg = badgeFg;
_badgeBorder = badgeBorder;
const auto text = tr::lng_prizes_badge(
tr::now,
lt_amount,
QString::number(_quantity));
const auto width = font->width(text);
const auto inner = QRect(0, 0, width, font->height);
const auto rect = inner.marginsAdded(st::chatGiveawayBadgePadding);
const auto size = rect.size();
const auto ratio = style::DevicePixelRatio();
_badge = QImage(size * ratio, QImage::Format_ARGB32_Premultiplied);
_badge.setDevicePixelRatio(ratio);
_badge.fill(Qt::transparent);
auto p = QPainter(&_badge);
auto hq = PainterHighQualityEnabler(p);
p.setPen(QPen(_badgeBorder, st::chatGiveawayBadgeStroke * 1.));
p.setBrush(Qt::NoBrush);
const auto half = st::chatGiveawayBadgeStroke / 2.;
const auto smaller = QRectF(
rect.translated(-rect.topLeft())
).marginsRemoved({ half, half, half, half });
const auto radius = smaller.height() / 2.;
p.drawRoundedRect(smaller, radius, radius);
p.setPen(_badgeFg);
p.setFont(font);
p.drawText(
st::chatGiveawayBadgePadding.left(),
st::chatGiveawayBadgePadding.top() + font->ascent,
text);
}
TextState Giveaway::textState(QPoint point, StateRequest request) const {
auto result = TextState(_parent);

View File

@ -59,6 +59,7 @@ private:
ClickHandlerPtr link;
};
void paintBadge(Painter &p, const PaintContext &context) const;
void paintChannels(Painter &p, const PaintContext &context) const;
int layoutChannels(int x, int y, int available);
QSize countOptimalSize() override;
@ -66,6 +67,7 @@ private:
void fillFromData(not_null<Data::Giveaway*> giveaway);
void ensureStickerCreated() const;
void validateBadge(const PaintContext &context) const;
[[nodiscard]] QMargins inBubblePadding() const;
@ -80,9 +82,14 @@ private:
Ui::Text::String _winners;
mutable QColor _channelBg;
mutable QColor _badgeFg;
mutable QColor _badgeBorder;
mutable std::array<QImage, 4> _channelCorners;
mutable QImage _badge;
mutable QImage _badgeCache;
int _months = 0;
int _quantity = 0;
int _stickerTop = 0;
int _prizesTitleTop = 0;
int _prizesTop = 0;

View File

@ -934,6 +934,10 @@ storyMentionButtonSkip: 5px;
chatGiveawayWidth: 292px;
chatGiveawayStickerTop: -16px;
chatGiveawayBadgeFont: font(12px bold);
chatGiveawayBadgeTop: 106px;
chatGiveawayBadgePadding: margins(7px, 1px, 5px, 3px);
chatGiveawayBadgeStroke: 2px;
chatGiveawayPrizesTop: 16px;
chatGiveawayPrizesSkip: 4px;
chatGiveawayParticipantsTop: 16px;