mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-07-27 07:52:57 +02:00
Show who released the gift.
This commit is contained in:
parent
f0aca45b11
commit
d05155a403
17 changed files with 400 additions and 11 deletions
|
@ -2863,6 +2863,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_credits_box_history_entry_gift_converted" = "Converted Gift";
|
"lng_credits_box_history_entry_gift_converted" = "Converted Gift";
|
||||||
"lng_credits_box_history_entry_gift_transfer" = "Gift Transfer";
|
"lng_credits_box_history_entry_gift_transfer" = "Gift Transfer";
|
||||||
"lng_credits_box_history_entry_gift_unavailable" = "Unavailable";
|
"lng_credits_box_history_entry_gift_unavailable" = "Unavailable";
|
||||||
|
"lng_credits_box_history_entry_gift_released" = "released by {name}";
|
||||||
"lng_credits_box_history_entry_gift_sold_out" = "This gift has sold out";
|
"lng_credits_box_history_entry_gift_sold_out" = "This gift has sold out";
|
||||||
"lng_credits_box_history_entry_gift_out_about" = "With Stars, **{user}** will be able to unlock content and services on Telegram.\n{link}";
|
"lng_credits_box_history_entry_gift_out_about" = "With Stars, **{user}** will be able to unlock content and services on Telegram.\n{link}";
|
||||||
"lng_credits_box_history_entry_gift_in_about" = "Use Stars to unlock content and services on Telegram. {link}";
|
"lng_credits_box_history_entry_gift_in_about" = "Use Stars to unlock content and services on Telegram. {link}";
|
||||||
|
@ -3581,12 +3582,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_gift_self_about" = "Buy yourself a gift to display on your page or reserve for later.\n\nLimited-edition gifts upgraded to collectibles can be gifted to others later.";
|
"lng_gift_self_about" = "Buy yourself a gift to display on your page or reserve for later.\n\nLimited-edition gifts upgraded to collectibles can be gifted to others later.";
|
||||||
"lng_gift_channel_title" = "Send a Gift";
|
"lng_gift_channel_title" = "Send a Gift";
|
||||||
"lng_gift_channel_about" = "Select a gift to show appreciation for {name}.";
|
"lng_gift_channel_about" = "Select a gift to show appreciation for {name}.";
|
||||||
|
"lng_gift_released_by" = "Released by {name}";
|
||||||
"lng_gift_unique_owner" = "Owner";
|
"lng_gift_unique_owner" = "Owner";
|
||||||
"lng_gift_unique_address_copied" = "Address copied to clipboard.";
|
"lng_gift_unique_address_copied" = "Address copied to clipboard.";
|
||||||
"lng_gift_unique_status" = "Status";
|
"lng_gift_unique_status" = "Status";
|
||||||
"lng_gift_unique_status_non" = "Non-Unique";
|
"lng_gift_unique_status_non" = "Non-Unique";
|
||||||
"lng_gift_unique_status_upgrade" = "upgrade";
|
"lng_gift_unique_status_upgrade" = "upgrade";
|
||||||
"lng_gift_unique_number" = "Collectible #{index}";
|
"lng_gift_unique_number" = "Collectible #{index}";
|
||||||
|
"lng_gift_unique_number_by" = "Collectible #{index} by {name}";
|
||||||
"lng_gift_unique_model" = "Model";
|
"lng_gift_unique_model" = "Model";
|
||||||
"lng_gift_unique_backdrop" = "Backdrop";
|
"lng_gift_unique_backdrop" = "Backdrop";
|
||||||
"lng_gift_unique_symbol" = "Symbol";
|
"lng_gift_unique_symbol" = "Symbol";
|
||||||
|
|
|
@ -867,6 +867,7 @@ std::optional<Data::StarGift> FromTL(
|
||||||
.ownerId = (data.vowner_id()
|
.ownerId = (data.vowner_id()
|
||||||
? peerFromMTP(*data.vowner_id())
|
? peerFromMTP(*data.vowner_id())
|
||||||
: PeerId()),
|
: PeerId()),
|
||||||
|
.releasedBy = releasedBy,
|
||||||
.number = data.vnum().v,
|
.number = data.vnum().v,
|
||||||
.starsForResale = int(data.vresell_stars().value_or_empty()),
|
.starsForResale = int(data.vresell_stars().value_or_empty()),
|
||||||
.model = *model,
|
.model = *model,
|
||||||
|
|
|
@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "chat_helpers/stickers_lottie.h"
|
#include "chat_helpers/stickers_lottie.h"
|
||||||
#include "chat_helpers/tabbed_panel.h"
|
#include "chat_helpers/tabbed_panel.h"
|
||||||
#include "chat_helpers/tabbed_selector.h"
|
#include "chat_helpers/tabbed_selector.h"
|
||||||
|
#include "core/application.h"
|
||||||
#include "core/ui_integration.h"
|
#include "core/ui_integration.h"
|
||||||
#include "data/components/promo_suggestions.h"
|
#include "data/components/promo_suggestions.h"
|
||||||
#include "data/data_birthday.h"
|
#include "data/data_birthday.h"
|
||||||
|
@ -94,6 +95,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/wrap/slide_wrap.h"
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
#include "window/section_widget.h"
|
#include "window/section_widget.h"
|
||||||
|
#include "window/window_controller.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
|
@ -333,6 +335,69 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TextBubblePart final : public MediaGenericTextPart {
|
||||||
|
public:
|
||||||
|
TextBubblePart(
|
||||||
|
TextWithEntities text,
|
||||||
|
QMargins margins,
|
||||||
|
const style::TextStyle &st = st::defaultTextStyle,
|
||||||
|
const base::flat_map<uint16, ClickHandlerPtr> &links = {},
|
||||||
|
const Ui::Text::MarkedContext &context = {},
|
||||||
|
style::align align = style::al_top);
|
||||||
|
|
||||||
|
void draw(
|
||||||
|
Painter &p,
|
||||||
|
not_null<const MediaGeneric*> owner,
|
||||||
|
const PaintContext &context,
|
||||||
|
int outerWidth) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupPen(
|
||||||
|
Painter &p,
|
||||||
|
not_null<const MediaGeneric*> owner,
|
||||||
|
const PaintContext &context) const override;
|
||||||
|
int elisionLines() const override;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
TextBubblePart::TextBubblePart(
|
||||||
|
TextWithEntities text,
|
||||||
|
QMargins margins,
|
||||||
|
const style::TextStyle &st,
|
||||||
|
const base::flat_map<uint16, ClickHandlerPtr> &links,
|
||||||
|
const Ui::Text::MarkedContext &context,
|
||||||
|
style::align align)
|
||||||
|
: MediaGenericTextPart(std::move(text), margins, st, links, context, align) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextBubblePart::draw(
|
||||||
|
Painter &p,
|
||||||
|
not_null<const MediaGeneric*> owner,
|
||||||
|
const PaintContext &context,
|
||||||
|
int outerWidth) const {
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(context.st->msgServiceBg());
|
||||||
|
const auto radius = height() / 2.;
|
||||||
|
const auto left = (outerWidth - width()) / 2;
|
||||||
|
const auto r = QRect(left, 0, width(), height());
|
||||||
|
p.drawRoundedRect(r, radius, radius);
|
||||||
|
|
||||||
|
MediaGenericTextPart::draw(p, owner, context, outerWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextBubblePart::setupPen(
|
||||||
|
Painter &p,
|
||||||
|
not_null<const MediaGeneric*> owner,
|
||||||
|
const PaintContext &context) const {
|
||||||
|
auto pen = context.st->msgServiceFg()->c;
|
||||||
|
pen.setAlphaF(pen.alphaF() * 0.65);
|
||||||
|
p.setPen(pen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextBubblePart::elisionLines() const {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] AttributeId FromTL(const MTPStarGiftAttributeId &id) {
|
[[nodiscard]] AttributeId FromTL(const MTPStarGiftAttributeId &id) {
|
||||||
return id.match([&](const MTPDstarGiftAttributeIdBackdrop &data) {
|
return id.match([&](const MTPDstarGiftAttributeIdBackdrop &data) {
|
||||||
return AttributeId{
|
return AttributeId{
|
||||||
|
@ -526,6 +591,21 @@ auto GenerateGiftMedia(
|
||||||
st::giftBoxPreviewTitlePadding,
|
st::giftBoxPreviewTitlePadding,
|
||||||
{},
|
{},
|
||||||
context);
|
context);
|
||||||
|
|
||||||
|
if (v::is<GiftTypeStars>(descriptor)) {
|
||||||
|
const auto &stars = v::get<GiftTypeStars>(descriptor);
|
||||||
|
if (const auto by = stars.info.releasedBy) {
|
||||||
|
push(std::make_unique<TextBubblePart>(
|
||||||
|
tr::lng_gift_released_by(
|
||||||
|
tr::now,
|
||||||
|
lt_name,
|
||||||
|
Ui::Text::Link('@' + by->username()),
|
||||||
|
Ui::Text::WithEntities),
|
||||||
|
st::giftBoxReleasedByMargin,
|
||||||
|
st::defaultTextStyle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pushText(
|
pushText(
|
||||||
std::move(description),
|
std::move(description),
|
||||||
st::giftBoxPreviewTextPadding,
|
st::giftBoxPreviewTextPadding,
|
||||||
|
@ -778,7 +858,7 @@ void PreviewWrap::prepare(rpl::producer<GiftDetails> details) {
|
||||||
owned.get(),
|
owned.get(),
|
||||||
GenerateGiftMedia(owned.get(), _item.get(), _recipient, details),
|
GenerateGiftMedia(owned.get(), _item.get(), _recipient, details),
|
||||||
MediaGenericDescriptor{
|
MediaGenericDescriptor{
|
||||||
.maxWidth = st::chatIntroWidth,
|
.maxWidth = st::chatGiftPreviewWidth,
|
||||||
.service = true,
|
.service = true,
|
||||||
}));
|
}));
|
||||||
_item = std::move(owned);
|
_item = std::move(owned);
|
||||||
|
@ -3820,6 +3900,19 @@ void AddUniqueGiftCover(
|
||||||
Fn<void()> resaleClick) {
|
Fn<void()> resaleClick) {
|
||||||
const auto cover = container->add(object_ptr<RpWidget>(container));
|
const auto cover = container->add(object_ptr<RpWidget>(container));
|
||||||
|
|
||||||
|
struct Released {
|
||||||
|
Released() : white(QColor(255, 255, 255)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
style::owned_color white;
|
||||||
|
style::FlatLabel st;
|
||||||
|
PeerData *by = nullptr;
|
||||||
|
QColor bg;
|
||||||
|
};
|
||||||
|
const auto released = cover->lifetime().make_state<Released>();
|
||||||
|
released->st = st::uniqueGiftSubtitle;
|
||||||
|
released->st.palette.linkFg = released->white.color();
|
||||||
|
|
||||||
if (resalePrice) {
|
if (resalePrice) {
|
||||||
auto background = rpl::duplicate(
|
auto background = rpl::duplicate(
|
||||||
data
|
data
|
||||||
|
@ -3841,17 +3934,56 @@ void AddUniqueGiftCover(
|
||||||
st::uniqueGiftTitle);
|
st::uniqueGiftTitle);
|
||||||
title->setTextColorOverride(QColor(255, 255, 255));
|
title->setTextColorOverride(QColor(255, 255, 255));
|
||||||
auto subtitleText = subtitleOverride
|
auto subtitleText = subtitleOverride
|
||||||
? std::move(subtitleOverride)
|
? std::move(subtitleOverride) | Ui::Text::ToWithEntities()
|
||||||
: rpl::duplicate(data) | rpl::map([](const Data::UniqueGift &gift) {
|
: rpl::duplicate(data) | rpl::map([=](const Data::UniqueGift &gift) {
|
||||||
return tr::lng_gift_unique_number(
|
released->by = gift.releasedBy;
|
||||||
|
released->bg = gift.backdrop.patternColor;
|
||||||
|
return gift.releasedBy
|
||||||
|
? tr::lng_gift_unique_number_by(
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_index,
|
lt_index,
|
||||||
QString::number(gift.number));
|
TextWithEntities{ QString::number(gift.number) },
|
||||||
|
lt_name,
|
||||||
|
Ui::Text::Link('@' + gift.releasedBy->username()),
|
||||||
|
Ui::Text::WithEntities)
|
||||||
|
: tr::lng_gift_unique_number(
|
||||||
|
tr::now,
|
||||||
|
lt_index,
|
||||||
|
TextWithEntities{ QString::number(gift.number) },
|
||||||
|
Ui::Text::WithEntities);
|
||||||
});
|
});
|
||||||
const auto subtitle = CreateChild<FlatLabel>(
|
const auto subtitle = CreateChild<FlatLabel>(
|
||||||
cover,
|
cover,
|
||||||
std::move(subtitleText),
|
std::move(subtitleText),
|
||||||
st::uniqueGiftSubtitle);
|
released->st);
|
||||||
|
if (released->by) {
|
||||||
|
const auto button = CreateChild<AbstractButton>(cover);
|
||||||
|
subtitle->raise();
|
||||||
|
subtitle->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
|
||||||
|
button->setClickedCallback([=] {
|
||||||
|
GiftReleasedByHandler(released->by);
|
||||||
|
});
|
||||||
|
subtitle->geometryValue(
|
||||||
|
) | rpl::start_with_next([=](QRect geometry) {
|
||||||
|
button->setGeometry(
|
||||||
|
geometry.marginsAdded(st::giftBoxReleasedByMargin));
|
||||||
|
}, button->lifetime());
|
||||||
|
button->paintRequest() | rpl::start_with_next([=] {
|
||||||
|
auto p = QPainter(button);
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
const auto use = subtitle->textMaxWidth();
|
||||||
|
const auto add = button->width() - subtitle->width();
|
||||||
|
const auto full = use + add;
|
||||||
|
const auto left = (button->width() - full) / 2;
|
||||||
|
const auto height = button->height();
|
||||||
|
const auto radius = height / 2.;
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(released->bg);
|
||||||
|
p.setOpacity(0.5);
|
||||||
|
p.drawRoundedRect(left, 0, full, height, radius, radius);
|
||||||
|
}, button->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
struct GiftView {
|
struct GiftView {
|
||||||
QImage gradient;
|
QImage gradient;
|
||||||
|
@ -4417,6 +4549,24 @@ void ShowUniqueGiftSellBox(
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GiftReleasedByHandler(not_null<PeerData*> peer) {
|
||||||
|
const auto session = &peer->session();
|
||||||
|
const auto window = session->tryResolveWindow(peer);
|
||||||
|
if (window) {
|
||||||
|
window->showPeerHistory(peer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto account = not_null(&session->account());
|
||||||
|
if (const auto window = Core::App().windowFor(account)) {
|
||||||
|
window->invokeForSessionController(
|
||||||
|
&session->account(),
|
||||||
|
peer,
|
||||||
|
[=](not_null<Window::SessionController*> window) {
|
||||||
|
window->showPeerHistory(peer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct UpgradeArgs : StarGiftUpgradeArgs {
|
struct UpgradeArgs : StarGiftUpgradeArgs {
|
||||||
std::vector<Data::UniqueGiftModel> models;
|
std::vector<Data::UniqueGiftModel> models;
|
||||||
std::vector<Data::UniqueGiftPattern> patterns;
|
std::vector<Data::UniqueGiftPattern> patterns;
|
||||||
|
|
|
@ -82,6 +82,8 @@ void ShowUniqueGiftSellBox(
|
||||||
Data::SavedStarGiftId savedId,
|
Data::SavedStarGiftId savedId,
|
||||||
Settings::GiftWearBoxStyleOverride st);
|
Settings::GiftWearBoxStyleOverride st);
|
||||||
|
|
||||||
|
void GiftReleasedByHandler(not_null<PeerData*> peer);
|
||||||
|
|
||||||
struct PatternPoint {
|
struct PatternPoint {
|
||||||
QPointF position;
|
QPointF position;
|
||||||
float64 scale = 1.;
|
float64 scale = 1.;
|
||||||
|
|
|
@ -65,6 +65,7 @@ struct CreditsHistoryEntry final {
|
||||||
uint64 bareGiveawayMsgId = 0;
|
uint64 bareGiveawayMsgId = 0;
|
||||||
uint64 bareGiftStickerId = 0;
|
uint64 bareGiftStickerId = 0;
|
||||||
uint64 bareGiftOwnerId = 0;
|
uint64 bareGiftOwnerId = 0;
|
||||||
|
uint64 bareGiftReleasedById = 0;
|
||||||
uint64 bareGiftResaleRecipientId = 0;
|
uint64 bareGiftResaleRecipientId = 0;
|
||||||
uint64 bareActorId = 0;
|
uint64 bareActorId = 0;
|
||||||
uint64 bareEntryOwnerId = 0;
|
uint64 bareEntryOwnerId = 0;
|
||||||
|
|
|
@ -2569,7 +2569,9 @@ std::unique_ptr<HistoryView::Media> MediaGiftBox::createView(
|
||||||
message,
|
message,
|
||||||
HistoryView::GenerateUniqueGiftMedia(message, replacing, unique),
|
HistoryView::GenerateUniqueGiftMedia(message, replacing, unique),
|
||||||
HistoryView::MediaGenericDescriptor{
|
HistoryView::MediaGenericDescriptor{
|
||||||
.maxWidth = st::msgServiceGiftBoxSize.width(),
|
.maxWidth = (_data.stargiftReleasedBy
|
||||||
|
? st::msgServiceStarGiftByWidth
|
||||||
|
: st::msgServiceGiftBoxSize.width()),
|
||||||
.paintBg = HistoryView::UniqueGiftBg(message, unique),
|
.paintBg = HistoryView::UniqueGiftBg(message, unique),
|
||||||
.service = true,
|
.service = true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -144,6 +144,7 @@ struct GiftCode {
|
||||||
QString slug;
|
QString slug;
|
||||||
uint64 stargiftId = 0;
|
uint64 stargiftId = 0;
|
||||||
DocumentData *document = nullptr;
|
DocumentData *document = nullptr;
|
||||||
|
PeerData *stargiftReleasedBy = nullptr;
|
||||||
std::shared_ptr<UniqueGift> unique;
|
std::shared_ptr<UniqueGift> unique;
|
||||||
TextWithEntities message;
|
TextWithEntities message;
|
||||||
ChannelData *channel = nullptr;
|
ChannelData *channel = nullptr;
|
||||||
|
|
|
@ -44,6 +44,7 @@ struct UniqueGift {
|
||||||
QString ownerAddress;
|
QString ownerAddress;
|
||||||
QString ownerName;
|
QString ownerName;
|
||||||
PeerId ownerId = 0;
|
PeerId ownerId = 0;
|
||||||
|
PeerData *releasedBy = nullptr;
|
||||||
int number = 0;
|
int number = 0;
|
||||||
int starsForTransfer = -1;
|
int starsForTransfer = -1;
|
||||||
int starsForResale = -1;
|
int starsForResale = -1;
|
||||||
|
|
|
@ -6349,6 +6349,7 @@ void HistoryItem::applyAction(const MTPMessageAction &action) {
|
||||||
fields.stargiftId = gift->id;
|
fields.stargiftId = gift->id;
|
||||||
fields.starsToUpgrade = gift->starsToUpgrade;
|
fields.starsToUpgrade = gift->starsToUpgrade;
|
||||||
fields.document = gift->document;
|
fields.document = gift->document;
|
||||||
|
fields.stargiftReleasedBy = gift->releasedBy;
|
||||||
fields.limitedCount = gift->limitedCount;
|
fields.limitedCount = gift->limitedCount;
|
||||||
fields.limitedLeft = gift->limitedLeft;
|
fields.limitedLeft = gift->limitedLeft;
|
||||||
fields.count = gift->stars;
|
fields.count = gift->stars;
|
||||||
|
@ -6384,6 +6385,7 @@ void HistoryItem::applyAction(const MTPMessageAction &action) {
|
||||||
if (auto gift = Api::FromTL(&history()->session(), data.vgift())) {
|
if (auto gift = Api::FromTL(&history()->session(), data.vgift())) {
|
||||||
fields.stargiftId = gift->id;
|
fields.stargiftId = gift->id;
|
||||||
fields.document = gift->document;
|
fields.document = gift->document;
|
||||||
|
fields.stargiftReleasedBy = gift->releasedBy;
|
||||||
fields.limitedCount = gift->limitedCount;
|
fields.limitedCount = gift->limitedCount;
|
||||||
fields.limitedLeft = gift->limitedLeft;
|
fields.limitedLeft = gift->limitedLeft;
|
||||||
fields.count = gift->stars;
|
fields.count = gift->stars;
|
||||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "api/api_premium.h"
|
#include "api/api_premium.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "boxes/gift_premium_box.h" // ResolveGiftCode
|
#include "boxes/gift_premium_box.h" // ResolveGiftCode
|
||||||
|
#include "boxes/star_gift_box.h" // GiftReleasedByHandler
|
||||||
#include "chat_helpers/stickers_gift_box_pack.h"
|
#include "chat_helpers/stickers_gift_box_pack.h"
|
||||||
#include "core/click_handler_types.h" // ClickHandlerContext
|
#include "core/click_handler_types.h" // ClickHandlerContext
|
||||||
#include "data/stickers/data_custom_emoji.h"
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
|
@ -54,7 +55,9 @@ int PremiumGift::top() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int PremiumGift::width() {
|
int PremiumGift::width() {
|
||||||
return st::msgServiceStarGiftBoxWidth;
|
return _data.stargiftReleasedBy
|
||||||
|
? st::msgServiceStarGiftByWidth
|
||||||
|
: st::msgServiceStarGiftBoxWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize PremiumGift::size() {
|
QSize PremiumGift::size() {
|
||||||
|
@ -120,6 +123,18 @@ TextWithEntities PremiumGift::title() {
|
||||||
: tr::lng_prize_title(tr::now, WithEntities);
|
: tr::lng_prize_title(tr::now, WithEntities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextWithEntities PremiumGift::author() {
|
||||||
|
using namespace Ui::Text;
|
||||||
|
if (!_data.stargiftReleasedBy) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return tr::lng_gift_released_by(
|
||||||
|
tr::now,
|
||||||
|
lt_name,
|
||||||
|
Ui::Text::Link('@' + _data.stargiftReleasedBy->username()),
|
||||||
|
Ui::Text::WithEntities);
|
||||||
|
}
|
||||||
|
|
||||||
TextWithEntities PremiumGift::subtitle() {
|
TextWithEntities PremiumGift::subtitle() {
|
||||||
if (tonGift()) {
|
if (tonGift()) {
|
||||||
return tr::lng_action_gift_got_ton(tr::now, Ui::Text::WithEntities);
|
return tr::lng_action_gift_got_ton(tr::now, Ui::Text::WithEntities);
|
||||||
|
@ -319,6 +334,18 @@ ClickHandlerPtr PremiumGift::createViewLink() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClickHandlerPtr PremiumGift::authorLink() {
|
||||||
|
if (const auto by = _data.stargiftReleasedBy) {
|
||||||
|
if (!_authorLink) {
|
||||||
|
_authorLink = std::make_shared<LambdaClickHandler>([=] {
|
||||||
|
Ui::GiftReleasedByHandler(by);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return _authorLink;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
int PremiumGift::buttonSkip() {
|
int PremiumGift::buttonSkip() {
|
||||||
return st::msgServiceGiftBoxButtonMargins.top();
|
return st::msgServiceGiftBoxButtonMargins.top();
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ public:
|
||||||
int width() override;
|
int width() override;
|
||||||
QSize size() override;
|
QSize size() override;
|
||||||
TextWithEntities title() override;
|
TextWithEntities title() override;
|
||||||
|
TextWithEntities author() override;
|
||||||
TextWithEntities subtitle() override;
|
TextWithEntities subtitle() override;
|
||||||
rpl::producer<QString> button() override;
|
rpl::producer<QString> button() override;
|
||||||
std::optional<Ui::Premium::MiniStarsType> buttonMinistars() override;
|
std::optional<Ui::Premium::MiniStarsType> buttonMinistars() override;
|
||||||
|
@ -39,6 +40,7 @@ public:
|
||||||
const PaintContext &context,
|
const PaintContext &context,
|
||||||
const QRect &geometry) override;
|
const QRect &geometry) override;
|
||||||
ClickHandlerPtr createViewLink() override;
|
ClickHandlerPtr createViewLink() override;
|
||||||
|
ClickHandlerPtr authorLink() override;
|
||||||
|
|
||||||
bool hideServiceText() override;
|
bool hideServiceText() override;
|
||||||
void stickerClearLoopPlayed() override;
|
void stickerClearLoopPlayed() override;
|
||||||
|
@ -63,6 +65,7 @@ private:
|
||||||
const not_null<Element*> _parent;
|
const not_null<Element*> _parent;
|
||||||
const not_null<Data::MediaGiftBox*> _gift;
|
const not_null<Data::MediaGiftBox*> _gift;
|
||||||
const Data::GiftCode &_data;
|
const Data::GiftCode &_data;
|
||||||
|
ClickHandlerPtr _authorLink;
|
||||||
QImage _badgeCache;
|
QImage _badgeCache;
|
||||||
Info::PeerGifts::GiftBadge _badgeKey;
|
Info::PeerGifts::GiftBadge _badgeKey;
|
||||||
mutable std::optional<Sticker> _sticker;
|
mutable std::optional<Sticker> _sticker;
|
||||||
|
|
|
@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/rect.h"
|
#include "ui/rect.h"
|
||||||
#include "ui/power_saving.h"
|
#include "ui/power_saving.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_chat.h"
|
||||||
|
#include "styles/style_credits.h"
|
||||||
#include "styles/style_premium.h"
|
#include "styles/style_premium.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
|
|
||||||
|
@ -51,6 +52,11 @@ ServiceBox::ServiceBox(
|
||||||
.session = &parent->history()->session(),
|
.session = &parent->history()->session(),
|
||||||
.repaint = [parent] { parent->customEmojiRepaint(); },
|
.repaint = [parent] { parent->customEmojiRepaint(); },
|
||||||
}))
|
}))
|
||||||
|
, _author(
|
||||||
|
st::defaultTextStyle,
|
||||||
|
_content->author(),
|
||||||
|
kMarkupTextOptions,
|
||||||
|
_maxWidth)
|
||||||
, _subtitle(
|
, _subtitle(
|
||||||
st::premiumPreviewAbout.style,
|
st::premiumPreviewAbout.style,
|
||||||
Ui::Text::Filtered(
|
Ui::Text::Filtered(
|
||||||
|
@ -79,6 +85,12 @@ ServiceBox::ServiceBox(
|
||||||
? 0
|
? 0
|
||||||
: (_title.countHeight(_maxWidth)
|
: (_title.countHeight(_maxWidth)
|
||||||
+ st::msgServiceGiftBoxTitlePadding.bottom()))
|
+ st::msgServiceGiftBoxTitlePadding.bottom()))
|
||||||
|
+ (_author.isEmpty()
|
||||||
|
? 0
|
||||||
|
: (st::giftBoxReleasedByMargin.top()
|
||||||
|
+ st::defaultTextStyle.font->height
|
||||||
|
+ st::giftBoxReleasedByMargin.bottom()
|
||||||
|
+ st::msgServiceGiftBoxTitlePadding.bottom()))
|
||||||
+ _subtitle.countHeight(_maxWidth)
|
+ _subtitle.countHeight(_maxWidth)
|
||||||
+ (!_content->button()
|
+ (!_content->button()
|
||||||
? 0
|
? 0
|
||||||
|
@ -164,6 +176,37 @@ void ServiceBox::draw(Painter &p, const PaintContext &context) const {
|
||||||
});
|
});
|
||||||
top += _title.countHeight(_maxWidth) + padding.bottom();
|
top += _title.countHeight(_maxWidth) + padding.bottom();
|
||||||
}
|
}
|
||||||
|
if (!_author.isEmpty()) {
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(context.st->msgServiceBg());
|
||||||
|
const auto use = std::min(_maxWidth, _author.maxWidth())
|
||||||
|
+ st::giftBoxReleasedByMargin.left()
|
||||||
|
+ st::giftBoxReleasedByMargin.right();
|
||||||
|
const auto left = st::msgPadding.left() + (_maxWidth - use) / 2;
|
||||||
|
const auto height = st::giftBoxReleasedByMargin.top()
|
||||||
|
+ st::defaultTextStyle.font->height
|
||||||
|
+ st::giftBoxReleasedByMargin.bottom();
|
||||||
|
const auto radius = height / 2.;
|
||||||
|
p.drawRoundedRect(left, top, use, height, radius, radius);
|
||||||
|
|
||||||
|
auto fg = context.st->msgServiceFg()->c;
|
||||||
|
fg.setAlphaF(0.65 * fg.alphaF());
|
||||||
|
p.setPen(fg);
|
||||||
|
_author.draw(p, {
|
||||||
|
.position = QPoint(
|
||||||
|
left + st::giftBoxReleasedByMargin.left(),
|
||||||
|
top + st::giftBoxReleasedByMargin.top()),
|
||||||
|
.availableWidth = (use
|
||||||
|
- st::giftBoxReleasedByMargin.left()
|
||||||
|
- st::giftBoxReleasedByMargin.right()),
|
||||||
|
.palette = &context.st->serviceTextPalette(),
|
||||||
|
.elisionLines = 1,
|
||||||
|
});
|
||||||
|
p.setPen(context.st->msgServiceFg());
|
||||||
|
|
||||||
|
top += height + st::msgServiceGiftBoxTitlePadding.bottom();
|
||||||
|
}
|
||||||
_parent->prepareCustomEmojiPaint(p, context, _subtitle);
|
_parent->prepareCustomEmojiPaint(p, context, _subtitle);
|
||||||
_subtitle.draw(p, {
|
_subtitle.draw(p, {
|
||||||
.position = QPoint(st::msgPadding.left(), top),
|
.position = QPoint(st::msgPadding.left(), top),
|
||||||
|
@ -231,6 +274,23 @@ TextState ServiceBox::textState(QPoint point, StateRequest request) const {
|
||||||
if (!_title.isEmpty()) {
|
if (!_title.isEmpty()) {
|
||||||
top += _title.countHeight(_maxWidth) + padding.bottom();
|
top += _title.countHeight(_maxWidth) + padding.bottom();
|
||||||
}
|
}
|
||||||
|
if (!_author.isEmpty()) {
|
||||||
|
const auto use = std::min(_maxWidth, _author.maxWidth())
|
||||||
|
+ st::giftBoxReleasedByMargin.left()
|
||||||
|
+ st::giftBoxReleasedByMargin.right();
|
||||||
|
const auto left = st::msgPadding.left() + (_maxWidth - use) / 2;
|
||||||
|
const auto height = st::giftBoxReleasedByMargin.top()
|
||||||
|
+ st::defaultTextStyle.font->height
|
||||||
|
+ st::giftBoxReleasedByMargin.bottom();
|
||||||
|
if (point.x() >= left
|
||||||
|
&& point.y() >= top
|
||||||
|
&& point.x() < left + use
|
||||||
|
&& point.y() < top + height) {
|
||||||
|
result.link = _content->authorLink();
|
||||||
|
}
|
||||||
|
top += height + st::msgServiceGiftBoxTitlePadding.bottom();
|
||||||
|
}
|
||||||
|
|
||||||
auto subtitleRequest = request.forText();
|
auto subtitleRequest = request.forText();
|
||||||
subtitleRequest.align = style::al_top;
|
subtitleRequest.align = style::al_top;
|
||||||
const auto state = _subtitle.getState(
|
const auto state = _subtitle.getState(
|
||||||
|
|
|
@ -28,6 +28,9 @@ public:
|
||||||
[[nodiscard]] virtual int top() = 0;
|
[[nodiscard]] virtual int top() = 0;
|
||||||
[[nodiscard]] virtual QSize size() = 0;
|
[[nodiscard]] virtual QSize size() = 0;
|
||||||
[[nodiscard]] virtual TextWithEntities title() = 0;
|
[[nodiscard]] virtual TextWithEntities title() = 0;
|
||||||
|
[[nodiscard]] virtual TextWithEntities author() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
[[nodiscard]] virtual TextWithEntities subtitle() = 0;
|
[[nodiscard]] virtual TextWithEntities subtitle() = 0;
|
||||||
[[nodiscard]] virtual int buttonSkip() {
|
[[nodiscard]] virtual int buttonSkip() {
|
||||||
return top();
|
return top();
|
||||||
|
@ -45,6 +48,9 @@ public:
|
||||||
const PaintContext &context,
|
const PaintContext &context,
|
||||||
const QRect &geometry) = 0;
|
const QRect &geometry) = 0;
|
||||||
[[nodiscard]] virtual ClickHandlerPtr createViewLink() = 0;
|
[[nodiscard]] virtual ClickHandlerPtr createViewLink() = 0;
|
||||||
|
[[nodiscard]] virtual ClickHandlerPtr authorLink() {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] virtual bool hideServiceText() = 0;
|
[[nodiscard]] virtual bool hideServiceText() = 0;
|
||||||
|
|
||||||
|
@ -123,6 +129,7 @@ private:
|
||||||
|
|
||||||
const int _maxWidth = 0;
|
const int _maxWidth = 0;
|
||||||
Ui::Text::String _title;
|
Ui::Text::String _title;
|
||||||
|
Ui::Text::String _author;
|
||||||
Ui::Text::String _subtitle;
|
Ui::Text::String _subtitle;
|
||||||
const QSize _size;
|
const QSize _size;
|
||||||
const QSize _innerSize;
|
const QSize _innerSize;
|
||||||
|
|
|
@ -81,6 +81,95 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TextBubblePart final : public MediaGenericTextPart {
|
||||||
|
public:
|
||||||
|
TextBubblePart(
|
||||||
|
TextWithEntities text,
|
||||||
|
QMargins margins,
|
||||||
|
Data::UniqueGiftBackdrop backdrop,
|
||||||
|
ClickHandlerPtr link);
|
||||||
|
|
||||||
|
void draw(
|
||||||
|
Painter &p,
|
||||||
|
not_null<const MediaGeneric*> owner,
|
||||||
|
const PaintContext &context,
|
||||||
|
int outerWidth) const override;
|
||||||
|
TextState textState(
|
||||||
|
QPoint point,
|
||||||
|
StateRequest request,
|
||||||
|
int outerWidth) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupPen(
|
||||||
|
Painter &p,
|
||||||
|
not_null<const MediaGeneric*> owner,
|
||||||
|
const PaintContext &context) const override;
|
||||||
|
int elisionLines() const override;
|
||||||
|
|
||||||
|
Data::UniqueGiftBackdrop _backdrop;
|
||||||
|
ClickHandlerPtr _link;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
TextBubblePart::TextBubblePart(
|
||||||
|
TextWithEntities text,
|
||||||
|
QMargins margins,
|
||||||
|
Data::UniqueGiftBackdrop backdrop,
|
||||||
|
ClickHandlerPtr link)
|
||||||
|
: MediaGenericTextPart(
|
||||||
|
std::move(text),
|
||||||
|
margins,
|
||||||
|
st::defaultTextStyle,
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
style::al_top)
|
||||||
|
, _backdrop(backdrop)
|
||||||
|
, _link(std::move(link)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextBubblePart::draw(
|
||||||
|
Painter &p,
|
||||||
|
not_null<const MediaGeneric*> owner,
|
||||||
|
const PaintContext &context,
|
||||||
|
int outerWidth) const {
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setOpacity(0.5);
|
||||||
|
p.setBrush(_backdrop.patternColor);
|
||||||
|
const auto radius = height() / 2.;
|
||||||
|
const auto left = (outerWidth - width()) / 2;
|
||||||
|
const auto r = QRect(left, 0, width(), height());
|
||||||
|
p.drawRoundedRect(r, radius, radius);
|
||||||
|
p.setOpacity(1.);
|
||||||
|
|
||||||
|
MediaGenericTextPart::draw(p, owner, context, outerWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextState TextBubblePart::textState(
|
||||||
|
QPoint point,
|
||||||
|
StateRequest request,
|
||||||
|
int outerWidth) const {
|
||||||
|
auto result = TextState();
|
||||||
|
const auto left = (outerWidth - width()) / 2;
|
||||||
|
if (point.x() >= left
|
||||||
|
&& point.y() >= 0
|
||||||
|
&& point.x() < left + width()
|
||||||
|
&& point.y() < height()) {
|
||||||
|
result.link = _link;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextBubblePart::setupPen(
|
||||||
|
Painter &p,
|
||||||
|
not_null<const MediaGeneric*> owner,
|
||||||
|
const PaintContext &context) const {
|
||||||
|
p.setPen(_backdrop.textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextBubblePart::elisionLines() const {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
ButtonPart::ButtonPart(
|
ButtonPart::ButtonPart(
|
||||||
const QString &text,
|
const QString &text,
|
||||||
QMargins margins,
|
QMargins margins,
|
||||||
|
@ -284,6 +373,21 @@ auto GenerateUniqueGiftMedia(
|
||||||
gift->backdrop.textColor,
|
gift->backdrop.textColor,
|
||||||
st::chatUniqueTextPadding);
|
st::chatUniqueTextPadding);
|
||||||
|
|
||||||
|
if (const auto by = gift->releasedBy) {
|
||||||
|
const auto handler = std::make_shared<LambdaClickHandler>([=] {
|
||||||
|
Ui::GiftReleasedByHandler(by);
|
||||||
|
});
|
||||||
|
push(std::make_unique<TextBubblePart>(
|
||||||
|
tr::lng_gift_released_by(
|
||||||
|
tr::now,
|
||||||
|
lt_name,
|
||||||
|
Ui::Text::Link('@' + by->username()),
|
||||||
|
Ui::Text::WithEntities),
|
||||||
|
st::giftBoxReleasedByMargin,
|
||||||
|
gift->backdrop,
|
||||||
|
handler));
|
||||||
|
}
|
||||||
|
|
||||||
const auto name = [](const Data::UniqueGiftAttribute &value) {
|
const auto name = [](const Data::UniqueGiftAttribute &value) {
|
||||||
return Ui::Text::Bold(value.name);
|
return Ui::Text::Bold(value.name);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1434,7 +1434,23 @@ void GenericCreditsEntryBox(
|
||||||
|
|
||||||
Ui::AddSkip(content);
|
Ui::AddSkip(content);
|
||||||
}
|
}
|
||||||
if (!isStarGift || creditsHistoryStarGift || e.soldOutInfo) {
|
if (e.bareGiftReleasedById && !e.uniqueGift) {
|
||||||
|
const auto peer = owner->peer(PeerId(e.bareGiftReleasedById));
|
||||||
|
const auto released = content->add(
|
||||||
|
object_ptr<Ui::CenterWrap<Ui::FlatLabel>>(
|
||||||
|
box,
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
content,
|
||||||
|
tr::lng_credits_box_history_entry_gift_released(
|
||||||
|
lt_name,
|
||||||
|
rpl::single(Ui::Text::Link('@' + peer->username())),
|
||||||
|
Ui::Text::WithEntities),
|
||||||
|
st::creditsReleasedByLabel)));
|
||||||
|
released->entity()->setClickHandlerFilter([=](const auto &...) {
|
||||||
|
Ui::GiftReleasedByHandler(peer);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
} else if (!isStarGift || creditsHistoryStarGift || e.soldOutInfo) {
|
||||||
constexpr auto kMinus = QChar(0x2212);
|
constexpr auto kMinus = QChar(0x2212);
|
||||||
auto &lifetime = content->lifetime();
|
auto &lifetime = content->lifetime();
|
||||||
const auto text = lifetime.make_state<Ui::Text::String>();
|
const auto text = lifetime.make_state<Ui::Text::String>();
|
||||||
|
@ -2282,6 +2298,9 @@ void StarGiftViewBox(
|
||||||
.bareGiftOwnerId = (data.unique
|
.bareGiftOwnerId = (data.unique
|
||||||
? data.unique->ownerId.value
|
? data.unique->ownerId.value
|
||||||
: toId.value),
|
: toId.value),
|
||||||
|
.bareGiftReleasedById = (data.stargiftReleasedBy
|
||||||
|
? data.stargiftReleasedBy->id.value
|
||||||
|
: 0),
|
||||||
.bareActorId = (toChannel ? data.channelFrom->id.value : 0),
|
.bareActorId = (toChannel ? data.channelFrom->id.value : 0),
|
||||||
.bareEntryOwnerId = (toChannel ? data.channel->id.value : 0),
|
.bareEntryOwnerId = (toChannel ? data.channel->id.value : 0),
|
||||||
.giftChannelSavedId = data.channelSavedId,
|
.giftChannelSavedId = data.channelSavedId,
|
||||||
|
|
|
@ -936,6 +936,7 @@ msgServiceGiftBoxTitlePadding: margins(0px, 20px, 0px, 6px);
|
||||||
msgServiceGiftBoxStickerTop: -19px;
|
msgServiceGiftBoxStickerTop: -19px;
|
||||||
msgServiceGiftBoxStickerSize: 140px;
|
msgServiceGiftBoxStickerSize: 140px;
|
||||||
msgServiceStarGiftBoxWidth: 224px;
|
msgServiceStarGiftBoxWidth: 224px;
|
||||||
|
msgServiceStarGiftByWidth: 272px;
|
||||||
msgServiceStarGiftStickerTop: 24px;
|
msgServiceStarGiftStickerTop: 24px;
|
||||||
msgServiceStarGiftStickerSize: 100px;
|
msgServiceStarGiftStickerSize: 100px;
|
||||||
|
|
||||||
|
@ -1105,6 +1106,7 @@ chatIntroWidth: 224px;
|
||||||
chatIntroTitleMargin: margins(11px, 16px, 11px, 4px);
|
chatIntroTitleMargin: margins(11px, 16px, 11px, 4px);
|
||||||
chatIntroMargin: margins(11px, 0px, 11px, 0px);
|
chatIntroMargin: margins(11px, 0px, 11px, 0px);
|
||||||
chatIntroStickerPadding: margins(10px, 8px, 10px, 16px);
|
chatIntroStickerPadding: margins(10px, 8px, 10px, 16px);
|
||||||
|
chatGiftPreviewWidth: 264px;
|
||||||
|
|
||||||
liveLocationLongInIcon: icon {{ "chat/live_location_long", msgInServiceFg }};
|
liveLocationLongInIcon: icon {{ "chat/live_location_long", msgInServiceFg }};
|
||||||
liveLocationLongInIconSelected: icon {{ "chat/live_location_long", msgInServiceFgSelected }};
|
liveLocationLongInIconSelected: icon {{ "chat/live_location_long", msgInServiceFgSelected }};
|
||||||
|
|
|
@ -66,6 +66,9 @@ creditsBoxAboutDivider: FlatLabel(boxDividerLabel) {
|
||||||
creditsBoxButtonLabel: FlatLabel(defaultFlatLabel) {
|
creditsBoxButtonLabel: FlatLabel(defaultFlatLabel) {
|
||||||
style: semiboldTextStyle;
|
style: semiboldTextStyle;
|
||||||
}
|
}
|
||||||
|
creditsReleasedByLabel: FlatLabel(defaultFlatLabel) {
|
||||||
|
textFg: windowSubTextFg;
|
||||||
|
}
|
||||||
|
|
||||||
starIconEmoji: IconEmoji {
|
starIconEmoji: IconEmoji {
|
||||||
icon: icon{{ "payments/premium_emoji", creditsBg1 }};
|
icon: icon{{ "payments/premium_emoji", creditsBg1 }};
|
||||||
|
@ -175,6 +178,7 @@ giftBoxButtonBottomByStars: 18px;
|
||||||
giftBoxButtonPadding: margins(8px, 4px, 8px, 4px);
|
giftBoxButtonPadding: margins(8px, 4px, 8px, 4px);
|
||||||
giftBoxPreviewStickerPadding: margins(10px, 12px, 10px, 16px);
|
giftBoxPreviewStickerPadding: margins(10px, 12px, 10px, 16px);
|
||||||
giftBoxPreviewTitlePadding: margins(12px, 4px, 12px, 4px);
|
giftBoxPreviewTitlePadding: margins(12px, 4px, 12px, 4px);
|
||||||
|
giftBoxReleasedByMargin: margins(12px, 2px, 12px, 2px);
|
||||||
giftBoxPreviewTextPadding: margins(12px, 4px, 12px, 4px);
|
giftBoxPreviewTextPadding: margins(12px, 4px, 12px, 4px);
|
||||||
giftBoxButtonMargin: margins(12px, 8px, 12px, 12px);
|
giftBoxButtonMargin: margins(12px, 8px, 12px, 12px);
|
||||||
giftBoxStickerTop: 0px;
|
giftBoxStickerTop: 0px;
|
||||||
|
|
Loading…
Add table
Reference in a new issue