From 46cb3ec1034c06893de56cfa6d3ac63c5eaf59d8 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 4 Sep 2024 01:55:57 +0300 Subject: [PATCH] Added box for boosts with credits. --- Telegram/Resources/langs/lang.strings | 1 + .../SourceFiles/boxes/gift_premium_box.cpp | 102 ++++++++++--- Telegram/SourceFiles/boxes/gift_premium_box.h | 6 + .../boosts/info_boosts_inner_widget.cpp | 7 + .../settings/settings_credits_graphics.cpp | 141 ++++++++++++++++++ .../settings/settings_credits_graphics.h | 5 + 6 files changed, 244 insertions(+), 18 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 58568a7715d2c3..83ce669e6bae0c 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2978,6 +2978,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_gift_stars_title#other" = "{count} Stars"; "lng_gift_stars_outgoing" = "With Stars, {user} will be able to unlock content and services on Telegram."; "lng_gift_stars_incoming" = "Use Stars to unlock content and services on Telegram."; +"lng_gift_until" = "Until"; "lng_accounts_limit_title" = "Limit Reached"; "lng_accounts_limit1#one" = "You have reached the limit of **{count}** connected accounts."; diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index f736cd3edc5087..37357dcb1cd437 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -69,6 +69,24 @@ constexpr auto kUserpicsMax = size_t(3); using GiftOption = Data::PremiumSubscriptionOption; using GiftOptions = Data::PremiumSubscriptionOptions; +[[nodiscard]] QString CreateMessageLink( + not_null session, + PeerId peerId, + uint64 messageId) { + if (const auto msgId = MsgId(peerId ? messageId : 0)) { + const auto peer = session->data().peer(peerId); + if (const auto channel = peer->asBroadcast()) { + const auto username = channel->username(); + const auto base = username.isEmpty() + ? u"c/%1"_q.arg(peerToChannel(channel->id).bare) + : username; + const auto query = base + '/' + QString::number(msgId.bare); + return session->createInternalLink(query); + } + } + return QString(); +}; + GiftOptions GiftOptionFromTL(const MTPDuserFull &data) { auto result = GiftOptions(); const auto gifts = data.vpremium_gifts(); @@ -1703,21 +1721,7 @@ void AddCreditsHistoryEntryTable( st::giveawayGiftCodeTable), st::giveawayGiftCodeTableMargin); const auto peerId = PeerId(entry.barePeerId); - const auto createMessageLink = [&](uint64 messageId) { - if (const auto msgId = MsgId(peerId ? messageId : 0)) { - const auto session = &controller->session(); - const auto peer = session->data().peer(peerId); - if (const auto channel = peer->asBroadcast()) { - const auto username = channel->username(); - const auto base = username.isEmpty() - ? u"c/%1"_q.arg(peerToChannel(channel->id).bare) - : username; - const auto query = base + '/' + QString::number(msgId.bare); - return session->createInternalLink(query); - } - } - return QString(); - }; + const auto session = &controller->session(); if (peerId) { auto text = entry.in ? tr::lng_credits_box_history_entry_peer_in() @@ -1725,10 +1729,12 @@ void AddCreditsHistoryEntryTable( AddTableRow(table, std::move(text), controller, peerId); } if (const auto msgId = MsgId(peerId ? entry.bareMsgId : 0)) { - const auto session = &controller->session(); const auto peer = session->data().peer(peerId); if (const auto channel = peer->asBroadcast()) { - const auto link = createMessageLink(entry.bareMsgId); + const auto link = CreateMessageLink( + session, + peerId, + entry.bareMsgId); auto label = object_ptr( table, rpl::single(Ui::Text::Link(link)), @@ -1796,7 +1802,10 @@ void AddCreditsHistoryEntryTable( Ui::Text::RichLangValue)); } { - const auto link = createMessageLink(entry.bareGiveawayMsgId); + const auto link = CreateMessageLink( + session, + peerId, + entry.bareGiveawayMsgId); if (!link.isEmpty()) { AddTableRow( table, @@ -1903,3 +1912,60 @@ void AddSubscriberEntryTable( rpl::single(Ui::Text::WithEntities(langDateTime(d)))); } } + +void AddCreditsBoostTable( + not_null controller, + not_null container, + const Data::Boost &b) { + auto table = container->add( + object_ptr( + container, + st::giveawayGiftCodeTable), + st::giveawayGiftCodeTableMargin); + const auto peerId = b.giveawayMessage.peer; + if (!peerId) { + return; + } + const auto from = controller->session().data().peer(peerId); + AddTableRow( + table, + tr::lng_credits_box_history_entry_peer_in(), + controller, + from->id); + if (b.credits) { + AddTableRow( + table, + tr::lng_gift_link_label_gift(), + tr::lng_gift_stars_title( + lt_count, + rpl::single(float64(b.credits)), + Ui::Text::RichLangValue)); + } + { + const auto link = CreateMessageLink( + &controller->session(), + peerId, + b.giveawayMessage.msg.bare); + if (!link.isEmpty()) { + AddTableRow( + table, + tr::lng_gift_link_label_reason(), + tr::lng_gift_link_reason_giveaway( + ) | rpl::map([link](const QString &text) { + return Ui::Text::Link(text, link); + })); + } + } + if (!b.date.isNull()) { + AddTableRow( + table, + tr::lng_gift_link_label_date(), + rpl::single(Ui::Text::WithEntities(langDateTime(b.date)))); + } + if (!b.expiresAt.isNull()) { + AddTableRow( + table, + tr::lng_gift_until(), + rpl::single(Ui::Text::WithEntities(langDateTime(b.expiresAt)))); + } +} diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.h b/Telegram/SourceFiles/boxes/gift_premium_box.h index c0b39a8148ceef..43ca082b9048d5 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.h +++ b/Telegram/SourceFiles/boxes/gift_premium_box.h @@ -16,6 +16,7 @@ struct GiftCode; } // namespace Api namespace Data { +struct Boost; struct CreditsHistoryEntry; struct GiveawayStart; struct GiveawayResults; @@ -89,3 +90,8 @@ void AddSubscriberEntryTable( not_null container, not_null peer, TimeId date); + +void AddCreditsBoostTable( + not_null controller, + not_null container, + const Data::Boost &boost); diff --git a/Telegram/SourceFiles/info/channel_statistics/boosts/info_boosts_inner_widget.cpp b/Telegram/SourceFiles/info/channel_statistics/boosts/info_boosts_inner_widget.cpp index f25a28ef6c4fb9..09ca0420908d14 100644 --- a/Telegram/SourceFiles/info/channel_statistics/boosts/info_boosts_inner_widget.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/boosts/info_boosts_inner_widget.cpp @@ -23,6 +23,7 @@ For license and copyright information please follow this link: #include "info/statistics/info_statistics_inner_widget.h" // FillLoading. #include "info/statistics/info_statistics_list_controllers.h" #include "lang/lang_keys.h" +#include "settings/settings_credits_graphics.h" #include "statistics/widgets/chart_header_widget.h" #include "ui/boxes/boost_box.h" #include "ui/controls/invite_link_label.h" @@ -413,6 +414,12 @@ void InnerWidget::fill() { _controller->showPeerInfo(user); }); } + } else if (boost.credits) { + _show->showBox( + Box( + ::Settings::BoostCreditsBox, + _controller->parentController(), + boost)); } else if (!boost.isUnclaimed) { _show->showToast(tr::lng_boosts_list_pending_about(tr::now)); } diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index 19519429b24231..eabd6d27bb3f5c 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -20,6 +20,7 @@ For license and copyright information please follow this link: #include "core/click_handler_types.h" // UrlClickHandler #include "core/ui_integration.h" #include "data/components/credits.h" +#include "data/data_boosts.h" #include "data/data_document.h" #include "data/data_document_media.h" #include "data/data_file_origin.h" @@ -45,6 +46,7 @@ For license and copyright information please follow this link: #include "ui/controls/userpic_button.h" #include "ui/effects/credits_graphics.h" #include "ui/effects/premium_graphics.h" +#include "ui/effects/premium_stars_colored.h" #include "ui/effects/premium_top_bar.h" #include "ui/image/image_prepare.h" #include "ui/layers/generic_box.h" @@ -498,6 +500,145 @@ not_null AddBalanceWidget( return balance; } +void BoostCreditsBox( + not_null box, + not_null controller, + const Data::Boost &b) { + box->setStyle(st::giveawayGiftCodeBox); + box->setNoContentMargin(true); + + const auto content = box->verticalLayout(); + const auto session = &controller->session(); + Ui::AddSkip(content); + { + const auto &stUser = st::premiumGiftsUserpicButton; + const auto widget = content->add(object_ptr(content)); + using ColoredMiniStars = Ui::Premium::ColoredMiniStars; + const auto stars = widget->lifetime().make_state( + widget, + false, + Ui::Premium::MiniStars::Type::BiStars); + stars->setColorOverride(Ui::Premium::CreditsIconGradientStops()); + widget->resize( + st::boxWidth - stUser.photoSize, + stUser.photoSize * 1.3); + const auto svg = std::make_shared( + Ui::Premium::ColorizedSvg( + Ui::Premium::CreditsIconGradientStops())); + content->sizeValue( + ) | rpl::start_with_next([=](const QSize &size) { + widget->moveToLeft(stUser.photoSize / 2, 0); + const auto starsRect = Rect(widget->size()); + stars->setPosition(starsRect.topLeft()); + stars->setSize(starsRect.size()); + widget->lower(); + }, widget->lifetime()); + widget->paintRequest( + ) | rpl::start_with_next([=](const QRect &r) { + auto p = QPainter(widget); + p.fillRect(r, Qt::transparent); + stars->paint(p); + svg->render( + &p, + QRectF( + (widget->width() - stUser.photoSize) / 2., + (widget->height() - stUser.photoSize) / 2., + stUser.photoSize, + stUser.photoSize)); + }, widget->lifetime()); + } + content->add( + object_ptr>( + content, + object_ptr( + content, + tr::lng_gift_stars_title( + lt_count, + rpl::single(float64(b.credits))), + st::boxTitle))); + Ui::AddSkip(content); + if (b.multiplier) { + const auto &st = st::statisticsDetailsBottomCaptionStyle; + const auto badge = content->add(object_ptr(content)); + badge->resize(badge->width(), st.font->height * 1.5); + const auto text = badge->lifetime().make_state( + st::boxWidth + - st::boxRowPadding.left() + - st::boxRowPadding.right()); + auto textWithEntities = TextWithEntities(); + textWithEntities.append( + Ui::Text::SingleCustomEmoji( + session->data().customEmojiManager().registerInternalEmoji( + st::boostsListMiniIcon, + { st.font->descent * 2, st.font->descent / 2, 0, 0 }, + true))); + textWithEntities.append( + tr::lng_boosts_list_title(tr::now, lt_count, b.multiplier)); + text->setMarkedText( + st, + std::move(textWithEntities), + kMarkupTextOptions, + Core::MarkedTextContext{ + .session = session, + .customEmojiRepaint = [=] { badge->update(); }, + }); + badge->paintRequest( + ) | rpl::start_with_next([=] { + auto p = QPainter(badge); + auto hq = PainterHighQualityEnabler(p); + const auto radius = badge->height() / 2; + const auto badgeWidth = text->maxWidth() + radius; + p.setPen(Qt::NoPen); + p.setBrush(st::premiumButtonBg2); + p.drawRoundedRect( + QRect( + (badge->width() - badgeWidth) / 2, + 0, + badgeWidth, + badge->height()), + radius, + radius); + p.setPen(st::premiumButtonFg); + p.setBrush(Qt::NoBrush); + text->draw(p, Ui::Text::PaintContext{ + .position = QPoint( + (badge->width() - text->maxWidth() - radius) / 2, + (badge->height() - text->minHeight()) / 2), + .outerWidth = badge->width(), + .availableWidth = badge->width(), + }); + }, badge->lifetime()); + + Ui::AddSkip(content); + } + AddCreditsBoostTable(controller, content, b); + Ui::AddSkip(content); + + box->addRow(object_ptr>( + box, + object_ptr( + box, + tr::lng_credits_box_out_about( + lt_link, + tr::lng_payments_terms_link( + ) | Ui::Text::ToLink( + tr::lng_credits_box_out_about_link(tr::now)), + Ui::Text::WithEntities), + st::creditsBoxAboutDivider))); + Ui::AddSkip(content); + + const auto button = box->addButton(tr::lng_box_ok(), [=] { + box->closeBox(); + }); + const auto buttonWidth = st::boxWidth + - rect::m::sum::h(st::giveawayGiftCodeBox.buttonPadding); + button->widthValue() | rpl::filter([=] { + return (button->widthNoMargins() != buttonWidth); + }) | rpl::start_with_next([=] { + button->resizeToWidth(buttonWidth); + }, button->lifetime()); +} + void ReceiptCreditsBox( not_null box, not_null controller, diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.h b/Telegram/SourceFiles/settings/settings_credits_graphics.h index 15b2f0ff868126..c57f0490af7127 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.h +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.h @@ -13,6 +13,7 @@ class object_ptr; class PeerData; namespace Data { +struct Boost; struct CreditsHistoryEntry; struct SubscriptionEntry; } // namespace Data @@ -74,6 +75,10 @@ void ReceiptCreditsBox( not_null controller, const Data::CreditsHistoryEntry &e, const Data::SubscriptionEntry &s); +void BoostCreditsBox( + not_null box, + not_null controller, + const Data::Boost &b); void GiftedCreditsBox( not_null box, not_null controller,