show_or_premium_box.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "ui/boxes/show_or_premium_box.h"
  8. #include "base/object_ptr.h"
  9. #include "lang/lang_keys.h"
  10. #include "ui/effects/premium_graphics.h"
  11. #include "ui/layers/generic_box.h"
  12. #include "ui/text/text_utilities.h"
  13. #include "ui/widgets/buttons.h"
  14. #include "ui/widgets/gradient_round_button.h"
  15. #include "ui/widgets/labels.h"
  16. #include "ui/painter.h"
  17. #include "styles/style_layers.h"
  18. #include "styles/style_premium.h"
  19. namespace Ui {
  20. namespace {
  21. constexpr auto kShowOrLineOpacity = 0.3;
  22. [[nodiscard]] object_ptr<RpWidget> MakeShowOrPremiumIcon(
  23. not_null<RpWidget*> parent,
  24. not_null<const style::icon*> icon) {
  25. const auto margin = st::showOrIconMargin;
  26. const auto padding = st::showOrIconPadding;
  27. const auto inner = padding.top() + icon->height() + padding.bottom();
  28. const auto full = margin.top() + inner + margin.bottom();
  29. auto result = object_ptr<FixedHeightWidget>(parent, full);
  30. const auto raw = result.data();
  31. raw->resize(st::boxWideWidth, full);
  32. raw->paintRequest(
  33. ) | rpl::start_with_next([=] {
  34. auto p = QPainter(raw);
  35. auto hq = PainterHighQualityEnabler(p);
  36. const auto width = raw->width();
  37. const auto position = QPoint((width - inner) / 2, margin.top());
  38. const auto rect = QRect(position, QSize(inner, inner));
  39. const auto shift = QPoint(padding.left(), padding.top());
  40. p.setPen(Qt::NoPen);
  41. p.setBrush(st::showOrIconBg);
  42. p.drawEllipse(rect);
  43. icon->paint(p, position + shift, width);
  44. }, raw->lifetime());
  45. return result;
  46. }
  47. } // namespace
  48. object_ptr<RpWidget> MakeShowOrLabel(
  49. not_null<RpWidget*> parent,
  50. rpl::producer<QString> text) {
  51. auto result = object_ptr<FlatLabel>(
  52. parent,
  53. std::move(text),
  54. st::showOrLabel);
  55. const auto raw = result.data();
  56. raw->paintRequest(
  57. ) | rpl::start_with_next([=] {
  58. auto p = QPainter(raw);
  59. const auto full = st::showOrLineWidth;
  60. const auto left = (raw->width() - full) / 2;
  61. const auto text = raw->textMaxWidth() + 2 * st::showOrLabelSkip;
  62. const auto fill = (full - text) / 2;
  63. const auto stroke = st::lineWidth;
  64. const auto top = st::showOrLineTop;
  65. p.setOpacity(kShowOrLineOpacity);
  66. p.fillRect(left, top, fill, stroke, st::windowSubTextFg);
  67. const auto start = left + full - fill;
  68. p.fillRect(start, top, fill, stroke, st::windowSubTextFg);
  69. }, raw->lifetime());
  70. return result;
  71. }
  72. void ShowOrPremiumBox(
  73. not_null<GenericBox*> box,
  74. ShowOrPremium type,
  75. QString shortName,
  76. Fn<void()> justShow,
  77. Fn<void()> toPremium) {
  78. struct Skin {
  79. rpl::producer<QString> showTitle;
  80. rpl::producer<TextWithEntities> showAbout;
  81. rpl::producer<QString> showButton;
  82. rpl::producer<QString> orPremium;
  83. rpl::producer<QString> premiumTitle;
  84. rpl::producer<TextWithEntities> premiumAbout;
  85. rpl::producer<QString> premiumButton;
  86. QString toast;
  87. const style::icon *icon = nullptr;
  88. };
  89. auto skin = (type == ShowOrPremium::LastSeen)
  90. ? Skin{
  91. tr::lng_lastseen_show_title(),
  92. tr::lng_lastseen_show_about(
  93. lt_user,
  94. rpl::single(TextWithEntities{ shortName }),
  95. Text::RichLangValue),
  96. tr::lng_lastseen_show_button(),
  97. tr::lng_lastseen_or(),
  98. tr::lng_lastseen_premium_title(),
  99. tr::lng_lastseen_premium_about(
  100. lt_user,
  101. rpl::single(TextWithEntities{ shortName }),
  102. Text::RichLangValue),
  103. tr::lng_lastseen_premium_button(),
  104. tr::lng_lastseen_shown_toast(tr::now),
  105. &st::showOrIconLastSeen,
  106. }
  107. : Skin{
  108. tr::lng_readtime_show_title(),
  109. tr::lng_readtime_show_about(
  110. lt_user,
  111. rpl::single(TextWithEntities{ shortName }),
  112. Text::RichLangValue),
  113. tr::lng_readtime_show_button(),
  114. tr::lng_readtime_or(),
  115. tr::lng_readtime_premium_title(),
  116. tr::lng_readtime_premium_about(
  117. lt_user,
  118. rpl::single(TextWithEntities{ shortName }),
  119. Text::RichLangValue),
  120. tr::lng_readtime_premium_button(),
  121. tr::lng_readtime_shown_toast(tr::now),
  122. &st::showOrIconReadTime,
  123. };
  124. box->setStyle(st::showOrBox);
  125. box->setWidth(st::boxWideWidth);
  126. box->addTopButton(st::boxTitleClose, [=] {
  127. box->closeBox();
  128. });
  129. const auto buttonPadding = QMargins(
  130. st::showOrBox.buttonPadding.left(),
  131. 0,
  132. st::showOrBox.buttonPadding.right(),
  133. 0);
  134. box->addRow(MakeShowOrPremiumIcon(box, skin.icon));
  135. box->addRow(
  136. object_ptr<FlatLabel>(
  137. box,
  138. std::move(skin.showTitle),
  139. st::boostCenteredTitle),
  140. st::showOrTitlePadding + buttonPadding);
  141. box->addRow(
  142. object_ptr<FlatLabel>(
  143. box,
  144. std::move(skin.showAbout),
  145. st::boostText),
  146. st::showOrAboutPadding + buttonPadding);
  147. const auto show = box->addRow(
  148. object_ptr<RoundButton>(
  149. box,
  150. std::move(skin.showButton),
  151. st::showOrShowButton),
  152. buttonPadding);
  153. show->setTextTransform(RoundButton::TextTransform::NoTransform);
  154. box->addRow(
  155. MakeShowOrLabel(box, std::move(skin.orPremium)),
  156. st::showOrLabelPadding + buttonPadding);
  157. box->addRow(
  158. object_ptr<FlatLabel>(
  159. box,
  160. std::move(skin.premiumTitle),
  161. st::boostCenteredTitle),
  162. st::showOrTitlePadding + buttonPadding);
  163. box->addRow(
  164. object_ptr<FlatLabel>(
  165. box,
  166. std::move(skin.premiumAbout),
  167. st::boostText),
  168. st::showOrPremiumAboutPadding + buttonPadding);
  169. const auto premium = CreateChild<GradientButton>(
  170. box.get(),
  171. Premium::ButtonGradientStops());
  172. premium->resize(st::showOrShowButton.width, st::showOrShowButton.height);
  173. const auto label = CreateChild<FlatLabel>(
  174. premium,
  175. std::move(skin.premiumButton),
  176. st::premiumPreviewButtonLabel);
  177. label->setAttribute(Qt::WA_TransparentForMouseEvents);
  178. rpl::combine(
  179. premium->widthValue(),
  180. label->widthValue()
  181. ) | rpl::start_with_next([=](int outer, int width) {
  182. label->moveToLeft(
  183. (outer - width) / 2,
  184. st::premiumPreviewBox.button.textTop,
  185. outer);
  186. }, label->lifetime());
  187. box->setShowFinishedCallback([=] {
  188. premium->startGlareAnimation();
  189. });
  190. box->addButton(
  191. object_ptr<AbstractButton>::fromRaw(premium));
  192. show->setClickedCallback([box, justShow, toast = skin.toast] {
  193. justShow();
  194. box->uiShow()->showToast(toast);
  195. box->closeBox();
  196. });
  197. premium->setClickedCallback(std::move(toPremium));
  198. }
  199. } // namespace Ui