diff --git a/Telegram/Resources/icons/settings/earn.png b/Telegram/Resources/icons/settings/earn.png new file mode 100644 index 0000000000..c2e73499e1 Binary files /dev/null and b/Telegram/Resources/icons/settings/earn.png differ diff --git a/Telegram/Resources/icons/settings/earn@2x.png b/Telegram/Resources/icons/settings/earn@2x.png new file mode 100644 index 0000000000..53b7eec28c Binary files /dev/null and b/Telegram/Resources/icons/settings/earn@2x.png differ diff --git a/Telegram/Resources/icons/settings/earn@3x.png b/Telegram/Resources/icons/settings/earn@3x.png new file mode 100644 index 0000000000..33c7144690 Binary files /dev/null and b/Telegram/Resources/icons/settings/earn@3x.png differ diff --git a/Telegram/Resources/icons/settings/gift.png b/Telegram/Resources/icons/settings/gift.png new file mode 100644 index 0000000000..8dacb6c7eb Binary files /dev/null and b/Telegram/Resources/icons/settings/gift.png differ diff --git a/Telegram/Resources/icons/settings/gift@2x.png b/Telegram/Resources/icons/settings/gift@2x.png new file mode 100644 index 0000000000..996bd85d0b Binary files /dev/null and b/Telegram/Resources/icons/settings/gift@2x.png differ diff --git a/Telegram/Resources/icons/settings/gift@3x.png b/Telegram/Resources/icons/settings/gift@3x.png new file mode 100644 index 0000000000..240680269e Binary files /dev/null and b/Telegram/Resources/icons/settings/gift@3x.png differ diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 85872ff6eb..225fb6b75a 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2795,10 +2795,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_credits_premium_gift_duration" = "Duration"; "lng_credits_more_options" = "More Options"; "lng_credits_balance_me" = "your balance"; -"lng_credits_buy_button" = "Buy More Stars"; +"lng_credits_balance_me_count" = "Your balance: {emoji} {amount}"; +"lng_credits_buy_button" = "Top Up Balance"; "lng_credits_buy_button_short" = "Top Up"; "lng_credits_stats_button_short" = "Stats"; +"lng_credits_stats_button" = "View Statistics"; "lng_credits_gift_button" = "Gift Stars to Friends"; +"lng_credits_earn_button" = "Earn Stars from Mini Apps"; "lng_credits_box_out_title" = "Confirm Your Purchase"; "lng_credits_box_out_sure#one" = "Do you want to buy **\"{text}\"** in **{bot}** for **{count} Star**?"; "lng_credits_box_out_sure#other" = "Do you want to buy **\"{text}\"** in **{bot}** for **{count} Stars**?"; diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp index 231d0010e1..db73f6249d 100644 --- a/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp +++ b/Telegram/SourceFiles/info/statistics/info_statistics_list_controllers.cpp @@ -19,7 +19,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_stories.h" #include "data/data_user.h" -#include "data/stickers/data_custom_emoji.h" #include "history/history_item.h" #include "info/channel_statistics/boosts/giveaway/boost_badge.h" #include "lang/lang_keys.h" @@ -921,16 +920,15 @@ void CreditsRow::init() { } }); } - auto &manager = _session->data().customEmojiManager(); if (_entry) { constexpr auto kMinus = QChar(0x2212); _rightText.setMarkedText( - st::semiboldTextStyle, + st::creditsHistoryRowRightStyle, TextWithEntities() .append(_entry.in ? QChar('+') : kMinus) .append(Lang::FormatCreditsAmountDecimal(_entry.credits.abs())) .append(QChar(' ')) - .append(manager.creditsEmoji()), + .append(Ui::MakeCreditsIconEntity()), kMarkupTextOptions, _context); } @@ -1041,7 +1039,6 @@ void CreditsRow::rightActionPaint( p.drawTextRight(rightSkip, y - statusFont->height / 2, outerWidth, t); return; } - y += _rowHeight / 2; p.setPen(_entry.pending ? st::creditsStroke : _entry.in @@ -1050,7 +1047,7 @@ void CreditsRow::rightActionPaint( _rightText.draw(p, Ui::Text::PaintContext{ .position = QPoint( outerWidth - _rightText.maxWidth() - rightSkip, - y - font->height / 2), + y + st::creditsHistoryRowRightTop), .outerWidth = outerWidth, .availableWidth = outerWidth, }); @@ -1079,7 +1076,7 @@ void CreditsRow::paintStatusText( available -= thumbnailSpace; } _description.draw(p, { - .position = QPoint(x, y - _description.minHeight()), + .position = QPoint(x, y - st::creditsHistoryRowDescriptionSkip), .outerWidth = outer, .availableWidth = available, .elisionLines = 1, @@ -1130,7 +1127,16 @@ CreditsController::CreditsController(CreditsDescriptor d) , _entryClickedCallback(std::move(d.entryClickedCallback)) , _api(d.peer, d.in, d.out) , _firstSlice(std::move(d.firstSlice)) -, _context(Core::TextContext({ .session = _session })) { +, _context([&]() -> Ui::Text::MarkedContext { + const auto height = st::creditsHistoryRowRightStyle.font->height + - st::lineWidth; + auto customEmojiFactory = [=](const auto &...) { + return std::make_unique( + Ui::MakeCreditsIconEmoji(height, 1), + QPoint(-st::lineWidth, st::lineWidth)); + }; + return { .customEmojiFactory = std::move(customEmojiFactory) }; +}()) { PeerListController::setStyleOverrides(&st::creditsHistoryEntriesList); } diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style index 76396d8b28..6cb2d637bd 100644 --- a/Telegram/SourceFiles/settings/settings.style +++ b/Telegram/SourceFiles/settings/settings.style @@ -706,3 +706,9 @@ settingsCreditsButtonStats: RoundButton(inviteLinkCopy) { icon: icon {{ "info/edit/links_share", activeButtonFg }}; iconOver: icon {{ "info/edit/links_share", activeButtonFgOver }}; } + +settingsCreditsButton: SettingsButton(settingsButton) { + padding: margins(62px, 8px, 22px, 8px); +} +settingsButtonIconGift: icon {{ "settings/gift", menuIconColor }}; +settingsButtonIconEarn: icon {{ "settings/earn", menuIconColor }}; diff --git a/Telegram/SourceFiles/settings/settings_credits.cpp b/Telegram/SourceFiles/settings/settings_credits.cpp index c758708953..750dce522d 100644 --- a/Telegram/SourceFiles/settings/settings_credits.cpp +++ b/Telegram/SourceFiles/settings/settings_credits.cpp @@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/effects/premium_graphics.h" #include "ui/effects/premium_top_bar.h" #include "ui/layers/generic_box.h" +#include "ui/text/format_values.h" #include "ui/painter.h" #include "ui/rect.h" #include "ui/text/text_utilities.h" @@ -53,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_premium.h" #include "styles/style_settings.h" #include "styles/style_statistics.h" +#include "styles/style_menu_icons.h" namespace Settings { namespace { @@ -80,7 +82,6 @@ private: void setupContent(); void setupHistory(not_null container); void setupSubscriptions(not_null container); - void setupStarRefPromo(not_null container); const not_null _controller; QWidget *_parent = nullptr; @@ -212,25 +213,6 @@ void Credits::setupSubscriptions(not_null container) { } } -void Credits::setupStarRefPromo(not_null container) { - const auto self = _controller->session().user(); - if (!Info::BotStarRef::Join::Allowed(self)) { - return; - } - Ui::AddSkip(container); - const auto button = Info::BotStarRef::AddViewListButton( - container, - tr::lng_credits_summary_earn_title(), - tr::lng_credits_summary_earn_about(), - true); - button->setClickedCallback([=] { - _controller->showSection(Info::BotStarRef::Join::Make(self)); - }); - Ui::AddSkip(container); - Ui::AddDivider(container); - Ui::AddSkip(container); -} - void Credits::setupHistory(not_null container) { const auto history = container->add( object_ptr>( @@ -239,7 +221,7 @@ void Credits::setupHistory(not_null container) { const auto content = history->entity(); const auto self = _controller->session().user(); - Ui::AddSkip(content); + Ui::AddSkip(content, st::lineWidth * 6); const auto fill = [=]( not_null premiumBot, @@ -271,9 +253,26 @@ void Credits::setupHistory(not_null container) { inner, object_ptr( inner, - st::defaultTabsSlider)), - st::boxRowPadding); + st::creditsHistoryTabsSlider)), + st::creditsHistoryTabsSliderPadding); slider->toggle(!hasOneTab, anim::type::instant); + if (!hasOneTab) { + const auto shadow = Ui::CreateChild(inner); + shadow->paintRequest() | rpl::start_with_next([=] { + auto p = QPainter(shadow); + p.fillRect(shadow->rect(), st::shadowFg); + }, shadow->lifetime()); + slider->geometryValue( + ) | rpl::start_with_next([=](const QRect &r) { + shadow->setGeometry( + inner->x(), + rect::bottom(slider) - st::lineWidth, + inner->width(), + st::lineWidth); + shadow->show(); + shadow->raise(); + }, shadow->lifetime()); + } slider->entity()->addSection(fullTabText); if (hasIn) { @@ -284,12 +283,12 @@ void Credits::setupHistory(not_null container) { } { - const auto &st = st::defaultTabsSlider; + const auto &st = st::creditsHistoryTabsSlider; slider->entity()->setNaturalWidth(0 + st.labelStyle.font->width(fullTabText) + (hasIn ? st.labelStyle.font->width(inTabText) : 0) + (hasOut ? st.labelStyle.font->width(outTabText) : 0) - + rect::m::sum::h(st::boxRowPadding)); + + rect::m::sum::h(st::creditsHistoryTabsSliderPadding)); } const auto fullWrap = inner->add( @@ -393,41 +392,6 @@ void Credits::setupContent() { Ui::StartFireworks(_parent); } }; - Ui::AddSkip(content); - Ui::AddSkip(content); - const auto balanceLine = content->add( - object_ptr>( - content, - object_ptr(content)))->entity(); - const auto balanceIcon = CreateSingleStarWidget( - balanceLine, - st::creditsSettingsBigBalance.style.font->height); - const auto balanceAmount = Ui::CreateChild( - balanceLine, - _controller->session().credits().balanceValue( - ) | rpl::map(Lang::FormatCreditsAmountDecimal), - st::creditsSettingsBigBalance); - balanceAmount->sizeValue() | rpl::start_with_next([=] { - balanceLine->resize( - balanceIcon->width() - + st::creditsSettingsBigBalanceSkip - + balanceAmount->textMaxWidth(), - balanceIcon->height()); - }, balanceLine->lifetime()); - balanceLine->widthValue() | rpl::start_with_next([=] { - balanceAmount->moveToRight(0, 0); - }, balanceLine->lifetime()); - Ui::AddSkip(content); - content->add( - object_ptr>( - content, - object_ptr( - content, - tr::lng_credits_balance_me(), - st::infoTopBar.subtitle))); - Ui::AddSkip(content); - Ui::AddSkip(content); - Ui::AddSkip(content); struct State final { BuyStarsHandler buyStars; @@ -435,16 +399,18 @@ void Credits::setupContent() { const auto state = content->lifetime().make_state(); const auto paddings = rect::m::sum::h(st::boxRowPadding); - if (!_controller->session().credits().statsEnabled()) { + { const auto button = content->add( - object_ptr( + object_ptr>( content, - rpl::conditional( - state->buyStars.loadingValue(), - rpl::single(QString()), - tr::lng_credits_buy_button()), - st::creditsSettingsBigBalanceButton), - st::boxRowPadding); + object_ptr( + content, + rpl::conditional( + state->buyStars.loadingValue(), + rpl::single(QString()), + tr::lng_credits_buy_button()), + st::creditsSettingsBigBalanceButton)), + st::boxRowPadding)->entity(); button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); const auto show = _controller->uiShow(); button->setClickedCallback(state->buyStars.handler(show, paid)); @@ -456,101 +422,87 @@ void Credits::setupContent() { AddChildToWidgetCenter(button, loadingAnimation); loadingAnimation->showOn(state->buyStars.loadingValue()); } - button->widthValue() | rpl::filter([=] { - return button->widthNoMargins() != (content->width() - paddings); - }) | rpl::start_with_next([=] { - button->resizeToWidth(content->width() - paddings); - }, button->lifetime()); - } else { - const auto wrap = content->add( - object_ptr( - content, - st::inviteLinkButton.height), - st::boxRowPadding); - const auto buy = Ui::CreateChild( - wrap, - tr::lng_credits_buy_button_short(), - st::settingsCreditsButtonBuy); - buy->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); - const auto show = _controller->uiShow(); - buy->setClickedCallback(state->buyStars.handler(show, paid)); - { - using namespace Info::Statistics; - const auto loadingAnimation = InfiniteRadialAnimationWidget( - buy, - buy->height() / 2); - AddChildToWidgetCenter(buy, loadingAnimation); - loadingAnimation->showOn(state->buyStars.loadingValue()); - } - const auto stats = Ui::CreateChild( - wrap, - tr::lng_credits_stats_button_short(), - st::settingsCreditsButtonStats); - stats->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); - const auto self = _controller->session().user(); - const auto controller = _controller->parentController(); - stats->setClickedCallback([=] { - controller->showSection(Info::BotEarn::Make(self)); - }); - - wrap->widthValue( - ) | rpl::start_with_next([=](int width) { - const auto buttonWidth = (width - st::inviteLinkButtonsSkip) / 2; - buy->setFullWidth(buttonWidth); - stats->setFullWidth(buttonWidth); - buy->moveToLeft(0, 0, width); - stats->moveToRight(0, 0, width); - }, wrap->lifetime()); } Ui::AddSkip(content); - - { - const auto &giftSt = st::creditsSettingsBigBalanceButtonGift; - const auto giftDelay = giftSt.ripple.hideDuration * 2; - const auto fakeLoading - = content->lifetime().make_state>(false); - const auto gift = content->add( - object_ptr( - content, - rpl::conditional( - fakeLoading->value(), - rpl::single(QString()), - tr::lng_credits_gift_button()), - giftSt), - st::boxRowPadding); - gift->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); - gift->setClickedCallback([=, controller = _controller] { - if (fakeLoading->current()) { - return; - } - *fakeLoading = true; - base::call_delayed(giftDelay, crl::guard(gift, [=] { - *fakeLoading = false; - Ui::ShowGiftCreditsBox(controller, paid); - })); - }); - { - using namespace Info::Statistics; - const auto loadingAnimation = InfiniteRadialAnimationWidget( - gift, - gift->height() / 2, - &st::editStickerSetNameLoading); - AddChildToWidgetCenter(gift, loadingAnimation); - loadingAnimation->showOn(fakeLoading->value()); - } - gift->widthValue() | rpl::filter([=] { - return (gift->widthNoMargins() != (content->width() - paddings)); - }) | rpl::start_with_next([=] { - gift->resizeToWidth(content->width() - paddings); - }, gift->lifetime()); - } - Ui::AddSkip(content); + Ui::AddSkip(content, st::lineWidth); + + const auto &textSt = st::creditsPremiumCover.about; + auto context = [&]() -> Ui::Text::MarkedContext { + const auto height = textSt.style.font->height; + auto customEmojiFactory = [=](const auto &...) { + return std::make_unique( + Ui::MakeCreditsIconEmoji(height, 1), + QPoint(-st::lineWidth, st::lineWidth)); + }; + return { .customEmojiFactory = std::move(customEmojiFactory) }; + }(); + content->add( + object_ptr>( + content, + object_ptr( + content, + tr::lng_credits_balance_me_count( + lt_emoji, + rpl::single(Ui::MakeCreditsIconEntity()), + lt_amount, + _controller->session().credits().balanceValue( + ) | rpl::map( + Lang::FormatCreditsAmountDecimal + ) | rpl::map(Ui::Text::Bold), + Ui::Text::WithEntities), + textSt, + st::defaultPopupMenu, + std::move(context)))); + Ui::AddSkip(content, st::lineWidth); + Ui::AddSkip(content, st::lineWidth); + Ui::AddSkip(content); + Ui::AddSkip(content); Ui::AddDivider(content); + Ui::AddSkip(content, st::lineWidth * 4); + + const auto controller = _controller->parentController(); + const auto self = _controller->session().user(); + { + const auto wrap = content->add( + object_ptr>( + content, + CreateButtonWithIcon( + content, + tr::lng_credits_stats_button(), + st::settingsCreditsButton, + { &st::menuIconStats }))); + wrap->entity()->setClickedCallback([=] { + controller->showSection(Info::BotEarn::Make(self)); + }); + wrap->toggleOn(_controller->session().credits().loadedValue( + ) | rpl::map([=] { + return _controller->session().credits().statsEnabled(); + })); + } + AddButtonWithIcon( + content, + tr::lng_credits_gift_button(), + st::settingsCreditsButton, + { &st::settingsButtonIconGift })->setClickedCallback([=] { + Ui::ShowGiftCreditsBox(controller, paid); + }); + + if (Info::BotStarRef::Join::Allowed(self)) { + AddButtonWithIcon( + content, + tr::lng_credits_earn_button(), + st::settingsCreditsButton, + { &st::settingsButtonIconEarn })->setClickedCallback([=] { + controller->showSection(Info::BotStarRef::Join::Make(self)); + }); + } + + Ui::AddSkip(content, st::lineWidth * 4); + Ui::AddDivider(content); - setupStarRefPromo(content); setupSubscriptions(content); setupHistory(content); diff --git a/Telegram/SourceFiles/ui/effects/credits.style b/Telegram/SourceFiles/ui/effects/credits.style index b06ef54a64..8692635d54 100644 --- a/Telegram/SourceFiles/ui/effects/credits.style +++ b/Telegram/SourceFiles/ui/effects/credits.style @@ -18,7 +18,8 @@ creditsSettingsBigBalance: FlatLabel(defaultFlatLabel) { } creditsSettingsBigBalanceSkip: 4px; creditsSettingsBigBalanceButton: RoundButton(defaultActiveButton) { - height: 42px; + width: 240px; + height: 40px; textTop: 12px; style: semiboldTextStyle; } @@ -29,9 +30,13 @@ creditsSettingsBigBalanceButtonGift: RoundButton(defaultLightButton) { } creditsPremiumCover: PremiumCover(defaultPremiumCover) { + starTopSkip: 39px; + titleFont: font(15px semibold); about: FlatLabel(userPremiumCoverAbout) { textFg: boxTitleFg; } + aboutMaxWidth: 236px; + additionalShadowForDarkThemes: false; } creditsLowBalancePremiumCover: PremiumCover(creditsPremiumCover) { starSize: size(64px, 62px); @@ -214,16 +219,12 @@ giftBoxLockMargins: margins(-2px, 1px, 0px, 0px); giftBoxPinIcon: icon {{ "dialogs/dialogs_pinned", premiumButtonFg }}; creditsHistoryEntriesList: PeerList(defaultPeerList) { - padding: margins( - 0px, - 7px, - 0px, - 7px); + padding: margins(0px, 7px, 0px, 7px); item: PeerListItem(defaultPeerListItem) { - height: 66px; - photoPosition: point(18px, 6px); + height: 72px; + photoPosition: point(18px, 7px); namePosition: point(70px, 6px); - statusPosition: point(70px, 43px); + statusPosition: point(70px, 46px); photoSize: 42px; } } @@ -297,3 +298,17 @@ giftTooManyPinnedBox: Box(giftBox) { giftTooManyPinnedChoose: FlatLabel(giftBoxAbout) { textFg: windowSubTextFg; } + +creditsHistoryTabsSlider: SettingsSlider(defaultTabsSlider) { + height: 39px; + labelTop: 7px; + barTop: 36px; + barSkip: 0px; + rippleBottomSkip: 0px; +} +creditsHistoryTabsSliderPadding: margins(14px, 0px, 24px, 0px); +creditsHistoryRowDescriptionSkip: 20px; +creditsHistoryRowRightTop: 16px; +creditsHistoryRowRightStyle: TextStyle(defaultTextStyle) { + font: font(fsize); +}