diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 966b61072..d0eb6dce5 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3061,6 +3061,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_gift_sold_out_title" = "Sold Out!"; "lng_gift_sold_out_text#one" = "All {count} gift was already sold."; "lng_gift_sold_out_text#other" = "All {count} gifts were already sold."; +"lng_gift_send_small" = "send a gift"; +"lng_gift_sell_small#one" = "sell for {count} Star"; +"lng_gift_sell_small#other" = "sell for {count} Stars"; "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_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index 1be6cbe8f..3e792bbb6 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/peers/prepare_short_info_box.h" #include "boxes/peers/replace_boost_box.h" // BoostsForGift. #include "boxes/premium_preview_box.h" // ShowPremiumPreviewBox. +#include "boxes/star_gift_box.h" // ShowStarGiftBox. #include "data/data_boosts.h" #include "data/data_changes.h" #include "data/data_channel.h" @@ -123,7 +124,8 @@ namespace { [[nodiscard]] object_ptr MakePeerTableValue( not_null parent, not_null controller, - PeerId id) { + PeerId id, + bool withSendGiftButton = false) { auto result = object_ptr(parent); const auto raw = result.data(); @@ -134,15 +136,40 @@ namespace { const auto userpic = Ui::CreateChild(raw, peer, st); const auto label = Ui::CreateChild( raw, - peer->name(), + withSendGiftButton ? peer->shortName() : peer->name(), st::giveawayGiftCodeValue); - raw->widthValue( - ) | rpl::start_with_next([=](int width) { + const auto send = withSendGiftButton + ? Ui::CreateChild( + raw, + tr::lng_gift_send_small(), + st::starGiftSmallButton) + : nullptr; + if (send) { + send->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); + send->setClickedCallback([=] { + Ui::ShowStarGiftBox(controller->parentController(), peer); + }); + } + rpl::combine( + raw->widthValue(), + send ? send->widthValue() : rpl::single(0) + ) | rpl::start_with_next([=](int width, int sendWidth) { const auto position = st::giveawayGiftCodeNamePosition; - label->resizeToNaturalWidth(width - position.x()); + const auto sendSkip = sendWidth + ? (st::normalFont->spacew + sendWidth) + : 0; + label->resizeToNaturalWidth(width - position.x() - sendSkip); label->moveToLeft(position.x(), position.y(), width); const auto top = (raw->height() - userpic->height()) / 2; userpic->moveToLeft(0, top, width); + if (send) { + send->moveToLeft( + position.x() + label->width() + st::normalFont->spacew, + (position.y() + + st::giveawayGiftCodeValue.style.font->ascent + - st::starGiftSmallButton.style.font->ascent), + width); + } }, label->lifetime()); userpic->setAttribute(Qt::WA_TransparentForMouseEvents); @@ -210,6 +237,71 @@ void AddTableRow( valueMargins); } +object_ptr MakeStarGiftStarsValue( + not_null parent, + not_null controller, + const Data::CreditsHistoryEntry &entry, + Fn convertToStars) { + auto result = object_ptr(parent); + const auto raw = result.data(); + + const auto session = &controller->session(); + const auto makeContext = [session](Fn update) { + return Core::MarkedTextContext{ + .session = session, + .customEmojiRepaint = std::move(update), + }; + }; + auto star = session->data().customEmojiManager().creditsEmoji(); + const auto label = Ui::CreateChild( + raw, + rpl::single( + star.append(' ' + Lang::FormatCountDecimal(entry.credits))), + st::giveawayGiftCodeValue, + st::defaultPopupMenu, + std::move(makeContext)); + + const auto convert = convertToStars + ? Ui::CreateChild( + raw, + tr::lng_gift_sell_small( + lt_count_decimal, + rpl::single(entry.convertStars * 1.)), + st::starGiftSmallButton) + : nullptr; + if (convert) { + convert->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); + convert->setClickedCallback(std::move(convertToStars)); + } + rpl::combine( + raw->widthValue(), + convert ? convert->widthValue() : rpl::single(0) + ) | rpl::start_with_next([=](int width, int convertWidth) { + const auto convertSkip = convertWidth + ? (st::normalFont->spacew + convertWidth) + : 0; + label->resizeToNaturalWidth(width - convertSkip); + label->moveToLeft(0, 0, width); + if (convert) { + convert->moveToLeft( + label->width() + st::normalFont->spacew, + (st::giveawayGiftCodeValue.style.font->ascent + - st::starGiftSmallButton.style.font->ascent), + width); + } + }, label->lifetime()); + + label->heightValue() | rpl::start_with_next([=](int height) { + raw->resize( + raw->width(), + height + st::giveawayGiftCodeValueMargin.bottom()); + }, raw->lifetime()); + + label->setAttribute(Qt::WA_TransparentForMouseEvents); + + return result; +} + not_null AddTableRow( not_null table, rpl::producer label, @@ -942,7 +1034,8 @@ void ResolveGiveawayInfo( void AddStarGiftTable( not_null controller, not_null container, - const Data::CreditsHistoryEntry &entry) { + const Data::CreditsHistoryEntry &entry, + Fn convertToStars) { auto table = container->add( object_ptr( container, @@ -950,18 +1043,13 @@ void AddStarGiftTable( st::giveawayGiftCodeTableMargin); const auto peerId = PeerId(entry.barePeerId); const auto session = &controller->session(); - const auto makeContext = [session](Fn update) { - return Core::MarkedTextContext{ - .session = session, - .customEmojiRepaint = std::move(update), - }; - }; if (peerId) { + const auto withSendButton = entry.in; AddTableRow( table, tr::lng_credits_box_history_entry_peer_in(), - controller, - peerId); + MakePeerTableValue(table, controller, peerId, withSendButton), + st::giveawayGiftCodePeerMargin); } else if (!entry.soldOutInfo) { AddTableRow( table, @@ -984,13 +1072,17 @@ void AddStarGiftTable( langDateTime(entry.lastSaleDate)))); } { - auto star = session->data().customEmojiManager().creditsEmoji(); + const auto margin = st::giveawayGiftCodeValueMargin + - QMargins(0, 0, 0, st::giveawayGiftCodeValueMargin.bottom()); AddTableRow( table, tr::lng_gift_link_label_value(), - rpl::single( - star.append(' ' + Lang::FormatCountDecimal(entry.credits))), - makeContext); + MakeStarGiftStarsValue( + table, + controller, + entry, + std::move(convertToStars)), + margin); } if (!entry.date.isNull()) { AddTableRow( @@ -1018,7 +1110,6 @@ void AddStarGiftTable( Ui::Text::WithEntities))); } if (!entry.description.empty()) { - const auto session = &controller->session(); const auto makeContext = [=](Fn update) { return Core::MarkedTextContext{ .session = session, diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.h b/Telegram/SourceFiles/boxes/gift_premium_box.h index 31ca5fcf2..3a2c20498 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.h +++ b/Telegram/SourceFiles/boxes/gift_premium_box.h @@ -57,7 +57,8 @@ void ResolveGiveawayInfo( void AddStarGiftTable( not_null controller, not_null container, - const Data::CreditsHistoryEntry &entry); + const Data::CreditsHistoryEntry &entry, + Fn convertToStars); void AddCreditsHistoryEntryTable( not_null controller, not_null container, diff --git a/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway.style b/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway.style index d3fb04e8d..226da96f7 100644 --- a/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway.style +++ b/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway.style @@ -208,10 +208,24 @@ startGiveawayButtonLoading: InfiniteRadialAnimation(defaultInfiniteRadialAnimati thickness: 2px; } -starGiftBox: Box(giveawayGiftCodeBox) { - buttonPadding: margins(22px, 11px, 22px, 52px); -} starConvertButtonLoading: InfiniteRadialAnimation(startGiveawayButtonLoading) { color: windowActiveTextFg; thickness: 2px; } + +starGiftSmallButton: RoundButton(defaultActiveButton) { + textFg: windowActiveTextFg; + textFgOver: windowActiveTextFg; + textBg: lightButtonBgOver; + textBgOver: lightButtonBgOver; + width: -12px; + height: 18px; + radius: 9px; + textTop: 0px; + style: TextStyle(defaultTextStyle) { + font: font(12px); + } + ripple: RippleAnimation(defaultRippleAnimation) { + color: lightButtonBgRipple; + } +} diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index dc24d4329..326eb4837 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -743,7 +743,7 @@ void ReceiptCreditsBox( : nullptr; const auto canConvert = gotStarGift && !e.converted && starGiftSender; - box->setStyle(canConvert ? st::starGiftBox : st::giveawayGiftCodeBox); + box->setStyle(st::giveawayGiftCodeBox); box->setNoContentMargin(true); const auto content = box->verticalLayout(); @@ -1091,8 +1091,61 @@ void ReceiptCreditsBox( Ui::AddSkip(content); Ui::AddSkip(content); + struct State final { + rpl::variable confirmButtonBusy; + rpl::variable convertButtonBusy; + }; + const auto state = box->lifetime().make_state(); + const auto weakWindow = base::make_weak(controller); + if (isStarGift && e.id.isEmpty()) { - AddStarGiftTable(controller, content, e); + const auto convert = [=, weak = Ui::MakeWeak(box)] { + const auto stars = e.convertStars; + const auto name = starGiftSender->shortName(); + ConfirmConvertStarGift(box->uiShow(), name, stars, [=] { + if (state->convertButtonBusy.current() + || state->confirmButtonBusy.current()) { + return; + } + state->convertButtonBusy = true; + const auto window = weakWindow.get(); + const auto itemId = MsgId(e.bareMsgId); + if (window && stars) { + const auto done = [=](bool ok) { + if (const auto window = weakWindow.get()) { + if (ok) { + using GiftAction = Data::GiftUpdate::Action; + window->session().data().notifyGiftUpdate({ + .itemId = FullMsgId( + starGiftSender->id, + itemId), + .action = GiftAction::Convert, + }); + } + } + if (const auto strong = weak.data()) { + if (ok) { + strong->closeBox(); + } else { + state->convertButtonBusy = false; + } + } + }; + ConvertStarGift( + window, + starGiftSender, + itemId, + stars, + done); + } + }); + }; + + AddStarGiftTable( + controller, + content, + e, + canConvert ? convert : Fn()); } else { AddCreditsHistoryEntryTable(controller, content, e); AddSubscriptionEntryTable(controller, content, s); @@ -1175,11 +1228,6 @@ void ReceiptCreditsBox( const auto toRenew = (s.cancelled || s.expired) && !s.inviteHash.isEmpty(); const auto toCancel = !toRenew && s; - struct State final { - rpl::variable confirmButtonBusy; - rpl::variable convertButtonBusy; - }; - const auto state = box->lifetime().make_state(); auto confirmText = rpl::conditional( state->confirmButtonBusy.value(), rpl::single(QString()), @@ -1192,7 +1240,6 @@ void ReceiptCreditsBox( ? tr::lng_gift_display_on_page_hide() : tr::lng_gift_display_on_page()) : tr::lng_box_ok())); - const auto weakWindow = base::make_weak(controller); const auto send = [=, weak = Ui::MakeWeak(box)] { if (canConvert) { const auto save = !e.savedToProfile; @@ -1290,85 +1337,6 @@ void ReceiptCreditsBox( }) | rpl::start_with_next([=] { button->resizeToWidth(buttonWidth); }, button->lifetime()); - - if (canConvert) { - using namespace Ui; - auto convertText = rpl::conditional( - state->convertButtonBusy.value(), - rpl::single(QString()), - tr::lng_gift_convert_to_stars( - lt_count, - rpl::single(e.convertStars * 1.))); - const auto convert = CreateChild( - button->parentWidget(), - std::move(convertText), - st::defaultLightButton); - convert->setTextTransform(RoundButton::TextTransform::NoTransform); - convert->widthValue() | rpl::filter([=] { - return convert->widthNoMargins() != buttonWidth; - }) | rpl::start_with_next([=] { - convert->resizeToWidth(buttonWidth); - }, convert->lifetime()); - button->positionValue( - ) | rpl::start_with_next([=](QPoint position) { - convert->move( - position.x(), - (position.y() - + st::starGiftBox.buttonHeight - + st::starGiftBox.buttonPadding.bottom() - - st::starGiftBox.buttonPadding.top() - - convert->height())); - }, convert->lifetime()); - convert->setClickedCallback([=, weak = Ui::MakeWeak(box)] { - const auto stars = e.convertStars; - const auto name = starGiftSender->shortName(); - ConfirmConvertStarGift(box->uiShow(), name, stars, [=] { - if (state->convertButtonBusy.current() - || state->confirmButtonBusy.current()) { - return; - } - state->convertButtonBusy = true; - const auto window = weakWindow.get(); - const auto itemId = MsgId(e.bareMsgId); - if (window && stars) { - const auto done = [=](bool ok) { - if (const auto window = weakWindow.get()) { - if (ok) { - using GiftAction = Data::GiftUpdate::Action; - window->session().data().notifyGiftUpdate({ - .itemId = FullMsgId( - starGiftSender->id, - itemId), - .action = GiftAction::Convert, - }); - } - } - if (const auto strong = weak.data()) { - if (ok) { - strong->closeBox(); - } else { - state->convertButtonBusy = false; - } - } - }; - ConvertStarGift( - window, - starGiftSender, - itemId, - stars, - done); - } - }); - }); - - using namespace Info::Statistics; - const auto loadingAnimation = InfiniteRadialAnimationWidget( - convert, - convert->height() / 2, - &st::starConvertButtonLoading); - AddChildToWidgetCenter(convert, loadingAnimation); - loadingAnimation->showOn(state->convertButtonBusy.value()); - } } void GiftedCreditsBox(