inline_bot_confirm_prepared.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 "inline_bots/inline_bot_confirm_prepared.h"
  8. #include "boxes/peers/edit_peer_invite_link.h"
  9. #include "data/data_forum_topic.h"
  10. #include "data/data_session.h"
  11. #include "data/data_user.h"
  12. #include "history/admin_log/history_admin_log_item.h"
  13. #include "history/view/history_view_element.h"
  14. #include "history/history.h"
  15. #include "history/history_item.h"
  16. #include "lang/lang_keys.h"
  17. #include "main/main_session.h"
  18. #include "ui/chat/chat_style.h"
  19. #include "ui/chat/chat_theme.h"
  20. #include "ui/effects/path_shift_gradient.h"
  21. #include "ui/layers/generic_box.h"
  22. #include "ui/wrap/slide_wrap.h"
  23. #include "ui/painter.h"
  24. #include "ui/vertical_list.h"
  25. #include "window/themes/window_theme.h"
  26. #include "window/section_widget.h"
  27. #include "styles/style_chat.h"
  28. #include "styles/style_layers.h"
  29. namespace InlineBots {
  30. namespace {
  31. using namespace HistoryView;
  32. class PreviewDelegate final : public DefaultElementDelegate {
  33. public:
  34. PreviewDelegate(
  35. not_null<QWidget*> parent,
  36. not_null<Ui::ChatStyle*> st,
  37. Fn<void()> update);
  38. bool elementAnimationsPaused() override;
  39. not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
  40. Context elementContext() override;
  41. private:
  42. const not_null<QWidget*> _parent;
  43. const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
  44. };
  45. class PreviewWrap final : public Ui::RpWidget {
  46. public:
  47. PreviewWrap(not_null<QWidget*> parent, not_null<HistoryItem*> item);
  48. ~PreviewWrap();
  49. private:
  50. void paintEvent(QPaintEvent *e) override;
  51. void resizeTo(int width);
  52. void prepare(not_null<HistoryItem*> item);
  53. const not_null<History*> _history;
  54. const std::unique_ptr<Ui::ChatTheme> _theme;
  55. const std::unique_ptr<Ui::ChatStyle> _style;
  56. const std::unique_ptr<PreviewDelegate> _delegate;
  57. AdminLog::OwnedItem _item;
  58. QPoint _position;
  59. };
  60. PreviewDelegate::PreviewDelegate(
  61. not_null<QWidget*> parent,
  62. not_null<Ui::ChatStyle*> st,
  63. Fn<void()> update)
  64. : _parent(parent)
  65. , _pathGradient(MakePathShiftGradient(st, update)) {
  66. }
  67. bool PreviewDelegate::elementAnimationsPaused() {
  68. return _parent->window()->isActiveWindow();
  69. }
  70. auto PreviewDelegate::elementPathShiftGradient()
  71. -> not_null<Ui::PathShiftGradient*> {
  72. return _pathGradient.get();
  73. }
  74. Context PreviewDelegate::elementContext() {
  75. return Context::History;
  76. }
  77. PreviewWrap::PreviewWrap(
  78. not_null<QWidget*> parent,
  79. not_null<HistoryItem*> item)
  80. : RpWidget(parent)
  81. , _history(item->history())
  82. , _theme(Window::Theme::DefaultChatThemeOn(lifetime()))
  83. , _style(std::make_unique<Ui::ChatStyle>(
  84. _history->session().colorIndicesValue()))
  85. , _delegate(std::make_unique<PreviewDelegate>(
  86. parent,
  87. _style.get(),
  88. [=] { update(); }))
  89. , _position(0, st::msgMargin.bottom()) {
  90. _style->apply(_theme.get());
  91. using namespace HistoryView;
  92. _history->owner().viewRepaintRequest(
  93. ) | rpl::start_with_next([=](not_null<const Element*> view) {
  94. if (view == _item.get()) {
  95. update();
  96. }
  97. }, lifetime());
  98. _history->session().downloaderTaskFinished() | rpl::start_with_next([=] {
  99. update();
  100. }, lifetime());
  101. prepare(item);
  102. }
  103. PreviewWrap::~PreviewWrap() {
  104. _item = {};
  105. }
  106. void PreviewWrap::prepare(not_null<HistoryItem*> item) {
  107. _item = AdminLog::OwnedItem(_delegate.get(), item);
  108. if (width() >= st::msgMinWidth) {
  109. resizeTo(width());
  110. }
  111. widthValue(
  112. ) | rpl::filter([=](int width) {
  113. return width >= st::msgMinWidth;
  114. }) | rpl::start_with_next([=](int width) {
  115. resizeTo(width);
  116. }, lifetime());
  117. }
  118. void PreviewWrap::resizeTo(int width) {
  119. const auto height = _position.y()
  120. + _item->resizeGetHeight(width)
  121. + _position.y()
  122. + st::msgServiceMargin.top()
  123. + st::msgServiceGiftBoxTopSkip
  124. - st::msgServiceMargin.bottom();
  125. resize(width, height);
  126. }
  127. void PreviewWrap::paintEvent(QPaintEvent *e) {
  128. auto p = Painter(this);
  129. const auto clip = e->rect();
  130. if (!clip.isEmpty()) {
  131. p.setClipRect(clip);
  132. Window::SectionWidget::PaintBackground(
  133. p,
  134. _theme.get(),
  135. QSize(width(), window()->height()),
  136. clip);
  137. }
  138. auto context = _theme->preparePaintContext(
  139. _style.get(),
  140. rect(),
  141. e->rect(),
  142. !window()->isActiveWindow());
  143. p.translate(_position);
  144. _item->draw(p, context);
  145. }
  146. } // namespace
  147. void PreparedPreviewBox(
  148. not_null<Ui::GenericBox*> box,
  149. not_null<HistoryItem*> item,
  150. rpl::producer<not_null<Data::Thread*>> recipient,
  151. Fn<void()> choose,
  152. Fn<void(not_null<Data::Thread*>)> send) {
  153. box->setTitle(tr::lng_bot_share_prepared_title());
  154. const auto container = box->verticalLayout();
  155. container->add(object_ptr<PreviewWrap>(container, item));
  156. const auto bot = item->viaBot();
  157. const auto name = bot ? bot->name() : u"Bot"_q;
  158. const auto info = container->add(
  159. object_ptr<Ui::SlideWrap<Ui::DividerLabel>>(
  160. container,
  161. object_ptr<Ui::DividerLabel>(
  162. container,
  163. object_ptr<Ui::FlatLabel>(
  164. container,
  165. tr::lng_bot_share_prepared_about(lt_bot, rpl::single(name)),
  166. st::boxDividerLabel),
  167. st::defaultBoxDividerLabelPadding,
  168. RectPart::Top | RectPart::Bottom)));
  169. const auto row = container->add(object_ptr<Ui::VerticalLayout>(
  170. container));
  171. const auto reset = [=] {
  172. info->show(anim::type::instant);
  173. while (row->count()) {
  174. delete row->widgetAt(0);
  175. }
  176. box->addButton(tr::lng_bot_share_prepared_button(), choose);
  177. box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
  178. };
  179. reset();
  180. const auto lifetime = box->lifetime().make_state<rpl::lifetime>();
  181. std::move(
  182. recipient
  183. ) | rpl::start_with_next([=](not_null<Data::Thread*> thread) {
  184. info->hide(anim::type::instant);
  185. while (row->count()) {
  186. delete row->widgetAt(0);
  187. }
  188. AddSkip(row);
  189. AddSinglePeerRow(row, thread, nullptr, choose);
  190. if (const auto topic = thread->asTopic()) {
  191. *lifetime = topic->destroyed() | rpl::start_with_next(reset);
  192. } else {
  193. *lifetime = rpl::lifetime();
  194. }
  195. row->resizeToWidth(container->width());
  196. box->clearButtons();
  197. box->addButton(tr::lng_send_button(), [=] { send(thread); });
  198. box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
  199. }, info->lifetime());
  200. item->history()->owner().itemRemoved(
  201. ) | rpl::start_with_next([=](not_null<const HistoryItem*> removed) {
  202. if (removed == item) {
  203. box->closeBox();
  204. }
  205. }, box->lifetime());
  206. }
  207. } // namespace InlineBots