diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 4b6d36107..c6b359c52 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1855,6 +1855,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_action_gift_received" = "{user} sent you a gift for {cost}"; "lng_action_gift_received_me" = "You sent to {user} a gift for {cost}"; "lng_action_gift_received_anonymous" = "Unknown user sent you a gift for {cost}"; +"lng_action_gift_anonymous" = "Anonymous Gift"; +"lng_action_gift_got_subtitle" = "Gift from {user}"; +"lng_action_gift_got_stars_text" = "Display this gift on your page or convert it to {cost}."; "lng_action_suggested_photo_me" = "You suggested this photo for {user}'s Telegram profile."; "lng_action_suggested_photo" = "{user} suggests this photo for your Telegram profile."; "lng_action_suggested_photo_button" = "View Photo"; @@ -2991,6 +2994,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_gift_stars_limited" = "limited"; "lng_gift_stars_tabs_all" = "All Gifts"; "lng_gift_stars_tabs_limited" = "Limited"; +"lng_gift_send_title" = "Send a Gift"; +"lng_gift_send_message" = "Enter Message"; +"lng_gift_send_anonymous" = "Hide My Name"; +"lng_gift_send_anonymous_about" = "You can hide your name and message from visitors to {user}'s profile. {recipient} will still see your name and message."; +"lng_gift_send_button" = "Send a Gift for {cost}"; "lng_accounts_limit_title" = "Limit Reached"; "lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected account."; diff --git a/Telegram/SourceFiles/boxes/gift_credits_box.cpp b/Telegram/SourceFiles/boxes/gift_credits_box.cpp index 48d68f324..e1f76509e 100644 --- a/Telegram/SourceFiles/boxes/gift_credits_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_credits_box.cpp @@ -10,18 +10,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_credits.h" #include "api/api_premium.h" #include "boxes/peer_list_controllers.h" +#include "boxes/send_credits_box.h" +#include "chat_helpers/stickers_gift_box_pack.h" +#include "chat_helpers/stickers_lottie.h" #include "data/data_peer.h" #include "data/data_session.h" #include "data/data_user.h" #include "data/stickers/data_custom_emoji.h" +#include "history/admin_log/history_admin_log_item.h" #include "history/view/media/history_view_sticker_player.h" +#include "history/view/media/history_view_media_generic.h" +#include "history/view/history_view_element.h" +#include "history/history.h" +#include "history/history_item.h" +#include "history/history_item_helpers.h" #include "lang/lang_keys.h" #include "main/session/session_show.h" #include "main/main_session.h" #include "settings/settings_credits_graphics.h" #include "settings/settings_credits.h" #include "settings/settings_premium.h" +#include "ui/chat/chat_style.h" +#include "ui/chat/chat_theme.h" #include "ui/controls/userpic_button.h" +#include "ui/effects/path_shift_gradient.h" #include "ui/effects/premium_graphics.h" #include "ui/effects/premium_stars_colored.h" #include "ui/effects/ripple_animation.h" @@ -31,8 +43,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text/format_values.h" #include "ui/text/text_utilities.h" #include "ui/vertical_list.h" +#include "ui/widgets/fields/input_field.h" #include "ui/widgets/label_with_custom_emoji.h" #include "ui/widgets/shadow.h" +#include "window/themes/window_theme.h" +#include "window/section_widget.h" #include "window/window_session_controller.h" #include "styles/style_boxes.h" #include "styles/style_channel_earn.h" @@ -41,9 +56,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_giveaway.h" #include "styles/style_layers.h" #include "styles/style_premium.h" +#include "styles/style_settings.h" #include "data/stickers/data_stickers.h" #include "data/data_document.h" +#include "data/data_document_media.h" namespace Ui { namespace { @@ -51,6 +68,9 @@ namespace { constexpr auto kPriceTabAll = 0; constexpr auto kPriceTabLimited = -1; constexpr auto kGiftsPerRow = 3; +constexpr auto kGiftMessageLimit = 256; + +using namespace HistoryView; struct GiftTypePremium { int64 cost = 0; @@ -81,6 +101,259 @@ struct GiftDescriptor : std::variant { const GiftDescriptor&) = default; }; +struct GiftDetails { + GiftDescriptor descriptor; + QString text; + bool anonymous = false; +}; + +class PreviewDelegate final : public DefaultElementDelegate { +public: + PreviewDelegate( + not_null parent, + not_null st, + Fn update); + + bool elementAnimationsPaused() override; + not_null elementPathShiftGradient() override; + Context elementContext() override; + +private: + const not_null _parent; + const std::unique_ptr _pathGradient; + +}; + +class PreviewWrap final : public Ui::RpWidget { +public: + PreviewWrap( + not_null parent, + not_null session, + rpl::producer details); + ~PreviewWrap(); + +private: + void paintEvent(QPaintEvent *e) override; + + void resizeTo(int width); + void prepare(rpl::producer details); + + const not_null _history; + const std::unique_ptr _theme; + const std::unique_ptr _style; + const std::unique_ptr _delegate; + AdminLog::OwnedItem _item; + QPoint _position; + +}; + +PreviewDelegate::PreviewDelegate( + not_null parent, + not_null st, + Fn update) +: _parent(parent) +, _pathGradient(MakePathShiftGradient(st, update)) { +} + +bool PreviewDelegate::elementAnimationsPaused() { + return _parent->window()->isActiveWindow(); +} + +auto PreviewDelegate::elementPathShiftGradient() +-> not_null { + return _pathGradient.get(); +} + +Context PreviewDelegate::elementContext() { + return Context::History; +} + +auto GenerateGiftMedia( + not_null parent, + Element *replacing, + const GiftDetails &data) +-> Fn)>)> { + return [=](Fn)> push) { + const auto &descriptor = data.descriptor; + auto pushText = [&]( + TextWithEntities text, + QMargins margins = {}, + const base::flat_map &links = {}) { + if (text.empty()) { + return; + } + push(std::make_unique( + std::move(text), + margins, + links)); + }; + const auto sticker = [=] { + using Tag = ChatHelpers::StickerLottieSize; + const auto &session = parent->history()->session(); + auto &packs = session.giftBoxStickersPacks(); + packs.load(); + auto sticker = v::match(descriptor, [&](GiftTypePremium data) { + return packs.lookup(data.months); + }, [&](GiftTypeStars data) { + return data.document + ? data.document + : packs.lookup(packs.monthsForStars(data.stars)); + }); + return StickerInBubblePart::Data{ + .sticker = sticker, + .size = st::chatIntroStickerSize, + .cacheTag = Tag::ChatIntroHelloSticker, + .singleTimePlayback = v::is(descriptor), + }; + }; + push(std::make_unique( + parent, + replacing, + sticker, + st::giftBoxPreviewStickerPadding)); + const auto title = data.anonymous + ? tr::lng_action_gift_anonymous(tr::now) + : tr::lng_action_gift_got_subtitle( + tr::now, + lt_user, + parent->data()->history()->session().user()->shortName()); + auto textFallback = v::match(descriptor, [&](GiftTypePremium data) { + return TextWithEntities{ + u"Use all those premium features with joy!"_q + }; + }, [&](GiftTypeStars data) { + return tr::lng_action_gift_got_stars_text( + tr::now, + lt_cost, + tr::lng_gift_stars_title( + tr::now, + lt_count, + data.stars, + Ui::Text::Bold), + Ui::Text::WithEntities); + }); + auto description = data.text.isEmpty() + ? std::move(textFallback) + : TextWithEntities{ data.text }; + pushText(Ui::Text::Bold(title), st::giftBoxPreviewTitlePadding); + pushText(std::move(description), st::giftBoxPreviewTextPadding); + }; +} + +PreviewWrap::PreviewWrap( + not_null parent, + not_null session, + rpl::producer details) +: RpWidget(parent) +, _history(session->data().history(session->userPeerId())) +, _theme(Window::Theme::DefaultChatThemeOn(lifetime())) +, _style(std::make_unique( + _history->session().colorIndicesValue())) +, _delegate(std::make_unique( + parent, + _style.get(), + [=] { update(); })) +, _position(0, st::msgMargin.bottom()) { + _style->apply(_theme.get()); + + using namespace HistoryView; + session->data().viewRepaintRequest( + ) | rpl::start_with_next([=](not_null view) { + if (view == _item.get()) { + update(); + } + }, lifetime()); + + session->downloaderTaskFinished() | rpl::start_with_next([=] { + update(); + }, lifetime()); + + prepare(std::move(details)); +} + +PreviewWrap::~PreviewWrap() { + _item = {}; +} + +void PreviewWrap::prepare(rpl::producer details) { + std::move(details) | rpl::start_with_next([=](GiftDetails details) { + const auto &descriptor = details.descriptor; + const auto cost = v::match(descriptor, [&](GiftTypePremium data) { + return FillAmountAndCurrency(data.cost, data.currency, true); + }, [&](GiftTypeStars data) { + return tr::lng_gift_stars_title(tr::now, lt_count, data.stars); + }); + const auto text = details.anonymous + ? tr::lng_action_gift_received_anonymous(tr::now, lt_cost, cost) + : tr::lng_action_gift_received( + tr::now, + lt_user, + _history->session().user()->shortName(), + lt_cost, + cost); + const auto item = _history->makeMessage({ + .id = _history->nextNonHistoryEntryId(), + .flags = (MessageFlag::FakeAboutView + | MessageFlag::FakeHistoryItem + | MessageFlag::Local), + .from = _history->peer->id, + }, PreparedServiceText{ { text } }); + + auto owned = AdminLog::OwnedItem(_delegate.get(), item); + owned->overrideMedia(std::make_unique( + owned.get(), + GenerateGiftMedia(owned.get(), _item.get(), details), + MediaGenericDescriptor{ + .maxWidth = st::chatIntroWidth, + .service = true, + })); + _item = std::move(owned); + if (width() >= st::msgMinWidth) { + resizeTo(width()); + } + update(); + }, lifetime()); + + widthValue( + ) | rpl::filter([=](int width) { + return width >= st::msgMinWidth; + }) | rpl::start_with_next([=](int width) { + resizeTo(width); + }, lifetime()); +} + +void PreviewWrap::resizeTo(int width) { + const auto height = _position.y() + + _item->resizeGetHeight(width) + + _position.y() + + st::msgServiceMargin.top() + + st::msgServiceGiftBoxTopSkip + - st::msgServiceMargin.bottom(); + resize(width, height); +} + +void PreviewWrap::paintEvent(QPaintEvent *e) { + auto p = Painter(this); + + const auto clip = e->rect(); + if (!clip.isEmpty()) { + p.setClipRect(clip); + Window::SectionWidget::PaintBackground( + p, + _theme.get(), + QSize(width(), window()->height()), + clip); + } + + auto context = _theme->preparePaintContext( + _style.get(), + rect(), + e->rect(), + !window()->isActiveWindow()); + p.translate(_position); + _item->draw(p, context); +} + [[nodiscard]] rpl::producer> GiftsPremium( not_null session, not_null peer) { @@ -389,6 +662,8 @@ public: [[nodiscard]] virtual std::any textContext() = 0; [[nodiscard]] virtual QSize buttonSize() = 0; [[nodiscard]] virtual QImage background() = 0; + [[nodiscard]] virtual DocumentData *lookupSticker( + const GiftDescriptor &descriptor) = 0; }; class GiftButton final : public AbstractButton { @@ -402,13 +677,17 @@ public: private: void paintEvent(QPaintEvent *e) override; + void setDocument(not_null document); + const not_null _delegate; GiftDescriptor _descriptor; Text::String _text; Text::String _price; QRect _button; QMargins _extend; - std::unique_ptr _player; + + std::unique_ptr _player; + rpl::lifetime _mediaLifetime; }; @@ -423,6 +702,8 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) { if (_descriptor == descriptor) { return; } + auto player = base::take(_player); + _mediaLifetime.destroy(); _descriptor = descriptor; v::match(descriptor, [&](const GiftTypePremium &data) { const auto months = data.months; @@ -449,6 +730,10 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) { kMarkupTextOptions, _delegate->textContext()); }); + if (const auto document = _delegate->lookupSticker(descriptor)) { + setDocument(document); + } + const auto buttonw = _price.maxWidth(); const auto buttonh = st::semiboldFont->height; const auto inner = QRect( @@ -464,6 +749,44 @@ void GiftButton::setDescriptor(const GiftDescriptor &descriptor) { _button = QRect(skipx, skipy, outer, inner.height()); } +void GiftButton::setDocument(not_null document) { + const auto media = document->createMediaView(); + media->checkStickerLarge(); + media->goodThumbnailWanted(); + + rpl::single() | rpl::then( + document->owner().session().downloaderTaskFinished() + ) | rpl::filter([=] { + return media->loaded(); + }) | rpl::start_with_next([=] { + _mediaLifetime.destroy(); + + auto result = std::unique_ptr(); + const auto sticker = document->sticker(); + if (sticker->isLottie()) { + result = std::make_unique( + ChatHelpers::LottiePlayerFromDocument( + media.get(), + ChatHelpers::StickerLottieSize::InlineResults, + st::giftBoxStickerSize, + Lottie::Quality::High)); + } else if (sticker->isWebm()) { + result = std::make_unique( + media->owner()->location(), + media->bytes(), + st::giftBoxStickerSize); + } else { + result = std::make_unique( + media->owner()->location(), + media->bytes(), + st::giftBoxStickerSize); + } + result->setRepaintCallback([=] { update(); }); + _player = std::move(result); + update(); + }, _mediaLifetime); +} + void GiftButton::setGeometry(QRect inner, QMargins extend) { _extend = extend; AbstractButton::setGeometry(inner.marginsAdded(extend)); @@ -474,6 +797,30 @@ void GiftButton::paintEvent(QPaintEvent *e) { const auto position = QPoint(_extend.left(), _extend.top()); p.drawImage(0, 0, _delegate->background()); + if (_player && _player->ready()) { + const auto paused = !isOver(); + auto info = _player->frame( + st::giftBoxStickerSize, + QColor(0, 0, 0, 0), + false, + crl::now(), + paused); + const auto finished = (info.index + 1 == _player->framesCount()); + if (!finished || !paused) { + _player->markFrameShown(); + } + const auto size = info.image.size() / style::DevicePixelRatio(); + p.drawImage( + QRect( + (width() - size.width()) / 2, + (_text.isEmpty() + ? st::giftBoxStickerStarTop + : st::giftBoxStickerTop), + size.width(), + size.height()), + info.image); + } + auto hq = PainterHighQualityEnabler(p); const auto premium = v::is(_descriptor); const auto singlew = _delegate->buttonSize().width(); @@ -481,12 +828,12 @@ void GiftButton::paintEvent(QPaintEvent *e) { v::match(_descriptor, [&](const GiftTypePremium &data) { if (data.discountPercent > 0) { p.setPen(st::attentionBoxButton.textFg); - p.drawText(QRect(position, QSize(singlew, st::normalFont->height * 2)), '-' + QString::number(data.discountPercent) + '%', style::al_center); + p.drawText(QRect(position, QSize(singlew, st::normalFont->height * 2)), '-' + QString::number(data.discountPercent) + '%', style::al_topright); } }, [&](const GiftTypeStars &data) { if (data.limited) { p.setPen(st::windowActiveTextFg); - p.drawText(QRect(position, QSize(singlew, st::normalFont->height * 2)), u"limited"_q, style::al_center); + p.drawText(QRect(position, QSize(singlew, st::normalFont->height * 2)), u"limited"_q, style::al_topright); } }); p.setBrush(premium ? st::lightButtonBgOver : st::creditsBg3); @@ -520,6 +867,124 @@ void GiftButton::paintEvent(QPaintEvent *e) { }); } +[[nodiscard]] not_null AddPartInput( + not_null container, + rpl::producer placeholder, + QString current, + int limit) { + const auto field = container->add( + object_ptr( + container, + st::giftBoxTextField, + Ui::InputField::Mode::NoNewlines, + std::move(placeholder), + current), + st::giftBoxTextPadding); + field->setMaxLength(limit); + Ui::AddLengthLimitLabel(field, limit); + return field; +} + +void SendGiftBox( + not_null box, + not_null window, + not_null peer, + const GiftDescriptor &descriptor) { + box->setStyle(st::giftBox); + box->setWidth(st::boxWideWidth); + box->setTitle(tr::lng_gift_send_title()); + box->addTopButton(st::boxTitleClose, [=] { + box->closeBox(); + }); + + const auto session = &window->session(); + const auto context = Core::MarkedTextContext{ + .session = session, + .customEmojiRepaint = [] {}, + }; + auto cost = rpl::single([&] { + return v::match(descriptor, [&](const GiftTypePremium &data) { + if (data.currency == Ui::kCreditsCurrency) { + return Ui::CreditsEmojiSmall(session).append( + Lang::FormatCountDecimal(std::abs(data.cost))); + } + return TextWithEntities{ + FillAmountAndCurrency(data.cost, data.currency), + }; + }, [&](const GiftTypeStars &data) { + return Ui::CreditsEmojiSmall(session).append( + Lang::FormatCountDecimal(std::abs(data.stars))); + }); + }()); + const auto button = box->addButton(rpl::single(QString()), [=] { + box->closeBox(); + }); + SetButtonMarkedLabel( + button, + tr::lng_gift_send_button( + lt_cost, + std::move(cost), + Ui::Text::WithEntities), + session, + st::creditsBoxButtonLabel, + st::giftBox.button.textFg->c); + + struct State { + rpl::variable details; + }; + const auto state = box->lifetime().make_state(); + state->details = GiftDetails{ + .descriptor = descriptor, + }; + + const auto container = box->verticalLayout(); + container->add(object_ptr( + container, + session, + state->details.value())); + + const auto text = AddPartInput( + container, + tr::lng_gift_send_message(), + QString(), + kGiftMessageLimit); + text->changes() | rpl::start_with_next([=] { + auto now = state->details.current(); + now.text = text->getLastText(); + state->details = std::move(now); + }, text->lifetime()); + + AddDivider(container); + AddSkip(container); + container->add( + object_ptr( + container, + tr::lng_gift_send_anonymous(), + st::settingsButtonNoIcon) + )->toggleOn(rpl::single(false))->toggledValue( + ) | rpl::start_with_next([=](bool toggled) { + auto now = state->details.current(); + now.anonymous = toggled; + state->details = std::move(now); + }, container->lifetime()); + AddSkip(container); + AddDividerText(container, tr::lng_gift_send_anonymous_about( + lt_user, + rpl::single(peer->shortName()), + lt_recipient, + rpl::single(peer->shortName()))); + + const auto buttonWidth = st::boxWideWidth + - st::giftBox.buttonPadding.left() + - st::giftBox.buttonPadding.right(); + button->resizeToWidth(buttonWidth); + button->widthValue() | rpl::start_with_next([=](int width) { + if (width != buttonWidth) { + button->resizeToWidth(buttonWidth); + } + }, button->lifetime()); +} + [[nodiscard]] object_ptr MakeGiftsList( not_null window, not_null peer, @@ -563,6 +1028,19 @@ void GiftButton::paintEvent(QPaintEvent *e) { QImage background() override { return _bg; } + DocumentData *lookupSticker( + const GiftDescriptor &descriptor) { + const auto &session = _window->session(); + auto &packs = session.giftBoxStickersPacks(); + packs.load(); + return v::match(descriptor, [&](GiftTypePremium data) { + return packs.lookup(data.months); + }, [&](GiftTypeStars data) { + return data.document + ? data.document + : packs.lookup(packs.monthsForStars(data.stars)); + }); + } private: const not_null _window; @@ -655,6 +1133,10 @@ void GiftButton::paintEvent(QPaintEvent *e) { } else { x += single.width() + st::giftBoxGiftSkip.x(); } + + button->setClickedCallback([=] { + window->show(Box(SendGiftBox, window, peer, descriptor)); + }); } if (gifts.size() % kGiftsPerRow) { y += padding.bottom() + single.height(); diff --git a/Telegram/SourceFiles/boxes/send_credits_box.cpp b/Telegram/SourceFiles/boxes/send_credits_box.cpp index 1bfeb01cc..e1aa39923 100644 --- a/Telegram/SourceFiles/boxes/send_credits_box.cpp +++ b/Telegram/SourceFiles/boxes/send_credits_box.cpp @@ -314,41 +314,22 @@ void SendCreditsBox( AddChildToWidgetCenter(button.data(), loadingAnimation); loadingAnimation->showOn(state->confirmButtonBusy.value()); } - { - auto buttonText = tr::lng_credits_box_out_confirm( - lt_count, - rpl::single(form->invoice.amount) | tr::to_count(), - lt_emoji, - rpl::single(CreditsEmojiSmall(session)), - Ui::Text::RichLangValue); - const auto buttonLabel = Ui::CreateChild( - button, - rpl::single(QString()), - st::creditsBoxButtonLabel); - std::move( - buttonText - ) | rpl::start_with_next([=](const TextWithEntities &text) { - buttonLabel->setMarkedText( - text, - Core::MarkedTextContext{ - .session = session, - .customEmojiRepaint = [=] { buttonLabel->update(); }, - }); - }, buttonLabel->lifetime()); - buttonLabel->setTextColorOverride( - box->getDelegate()->style().button.textFg->c); - button->sizeValue( - ) | rpl::start_with_next([=](const QSize &size) { - buttonLabel->moveToLeft( - (size.width() - buttonLabel->width()) / 2, - (size.height() - buttonLabel->height()) / 2); - }, buttonLabel->lifetime()); - buttonLabel->setAttribute(Qt::WA_TransparentForMouseEvents); - state->confirmButtonBusy.value( - ) | rpl::start_with_next([=](bool busy) { - buttonLabel->setVisible(!busy); - }, buttonLabel->lifetime()); - } + SetButtonMarkedLabel( + button, + rpl::combine( + tr::lng_credits_box_out_confirm( + lt_count, + rpl::single(form->invoice.amount) | tr::to_count(), + lt_emoji, + rpl::single(CreditsEmojiSmall(session)), + Ui::Text::RichLangValue), + state->confirmButtonBusy.value() + ) | rpl::map([](TextWithEntities &&text, bool busy) { + return busy ? TextWithEntities() : std::move(text); + }), + session, + st::creditsBoxButtonLabel, + box->getDelegate()->style().button.textFg->c); const auto buttonWidth = st::boxWidth - rect::m::sum::h(st::giveawayGiftCodeBox.buttonPadding); @@ -408,4 +389,55 @@ TextWithEntities CreditsEmojiSmall(not_null session) { QString(QChar(0x2B50))); } +not_null SetButtonMarkedLabel( + not_null button, + rpl::producer text, + Fn update)> context, + const style::FlatLabel &st, + std::optional textFg) { + const auto buttonLabel = Ui::CreateChild( + button, + rpl::single(QString()), + st); + rpl::duplicate( + text + ) | rpl::filter([=](const TextWithEntities &text) { + return !text.text.isEmpty(); + }) | rpl::start_with_next([=](const TextWithEntities &text) { + buttonLabel->setMarkedText( + text, + context([=] { buttonLabel->update(); })); + }, buttonLabel->lifetime()); + if (textFg) { + buttonLabel->setTextColorOverride(textFg); + } + button->sizeValue( + ) | rpl::start_with_next([=](const QSize &size) { + buttonLabel->moveToLeft( + (size.width() - buttonLabel->width()) / 2, + (size.height() - buttonLabel->height()) / 2); + }, buttonLabel->lifetime()); + buttonLabel->setAttribute(Qt::WA_TransparentForMouseEvents); + buttonLabel->showOn(std::move( + text + ) | rpl::map([=](const TextWithEntities &text) { + return !text.text.isEmpty(); + })); + return buttonLabel; +} + +not_null SetButtonMarkedLabel( + not_null button, + rpl::producer text, + not_null session, + const style::FlatLabel &st, + std::optional textFg) { + return SetButtonMarkedLabel(button, text, [=](Fn update) { + return Core::MarkedTextContext{ + .session = session, + .customEmojiRepaint = update, + }; + }, st, textFg); +} + } // namespace Ui diff --git a/Telegram/SourceFiles/boxes/send_credits_box.h b/Telegram/SourceFiles/boxes/send_credits_box.h index c0107a360..c462fdc4e 100644 --- a/Telegram/SourceFiles/boxes/send_credits_box.h +++ b/Telegram/SourceFiles/boxes/send_credits_box.h @@ -9,6 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class HistoryItem; +namespace style { +struct FlatLabel; +} // namespace style + namespace Main { class Session; } // namespace Main @@ -19,7 +23,9 @@ struct CreditsFormData; namespace Ui { +class RpWidget; class GenericBox; +class FlatLabel; void SendCreditsBox( not_null box, @@ -32,4 +38,18 @@ void SendCreditsBox( [[nodiscard]] TextWithEntities CreditsEmojiSmall( not_null session); +not_null SetButtonMarkedLabel( + not_null button, + rpl::producer text, + Fn update)> context, + const style::FlatLabel &st, + std::optional textFg = {}); + +not_null SetButtonMarkedLabel( + not_null button, + rpl::producer text, + not_null session, + const style::FlatLabel &st, + std::optional textFg = {}); + } // namespace Ui diff --git a/Telegram/SourceFiles/ui/effects/credits.style b/Telegram/SourceFiles/ui/effects/credits.style index b3b56bd98..6f7e3bb07 100644 --- a/Telegram/SourceFiles/ui/effects/credits.style +++ b/Telegram/SourceFiles/ui/effects/credits.style @@ -58,6 +58,15 @@ creditsGiftBox: Box(defaultBox) { shadowIgnoreTopSkip: true; } +giftBox: Box(defaultBox) { + buttonPadding: margins(22px, 11px, 22px, 22px); + buttonHeight: 42px; + button: RoundButton(defaultActiveButton) { + height: 42px; + textTop: 12px; + style: semiboldTextStyle; + } +} giftBoxSubtitle: FlatLabel(defaultFlatLabel) { style: TextStyle(defaultTextStyle) { font: boxTitleFont; @@ -85,6 +94,32 @@ giftBoxGiftHeight: 164px; giftBoxGiftRadius: 12px; giftBoxPremiumIconSize: 64px; giftBoxPremiumIconTop: 10px; -giftBoxPremiumTextTop: 56px; +giftBoxPremiumTextTop: 84px; giftBoxButtonBottom: 12px; giftBoxButtonPadding: margins(8px, 4px, 8px, 4px); +giftBoxPreviewStickerPadding: margins(10px, 12px, 10px, 16px); +giftBoxPreviewTitlePadding: margins(12px, 4px, 12px, 4px); +giftBoxPreviewTextPadding: margins(12px, 4px, 12px, 24px); +giftBoxStickerTop: 0px; +giftBoxStickerStarTop: 24px; +giftBoxStickerSize: size(80px, 80px); +giftBoxTextField: InputField(defaultInputField) { + textBg: transparent; + textMargins: margins(2px, 0px, 32px, 0px); + + placeholderFg: placeholderFg; + placeholderFgActive: placeholderFgActive; + placeholderFgError: placeholderFgActive; + placeholderMargins: margins(2px, 0px, 2px, 0px); + placeholderScale: 0.; + placeholderFont: normalFont; + + border: 0px; + borderActive: 0px; + + heightMin: 20px; + heightMax: 48px; + + style: defaultTextStyle; +} +giftBoxTextPadding: margins(20px, 15px, 20px, 11px);