inline_bot_layout_internal.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  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. #pragma once
  8. #include "base/flags.h"
  9. #include "inline_bots/inline_bot_layout_item.h"
  10. #include "media/clip/media_clip_reader.h"
  11. #include "ui/effects/animations.h"
  12. #include "ui/effects/radial_animation.h"
  13. #include "ui/text/text.h"
  14. namespace Lottie {
  15. class SinglePlayer;
  16. } // namespace Lottie
  17. namespace Data {
  18. class PhotoMedia;
  19. class DocumentMedia;
  20. } // namespace Data
  21. namespace InlineBots {
  22. namespace Layout {
  23. namespace internal {
  24. class FileBase : public ItemBase {
  25. public:
  26. FileBase(not_null<Context*> context, std::shared_ptr<Result> result);
  27. // For saved gif layouts.
  28. FileBase(not_null<Context*> context, not_null<DocumentData*> document);
  29. protected:
  30. DocumentData *getShownDocument() const;
  31. int content_width() const;
  32. int content_height() const;
  33. int content_duration() const;
  34. };
  35. class DeleteSavedGifClickHandler : public LeftButtonClickHandler {
  36. public:
  37. DeleteSavedGifClickHandler(not_null<DocumentData*> data) : _data(data) {
  38. }
  39. protected:
  40. void onClickImpl() const override;
  41. private:
  42. const not_null<DocumentData*> _data;
  43. };
  44. class Gif final : public FileBase {
  45. public:
  46. Gif(not_null<Context*> context, std::shared_ptr<Result> result);
  47. Gif(
  48. not_null<Context*> context,
  49. not_null<DocumentData*> document,
  50. bool hasDeleteButton);
  51. void setPosition(int32 position) override;
  52. void initDimensions() override;
  53. bool isFullLine() const override {
  54. return false;
  55. }
  56. bool hasRightSkip() const override {
  57. return true;
  58. }
  59. void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
  60. TextState getState(
  61. QPoint point,
  62. StateRequest request) const override;
  63. // ClickHandlerHost interface
  64. void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
  65. int resizeGetHeight(int width) override;
  66. void unloadHeavyPart() override;
  67. QRect innerContentRect() const override;
  68. private:
  69. enum class StateFlag {
  70. Over = (1 << 0),
  71. DeleteOver = (1 << 1),
  72. };
  73. using StateFlags = base::flags<StateFlag>;
  74. friend inline constexpr auto is_flag_type(StateFlag) { return true; };
  75. struct AnimationData {
  76. template <typename Callback>
  77. AnimationData(Callback &&callback)
  78. : radial(std::forward<Callback>(callback)) {
  79. }
  80. bool over = false;
  81. Ui::Animations::Simple _a_over;
  82. Ui::RadialAnimation radial;
  83. };
  84. void ensureDataMediaCreated(not_null<DocumentData*> document) const;
  85. QSize countFrameSize() const;
  86. void validateThumbnail(
  87. Image *image,
  88. QSize size,
  89. QSize frame,
  90. bool good) const;
  91. void prepareThumbnail(QSize size, QSize frame) const;
  92. void ensureAnimation() const;
  93. bool isRadialAnimation() const;
  94. void radialAnimationCallback(crl::time now) const;
  95. void clipCallback(Media::Clip::Notification notification);
  96. StateFlags _state;
  97. Media::Clip::ReaderPointer _gif;
  98. ClickHandlerPtr _delete;
  99. mutable QImage _thumb;
  100. mutable bool _thumbGood = false;
  101. mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
  102. mutable std::unique_ptr<AnimationData> _animation;
  103. mutable Ui::Animations::Simple _a_deleteOver;
  104. };
  105. class Photo : public ItemBase {
  106. public:
  107. Photo(not_null<Context*> context, std::shared_ptr<Result> result);
  108. // Not used anywhere currently.
  109. //Photo(not_null<Context*> context, not_null<PhotoData*> photo);
  110. void initDimensions() override;
  111. bool isFullLine() const override {
  112. return false;
  113. }
  114. bool hasRightSkip() const override {
  115. return true;
  116. }
  117. void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
  118. TextState getState(
  119. QPoint point,
  120. StateRequest request) const override;
  121. void unloadHeavyPart() override;
  122. private:
  123. PhotoData *getShownPhoto() const;
  124. QSize countFrameSize() const;
  125. mutable QPixmap _thumb;
  126. mutable bool _thumbGood = false;
  127. void prepareThumbnail(QSize size, QSize frame) const;
  128. void validateThumbnail(
  129. Image *image,
  130. QSize size,
  131. QSize frame,
  132. bool good) const;
  133. mutable std::shared_ptr<Data::PhotoMedia> _photoMedia;
  134. };
  135. class Sticker : public FileBase {
  136. public:
  137. Sticker(not_null<Context*> context, std::shared_ptr<Result> result);
  138. ~Sticker();
  139. // Not used anywhere currently.
  140. //Sticker(not_null<Context*> context, not_null<DocumentData*> document);
  141. void initDimensions() override;
  142. bool isFullLine() const override {
  143. return false;
  144. }
  145. bool hasRightSkip() const override {
  146. return false;
  147. }
  148. void preload() const override;
  149. void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
  150. TextState getState(
  151. QPoint point,
  152. StateRequest request) const override;
  153. // ClickHandlerHost interface
  154. void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
  155. void unloadHeavyPart() override;
  156. QRect innerContentRect() const override;
  157. private:
  158. void ensureDataMediaCreated(not_null<DocumentData*> document) const;
  159. void setupLottie() const;
  160. void setupWebm() const;
  161. QSize getThumbSize() const;
  162. QSize boundingBox() const;
  163. void prepareThumbnail() const;
  164. void clipCallback(Media::Clip::Notification notification);
  165. mutable Ui::Animations::Simple _a_over;
  166. mutable bool _active = false;
  167. mutable QPixmap _thumb;
  168. mutable bool _thumbLoaded = false;
  169. mutable std::unique_ptr<Lottie::SinglePlayer> _lottie;
  170. Media::Clip::ReaderPointer _webm;
  171. mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
  172. mutable rpl::lifetime _lifetime;
  173. };
  174. class Video : public FileBase {
  175. public:
  176. Video(not_null<Context*> context, std::shared_ptr<Result> result);
  177. void initDimensions() override;
  178. void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
  179. TextState getState(
  180. QPoint point,
  181. StateRequest request) const override;
  182. void unloadHeavyPart() override;
  183. private:
  184. ClickHandlerPtr _link;
  185. mutable QPixmap _thumb;
  186. mutable std::shared_ptr<Data::DocumentMedia> _documentMedia;
  187. Ui::Text::String _title, _description;
  188. QString _duration;
  189. int _durationWidth = 0;
  190. [[nodiscard]] bool withThumbnail() const;
  191. void prepareThumbnail(QSize size) const;
  192. };
  193. class CancelFileClickHandler : public LeftButtonClickHandler {
  194. public:
  195. CancelFileClickHandler(not_null<Result*> result) : _result(result) {
  196. }
  197. protected:
  198. void onClickImpl() const override;
  199. private:
  200. not_null<Result*> _result;
  201. };
  202. class File : public FileBase {
  203. public:
  204. File(not_null<Context*> context, std::shared_ptr<Result> result);
  205. ~File();
  206. void initDimensions() override;
  207. void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
  208. TextState getState(
  209. QPoint point,
  210. StateRequest request) const override;
  211. // ClickHandlerHost interface
  212. void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
  213. void unloadHeavyPart() override;
  214. private:
  215. void thumbAnimationCallback();
  216. void radialAnimationCallback(crl::time now) const;
  217. void ensureAnimation() const;
  218. void ensureDataMediaCreated() const;
  219. void checkAnimationFinished() const;
  220. bool updateStatusText() const;
  221. bool isRadialAnimation() const {
  222. if (_animation) {
  223. if (_animation->radial.animating()) {
  224. return true;
  225. }
  226. checkAnimationFinished();
  227. }
  228. return false;
  229. }
  230. bool isThumbAnimation() const {
  231. if (_animation) {
  232. if (_animation->a_thumbOver.animating()) {
  233. return true;
  234. }
  235. checkAnimationFinished();
  236. }
  237. return false;
  238. }
  239. struct AnimationData {
  240. template <typename Callback>
  241. AnimationData(Callback &&radialCallback)
  242. : radial(std::forward<Callback>(radialCallback)) {
  243. }
  244. Ui::Animations::Simple a_thumbOver;
  245. Ui::RadialAnimation radial;
  246. };
  247. mutable std::unique_ptr<AnimationData> _animation;
  248. Ui::Text::String _title, _description;
  249. ClickHandlerPtr _cancel;
  250. // >= 0 will contain download / upload string, _statusSize = loaded bytes
  251. // < 0 will contain played string, _statusSize = -(seconds + 1) played
  252. // 0xFFFFFFF0LL will contain status for not yet downloaded file
  253. // 0xFFFFFFF1LL will contain status for already downloaded file
  254. // 0xFFFFFFF2LL will contain status for failed to download / upload file
  255. mutable int64 _statusSize = 0;
  256. mutable QString _statusText;
  257. // duration = -1 - no duration, duration = -2 - "GIF" duration
  258. void setStatusSize(
  259. int64 newSize,
  260. int64 fullSize,
  261. TimeId duration,
  262. TimeId realDuration) const;
  263. not_null<DocumentData*> _document;
  264. mutable std::shared_ptr<Data::DocumentMedia> _documentMedia;
  265. };
  266. class Contact : public ItemBase {
  267. public:
  268. Contact(not_null<Context*> context, std::shared_ptr<Result> result);
  269. void initDimensions() override;
  270. void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
  271. TextState getState(
  272. QPoint point,
  273. StateRequest request) const override;
  274. private:
  275. mutable QPixmap _thumb;
  276. Ui::Text::String _title, _description;
  277. void prepareThumbnail(int width, int height) const;
  278. };
  279. class Article : public ItemBase {
  280. public:
  281. Article(
  282. not_null<Context*> context,
  283. std::shared_ptr<Result> result,
  284. bool withThumb);
  285. void initDimensions() override;
  286. int resizeGetHeight(int width) override;
  287. void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
  288. TextState getState(
  289. QPoint point,
  290. StateRequest request) const override;
  291. private:
  292. ClickHandlerPtr _url, _link;
  293. bool _withThumb;
  294. mutable QPixmap _thumb;
  295. Ui::Text::String _title, _description;
  296. QString _thumbLetter, _urlText;
  297. int32 _urlWidth;
  298. void prepareThumbnail(int width, int height) const;
  299. };
  300. class Game : public ItemBase {
  301. public:
  302. Game(not_null<Context*> context, std::shared_ptr<Result> result);
  303. void setPosition(int32 position) override;
  304. void initDimensions() override;
  305. void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
  306. TextState getState(
  307. QPoint point,
  308. StateRequest request) const override;
  309. void unloadHeavyPart() override;
  310. private:
  311. void ensureDataMediaCreated(not_null<PhotoData*> photo) const;
  312. void ensureDataMediaCreated(not_null<DocumentData*> document) const;
  313. void countFrameSize();
  314. void prepareThumbnail(QSize size) const;
  315. void validateThumbnail(Image *image, QSize size, bool good) const;
  316. bool isRadialAnimation() const;
  317. void radialAnimationCallback(crl::time now) const;
  318. void clipCallback(Media::Clip::Notification notification);
  319. Media::Clip::ReaderPointer _gif;
  320. mutable std::shared_ptr<Data::PhotoMedia> _photoMedia;
  321. mutable std::shared_ptr<Data::DocumentMedia> _documentMedia;
  322. mutable QImage _thumb;
  323. mutable bool _thumbGood = false;
  324. mutable std::unique_ptr<Ui::RadialAnimation> _radial;
  325. Ui::Text::String _title, _description;
  326. QSize _frameSize;
  327. };
  328. } // namespace internal
  329. } // namespace Layout
  330. } // namespace InlineBots