emoji_list_widget.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  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 "chat_helpers/compose/compose_features.h"
  9. #include "chat_helpers/tabbed_selector.h"
  10. #include "ui/widgets/tooltip.h"
  11. #include "ui/round_rect.h"
  12. #include "base/timer.h"
  13. class StickerPremiumMark;
  14. namespace style {
  15. struct EmojiPan;
  16. } // namespace style
  17. namespace Core {
  18. struct RecentEmojiId;
  19. } // namespace Core
  20. namespace Data {
  21. class StickersSet;
  22. } // namespace Data
  23. namespace PowerSaving {
  24. enum Flag : uint32;
  25. } // namespace PowerSaving
  26. namespace tr {
  27. template <typename ...Tags>
  28. struct phrase;
  29. } // namespace tr
  30. namespace Ui {
  31. class RippleAnimation;
  32. class TabbedSearch;
  33. } // namespace Ui
  34. namespace Ui::Emoji {
  35. enum class Section;
  36. } // namespace Ui::Emoji
  37. namespace Ui::Text {
  38. class CustomEmoji;
  39. struct CustomEmojiPaintContext;
  40. } // namespace Ui::Text
  41. namespace Ui::CustomEmoji {
  42. class Loader;
  43. class Instance;
  44. struct RepaintRequest;
  45. } // namespace Ui::CustomEmoji
  46. namespace Window {
  47. class SessionController;
  48. } // namespace Window
  49. namespace ChatHelpers {
  50. inline constexpr auto kEmojiSectionCount = 8;
  51. struct StickerIcon;
  52. class EmojiColorPicker;
  53. class StickersListFooter;
  54. class GradientPremiumStar;
  55. class LocalStickersManager;
  56. enum class EmojiListMode {
  57. Full,
  58. TopicIcon,
  59. EmojiStatus,
  60. ChannelStatus,
  61. FullReactions,
  62. RecentReactions,
  63. UserpicBuilder,
  64. BackgroundEmoji,
  65. PeerTitle,
  66. MessageEffects,
  67. };
  68. [[nodiscard]] std::vector<EmojiStatusId> DocumentListToRecent(
  69. const std::vector<DocumentId> &documents);
  70. struct EmojiListDescriptor {
  71. std::shared_ptr<Show> show;
  72. EmojiListMode mode = EmojiListMode::Full;
  73. Fn<QColor()> customTextColor;
  74. Fn<bool()> paused;
  75. std::vector<EmojiStatusId> customRecentList;
  76. Fn<std::unique_ptr<Ui::Text::CustomEmoji>(
  77. DocumentId,
  78. Fn<void()>)> customRecentFactory;
  79. base::flat_set<DocumentId> freeEffects;
  80. const style::EmojiPan *st = nullptr;
  81. ComposeFeatures features;
  82. };
  83. class EmojiListWidget final
  84. : public TabbedSelector::Inner
  85. , public Ui::AbstractTooltipShower {
  86. public:
  87. using Mode = EmojiListMode;
  88. EmojiListWidget(
  89. QWidget *parent,
  90. not_null<Window::SessionController*> controller,
  91. PauseReason level,
  92. Mode mode);
  93. EmojiListWidget(QWidget *parent, EmojiListDescriptor &&descriptor);
  94. ~EmojiListWidget();
  95. using Section = Ui::Emoji::Section;
  96. void refreshRecent() override;
  97. void clearSelection() override;
  98. object_ptr<TabbedSelector::InnerFooter> createFooter() override;
  99. void afterShown() override;
  100. void beforeHiding() override;
  101. void showSet(uint64 setId);
  102. [[nodiscard]] uint64 currentSet(int yOffset) const;
  103. void setAllowWithoutPremium(bool allow);
  104. void showMegagroupSet(ChannelData *megagroup);
  105. // Ui::AbstractTooltipShower interface.
  106. QString tooltipText() const override;
  107. QPoint tooltipPos() const override;
  108. bool tooltipWindowActive() const override;
  109. void refreshEmoji();
  110. [[nodiscard]] rpl::producer<EmojiChosen> chosen() const;
  111. [[nodiscard]] rpl::producer<FileChosen> customChosen() const;
  112. [[nodiscard]] rpl::producer<> jumpedToPremium() const;
  113. [[nodiscard]] rpl::producer<> escapes() const;
  114. void provideRecent(const std::vector<EmojiStatusId> &customRecentList);
  115. void prepareExpanding();
  116. void paintExpanding(
  117. Painter &p,
  118. QRect clip,
  119. int finalBottom,
  120. float64 geometryProgress,
  121. float64 fullProgress,
  122. RectPart origin);
  123. base::unique_qptr<Ui::PopupMenu> fillContextMenu(
  124. const SendMenu::Details &details) override;
  125. [[nodiscard]] rpl::producer<std::vector<QString>> searchQueries() const;
  126. [[nodiscard]] rpl::producer<int> recentShownCount() const;
  127. protected:
  128. void visibleTopBottomUpdated(
  129. int visibleTop,
  130. int visibleBottom) override;
  131. void mousePressEvent(QMouseEvent *e) override;
  132. void mouseReleaseEvent(QMouseEvent *e) override;
  133. void mouseMoveEvent(QMouseEvent *e) override;
  134. void paintEvent(QPaintEvent *e) override;
  135. void leaveEventHook(QEvent *e) override;
  136. void leaveToChildEvent(QEvent *e, QWidget *child) override;
  137. void enterFromChildEvent(QEvent *e, QWidget *child) override;
  138. bool eventHook(QEvent *e) override;
  139. TabbedSelector::InnerFooter *getFooter() const override;
  140. void processHideFinished() override;
  141. void processPanelHideFinished() override;
  142. int countDesiredHeight(int newWidth) override;
  143. int defaultMinimalHeight() const override;
  144. private:
  145. struct SectionInfo {
  146. int section = 0;
  147. int count = 0;
  148. int top = 0;
  149. int rowsCount = 0;
  150. int rowsTop = 0;
  151. int rowsBottom = 0;
  152. bool premiumRequired = false;
  153. bool collapsed = false;
  154. };
  155. struct CustomOne {
  156. std::shared_ptr<Data::EmojiStatusCollectible> collectible;
  157. not_null<Ui::Text::CustomEmoji*> custom;
  158. not_null<DocumentData*> document;
  159. EmojiPtr emoji = nullptr;
  160. };
  161. struct CustomSet {
  162. uint64 id = 0;
  163. not_null<Data::StickersSet*> set;
  164. DocumentData *thumbnailDocument = nullptr;
  165. QString title;
  166. std::vector<CustomOne> list;
  167. mutable std::unique_ptr<Ui::RippleAnimation> ripple;
  168. bool painted = false;
  169. bool expanded = false;
  170. bool canRemove = false;
  171. bool premiumRequired = false;
  172. };
  173. struct CustomEmojiInstance;
  174. struct RightButton {
  175. QImage back;
  176. QImage backOver;
  177. QImage rippleMask;
  178. QString text;
  179. int textWidth = 0;
  180. };
  181. struct RecentOne;
  182. struct OverEmoji {
  183. int section = 0;
  184. int index = 0;
  185. inline bool operator==(OverEmoji other) const {
  186. return (section == other.section)
  187. && (index == other.index);
  188. }
  189. inline bool operator!=(OverEmoji other) const {
  190. return !(*this == other);
  191. }
  192. };
  193. struct OverSet {
  194. int section = 0;
  195. inline bool operator==(OverSet other) const {
  196. return (section == other.section);
  197. }
  198. inline bool operator!=(OverSet other) const {
  199. return !(*this == other);
  200. }
  201. };
  202. struct OverButton {
  203. int section = 0;
  204. inline bool operator==(OverButton other) const {
  205. return (section == other.section);
  206. }
  207. inline bool operator!=(OverButton other) const {
  208. return !(*this == other);
  209. }
  210. };
  211. using OverState = std::variant<
  212. v::null_t,
  213. OverEmoji,
  214. OverSet,
  215. OverButton>;
  216. struct ExpandingContext {
  217. float64 progress = 0.;
  218. int finalHeight = 0;
  219. bool expanding = false;
  220. };
  221. struct ResolvedCustom {
  222. DocumentData *document = nullptr;
  223. std::shared_ptr<Data::EmojiStatusCollectible> collectible;
  224. explicit operator bool() const {
  225. return document != nullptr;
  226. }
  227. };
  228. template <typename Callback>
  229. bool enumerateSections(Callback callback) const;
  230. [[nodiscard]] SectionInfo sectionInfo(int section) const;
  231. [[nodiscard]] SectionInfo sectionInfoByOffset(int yOffset) const;
  232. [[nodiscard]] int sectionsCount() const;
  233. void setSingleSize(QSize size);
  234. void setColorAllForceRippled(bool force);
  235. void showPicker();
  236. void pickerHidden();
  237. void colorChosen(EmojiChosen data);
  238. bool checkPickerHide();
  239. void refreshCustom();
  240. enum class GroupStickersPlace {
  241. Visible,
  242. Hidden,
  243. };
  244. void refreshEmojiStatusCollectibles();
  245. void refreshMegagroupStickers(
  246. Fn<void(uint64 setId, bool installed)> push,
  247. GroupStickersPlace place);
  248. void unloadNotSeenCustom(int visibleTop, int visibleBottom);
  249. void unloadAllCustom();
  250. void unloadCustomIn(const SectionInfo &info);
  251. void setupSearch();
  252. [[nodiscard]] std::vector<EmojiPtr> collectPlainSearchResults();
  253. void appendPremiumSearchResults();
  254. void ensureLoaded(int section);
  255. void updateSelected();
  256. void setSelected(OverState newSelected);
  257. void setPressed(OverState newPressed);
  258. void fillRecentMenu(
  259. not_null<Ui::PopupMenu*> menu,
  260. int section,
  261. int index);
  262. void fillEmojiStatusMenu(
  263. not_null<Ui::PopupMenu*> menu,
  264. int section,
  265. int index);
  266. [[nodiscard]] EmojiPtr lookupOverEmoji(const OverEmoji *over) const;
  267. [[nodiscard]] ResolvedCustom lookupCustomEmoji(
  268. const OverEmoji *over) const;
  269. [[nodiscard]] ResolvedCustom lookupCustomEmoji(
  270. int index,
  271. int section) const;
  272. [[nodiscard]] EmojiChosen lookupChosen(
  273. EmojiPtr emoji,
  274. not_null<const OverEmoji*> over);
  275. [[nodiscard]] FileChosen lookupChosen(
  276. ResolvedCustom custom,
  277. const OverEmoji *over,
  278. Api::SendOptions options = Api::SendOptions());
  279. void selectEmoji(EmojiChosen data);
  280. void selectCustom(FileChosen data);
  281. void paint(Painter &p, ExpandingContext context, QRect clip);
  282. void drawCollapsedBadge(QPainter &p, QPoint position, int count);
  283. void drawRecent(
  284. QPainter &p,
  285. const ExpandingContext &context,
  286. QPoint position,
  287. const RecentOne &recent);
  288. void drawEmoji(
  289. QPainter &p,
  290. const ExpandingContext &context,
  291. QPoint position,
  292. EmojiPtr emoji);
  293. void drawCustom(
  294. QPainter &p,
  295. const ExpandingContext &context,
  296. QPoint position,
  297. int set,
  298. int index);
  299. void validateEmojiPaintContext(const ExpandingContext &context);
  300. [[nodiscard]] bool hasColorButton(int index) const;
  301. [[nodiscard]] QRect colorButtonRect(int index) const;
  302. [[nodiscard]] QRect colorButtonRect(const SectionInfo &info) const;
  303. [[nodiscard]] bool hasRemoveButton(int index) const;
  304. [[nodiscard]] QRect removeButtonRect(int index) const;
  305. [[nodiscard]] QRect removeButtonRect(const SectionInfo &info) const;
  306. [[nodiscard]] bool hasAddButton(int index) const;
  307. [[nodiscard]] QRect addButtonRect(int index) const;
  308. [[nodiscard]] bool hasUnlockButton(int index) const;
  309. [[nodiscard]] QRect unlockButtonRect(int index) const;
  310. [[nodiscard]] bool hasButton(int index) const;
  311. [[nodiscard]] QRect buttonRect(int index) const;
  312. [[nodiscard]] QRect buttonRect(
  313. const SectionInfo &info,
  314. const RightButton &button) const;
  315. [[nodiscard]] const RightButton &rightButton(int index) const;
  316. [[nodiscard]] QRect emojiRect(int section, int index) const;
  317. [[nodiscard]] int emojiRight() const;
  318. [[nodiscard]] int emojiLeft() const;
  319. [[nodiscard]] uint64 sectionSetId(int section) const;
  320. [[nodiscard]] std::vector<StickerIcon> fillIcons();
  321. int paintButtonGetWidth(
  322. QPainter &p,
  323. const SectionInfo &info,
  324. bool selected,
  325. QRect clip) const;
  326. void paintEmptySearchResults(Painter &p);
  327. void displaySet(uint64 setId);
  328. void removeSet(uint64 setId);
  329. void removeMegagroupSet(bool locally);
  330. void initButton(RightButton &button, const QString &text, bool gradient);
  331. [[nodiscard]] std::unique_ptr<Ui::RippleAnimation> createButtonRipple(
  332. int section);
  333. [[nodiscard]] QPoint buttonRippleTopLeft(int section) const;
  334. [[nodiscard]] PowerSaving::Flag powerSavingFlag() const;
  335. void repaintCustom(uint64 setId);
  336. void fillRecent();
  337. void fillRecentFrom(const std::vector<EmojiStatusId> &list);
  338. [[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomEmoji(
  339. EmojiStatusId id,
  340. not_null<DocumentData*> document,
  341. uint64 setId);
  342. [[nodiscard]] Ui::Text::CustomEmoji *resolveCustomRecent(
  343. Core::RecentEmojiId customId);
  344. [[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomRecent(
  345. DocumentId documentId);
  346. [[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomRecent(
  347. EmojiStatusId id);
  348. [[nodiscard]] Fn<void()> repaintCallback(
  349. DocumentId documentId,
  350. uint64 setId);
  351. void showPreview();
  352. void applyNextSearchQuery();
  353. const std::shared_ptr<Show> _show;
  354. const ComposeFeatures _features;
  355. const bool _onlyUnicodeEmoji;
  356. Mode _mode = Mode::Full;
  357. std::unique_ptr<Ui::TabbedSearch> _search;
  358. MTP::Sender _api;
  359. const int _staticCount = 0;
  360. StickersListFooter *_footer = nullptr;
  361. std::unique_ptr<GradientPremiumStar> _premiumIcon;
  362. std::unique_ptr<LocalStickersManager> _localSetsManager;
  363. ChannelData *_megagroupSet = nullptr;
  364. uint64 _megagroupSetIdRequested = 0;
  365. Fn<std::unique_ptr<Ui::Text::CustomEmoji>(
  366. DocumentId,
  367. Fn<void()>)> _customRecentFactory;
  368. int _counts[kEmojiSectionCount];
  369. std::vector<RecentOne> _recent;
  370. base::flat_set<DocumentId> _recentCustomIds;
  371. base::flat_set<DocumentId> _freeEffects;
  372. base::flat_set<uint64> _repaintsScheduled;
  373. rpl::variable<int> _recentShownCount;
  374. std::unique_ptr<Ui::Text::CustomEmojiPaintContext> _emojiPaintContext;
  375. bool _recentPainted = false;
  376. bool _grabbingChosen = false;
  377. bool _paintAsPremium = false;
  378. QVector<EmojiPtr> _emoji[kEmojiSectionCount];
  379. std::vector<CustomSet> _custom;
  380. base::flat_set<DocumentId> _restrictedCustomList;
  381. base::flat_map<EmojiStatusId, CustomEmojiInstance> _customEmoji;
  382. base::flat_map<
  383. DocumentId,
  384. std::unique_ptr<Ui::Text::CustomEmoji>> _customRecent;
  385. Fn<QColor()> _customTextColor;
  386. int _customSingleSize = 0;
  387. bool _allowWithoutPremium = false;
  388. Ui::RoundRect _overBg;
  389. QImage _searchExpandCache;
  390. std::unique_ptr<StickerPremiumMark> _premiumMark;
  391. QImage _premiumMarkFrameCache;
  392. mutable std::unique_ptr<Ui::RippleAnimation> _colorAllRipple;
  393. bool _colorAllRippleForced = false;
  394. rpl::lifetime _colorAllRippleForcedLifetime;
  395. rpl::event_stream<std::vector<QString>> _searchQueries;
  396. std::vector<QString> _nextSearchQuery;
  397. std::vector<QString> _searchQuery;
  398. base::flat_set<EmojiPtr> _searchEmoji;
  399. base::flat_set<EmojiPtr> _searchEmojiPrevious;
  400. base::flat_set<DocumentId> _searchCustomIds;
  401. std::vector<RecentOne> _searchResults;
  402. bool _searchMode = false;
  403. int _rowsTop = 0;
  404. int _rowsLeft = 0;
  405. int _columnCount = 1;
  406. QSize _singleSize;
  407. QPoint _areaPosition;
  408. QPoint _innerPosition;
  409. QPoint _customPosition;
  410. RightButton _add;
  411. RightButton _unlock;
  412. RightButton _restore;
  413. Ui::RoundRect _collapsedBg;
  414. OverState _selected;
  415. OverState _pressed;
  416. OverState _pickerSelected;
  417. QPoint _lastMousePos;
  418. object_ptr<EmojiColorPicker> _picker;
  419. base::Timer _showPickerTimer;
  420. base::Timer _previewTimer;
  421. bool _previewShown = false;
  422. rpl::event_stream<EmojiChosen> _chosen;
  423. rpl::event_stream<FileChosen> _customChosen;
  424. rpl::event_stream<> _jumpedToPremium;
  425. };
  426. tr::phrase<> EmojiCategoryTitle(int index);
  427. } // namespace ChatHelpers