/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "ui/boxes/show_or_premium_box.h" #include "base/object_ptr.h" #include "lang/lang_keys.h" #include "ui/effects/premium_graphics.h" #include "ui/layers/generic_box.h" #include "ui/text/text_utilities.h" #include "ui/widgets/buttons.h" #include "ui/widgets/gradient_round_button.h" #include "ui/widgets/labels.h" #include "ui/painter.h" #include "styles/style_layers.h" #include "styles/style_premium.h" namespace Ui { namespace { constexpr auto kShowOrLineOpacity = 0.3; [[nodiscard]] object_ptr MakeShowOrPremiumIcon( not_null parent, not_null icon) { const auto margin = st::showOrIconMargin; const auto padding = st::showOrIconPadding; const auto inner = padding.top() + icon->height() + padding.bottom(); const auto full = margin.top() + inner + margin.bottom(); auto result = object_ptr(parent, full); const auto raw = result.data(); raw->resize(st::boxWideWidth, full); raw->paintRequest( ) | rpl::start_with_next([=] { auto p = QPainter(raw); auto hq = PainterHighQualityEnabler(p); const auto width = raw->width(); const auto position = QPoint((width - inner) / 2, margin.top()); const auto rect = QRect(position, QSize(inner, inner)); const auto shift = QPoint(padding.left(), padding.top()); p.setPen(Qt::NoPen); p.setBrush(st::showOrIconBg); p.drawEllipse(rect); icon->paint(p, position + shift, width); }, raw->lifetime()); return result; } } // namespace object_ptr MakeShowOrLabel( not_null parent, rpl::producer text) { auto result = object_ptr( parent, std::move(text), st::showOrLabel); const auto raw = result.data(); raw->paintRequest( ) | rpl::start_with_next([=] { auto p = QPainter(raw); const auto full = st::showOrLineWidth; const auto left = (raw->width() - full) / 2; const auto text = raw->textMaxWidth() + 2 * st::showOrLabelSkip; const auto fill = (full - text) / 2; const auto stroke = st::lineWidth; const auto top = st::showOrLineTop; p.setOpacity(kShowOrLineOpacity); p.fillRect(left, top, fill, stroke, st::windowSubTextFg); const auto start = left + full - fill; p.fillRect(start, top, fill, stroke, st::windowSubTextFg); }, raw->lifetime()); return result; } void ShowOrPremiumBox( not_null box, ShowOrPremium type, QString shortName, Fn justShow, Fn toPremium) { struct Skin { rpl::producer showTitle; rpl::producer showAbout; rpl::producer showButton; rpl::producer orPremium; rpl::producer premiumTitle; rpl::producer premiumAbout; rpl::producer premiumButton; QString toast; const style::icon *icon = nullptr; }; auto skin = (type == ShowOrPremium::LastSeen) ? Skin{ tr::lng_lastseen_show_title(), tr::lng_lastseen_show_about( lt_user, rpl::single(TextWithEntities{ shortName }), Text::RichLangValue), tr::lng_lastseen_show_button(), tr::lng_lastseen_or(), tr::lng_lastseen_premium_title(), tr::lng_lastseen_premium_about( lt_user, rpl::single(TextWithEntities{ shortName }), Text::RichLangValue), tr::lng_lastseen_premium_button(), tr::lng_lastseen_shown_toast(tr::now), &st::showOrIconLastSeen, } : (type == ShowOrPremium::ReadTime) ? Skin{ tr::lng_readtime_show_title(), tr::lng_readtime_show_about( lt_user, rpl::single(TextWithEntities{ shortName }), Text::RichLangValue), tr::lng_readtime_show_button(), tr::lng_readtime_or(), tr::lng_readtime_premium_title(), tr::lng_readtime_premium_about( lt_user, rpl::single(TextWithEntities{ shortName }), Text::RichLangValue), tr::lng_readtime_premium_button(), tr::lng_readtime_shown_toast(tr::now), &st::showOrIconReadTime, } : Skin(); box->setStyle(st::showOrBox); box->setWidth(st::boxWideWidth); box->addTopButton(st::boxTitleClose, [=] { box->closeBox(); }); box->addRow(MakeShowOrPremiumIcon(box, skin.icon)); box->addRow( object_ptr( box, std::move(skin.showTitle), st::boostCenteredTitle), st::showOrTitlePadding); box->addRow( object_ptr( box, std::move(skin.showAbout), st::boostText), st::showOrAboutPadding); const auto show = box->addRow( object_ptr( box, std::move(skin.showButton), st::showOrShowButton), QMargins( st::showOrBox.buttonPadding.left(), 0, st::showOrBox.buttonPadding.right(), 0)); show->setTextTransform(RoundButton::TextTransform::NoTransform); box->addRow( MakeShowOrLabel(box, std::move(skin.orPremium)), st::showOrLabelPadding); box->addRow( object_ptr( box, std::move(skin.premiumTitle), st::boostCenteredTitle), st::showOrTitlePadding); box->addRow( object_ptr( box, std::move(skin.premiumAbout), st::boostText), st::showOrPremiumAboutPadding); const auto premium = CreateChild( box.get(), Premium::ButtonGradientStops()); premium->resize(st::showOrShowButton.width, st::showOrShowButton.height); const auto label = CreateChild( premium, std::move(skin.premiumButton), st::premiumPreviewButtonLabel); label->setAttribute(Qt::WA_TransparentForMouseEvents); rpl::combine( premium->widthValue(), label->widthValue() ) | rpl::start_with_next([=](int outer, int width) { label->moveToLeft( (outer - width) / 2, st::premiumPreviewBox.button.textTop, outer); }, label->lifetime()); box->setShowFinishedCallback([=] { premium->startGlareAnimation(); }); box->addButton( object_ptr::fromRaw(premium)); show->setClickedCallback([box, justShow, toast = skin.toast] { justShow(); box->uiShow()->showToast(toast); box->closeBox(); }); premium->setClickedCallback(std::move(toPremium)); } } // namespace Ui