data_drafts.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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 "data/data_msg_id.h"
  9. namespace Ui {
  10. class InputField;
  11. } // namespace Ui
  12. namespace Main {
  13. class Session;
  14. } // namespace Main
  15. namespace Data {
  16. void ApplyPeerCloudDraft(
  17. not_null<Main::Session*> session,
  18. PeerId peerId,
  19. MsgId topicRootId,
  20. const MTPDdraftMessage &draft);
  21. void ClearPeerCloudDraft(
  22. not_null<Main::Session*> session,
  23. PeerId peerId,
  24. MsgId topicRootId,
  25. TimeId date);
  26. struct WebPageDraft {
  27. [[nodiscard]] static WebPageDraft FromItem(not_null<HistoryItem*> item);
  28. WebPageId id = 0;
  29. QString url;
  30. bool forceLargeMedia : 1 = false;
  31. bool forceSmallMedia : 1 = false;
  32. bool invert : 1 = false;
  33. bool manual : 1 = false;
  34. bool removed : 1 = false;
  35. friend inline bool operator==(const WebPageDraft&, const WebPageDraft&)
  36. = default;
  37. };
  38. struct Draft {
  39. Draft() = default;
  40. Draft(
  41. const TextWithTags &textWithTags,
  42. FullReplyTo reply,
  43. const MessageCursor &cursor,
  44. WebPageDraft webpage,
  45. mtpRequestId saveRequestId = 0);
  46. Draft(
  47. not_null<const Ui::InputField*> field,
  48. FullReplyTo reply,
  49. WebPageDraft webpage,
  50. mtpRequestId saveRequestId = 0);
  51. TimeId date = 0;
  52. TextWithTags textWithTags;
  53. FullReplyTo reply; // reply.messageId.msg is editMsgId for edit draft.
  54. MessageCursor cursor;
  55. WebPageDraft webpage;
  56. mtpRequestId saveRequestId = 0;
  57. };
  58. class DraftKey {
  59. public:
  60. [[nodiscard]] static constexpr DraftKey None() {
  61. return 0;
  62. }
  63. [[nodiscard]] static constexpr DraftKey Local(MsgId topicRootId) {
  64. return (topicRootId < 0 || topicRootId >= ServerMaxMsgId)
  65. ? None()
  66. : (topicRootId ? topicRootId.bare : kLocalDraftIndex);
  67. }
  68. [[nodiscard]] static constexpr DraftKey LocalEdit(MsgId topicRootId) {
  69. return (topicRootId < 0 || topicRootId >= ServerMaxMsgId)
  70. ? None()
  71. : ((topicRootId ? topicRootId.bare : kLocalDraftIndex)
  72. + kEditDraftShift);
  73. }
  74. [[nodiscard]] static constexpr DraftKey Cloud(MsgId topicRootId) {
  75. return (topicRootId < 0 || topicRootId >= ServerMaxMsgId)
  76. ? None()
  77. : topicRootId
  78. ? (kCloudDraftShift + topicRootId.bare)
  79. : kCloudDraftIndex;
  80. }
  81. [[nodiscard]] static constexpr DraftKey Scheduled() {
  82. return kScheduledDraftIndex;
  83. }
  84. [[nodiscard]] static constexpr DraftKey ScheduledEdit() {
  85. return kScheduledDraftIndex + kEditDraftShift;
  86. }
  87. [[nodiscard]] static constexpr DraftKey Shortcut(
  88. BusinessShortcutId shortcutId) {
  89. return (shortcutId < 0 || shortcutId >= ServerMaxMsgId)
  90. ? None()
  91. : (kShortcutDraftShift + shortcutId);
  92. }
  93. [[nodiscard]] static constexpr DraftKey ShortcutEdit(
  94. BusinessShortcutId shortcutId) {
  95. return (shortcutId < 0 || shortcutId >= ServerMaxMsgId)
  96. ? None()
  97. : (kShortcutDraftShift + kEditDraftShift + shortcutId);
  98. }
  99. [[nodiscard]] static constexpr DraftKey FromSerialized(qint64 value) {
  100. return value;
  101. }
  102. [[nodiscard]] constexpr qint64 serialize() const {
  103. return _value;
  104. }
  105. [[nodiscard]] static constexpr DraftKey FromSerializedOld(int32 value) {
  106. return !value
  107. ? None()
  108. : (value == kLocalDraftIndex + kEditDraftShiftOld)
  109. ? LocalEdit(0)
  110. : (value == kScheduledDraftIndex + kEditDraftShiftOld)
  111. ? ScheduledEdit()
  112. : (value > 0 && value < 0x4000'0000)
  113. ? Local(MsgId(value))
  114. : (value > kEditDraftShiftOld
  115. && value < kEditDraftShiftOld + 0x4000'000)
  116. ? LocalEdit(int64(value - kEditDraftShiftOld))
  117. : None();
  118. }
  119. [[nodiscard]] constexpr bool isLocal() const {
  120. return (_value == kLocalDraftIndex)
  121. || (_value > 0 && _value < ServerMaxMsgId.bare);
  122. }
  123. [[nodiscard]] constexpr bool isCloud() const {
  124. return (_value == kCloudDraftIndex)
  125. || (_value > kCloudDraftShift
  126. && _value < kCloudDraftShift + ServerMaxMsgId.bare);
  127. }
  128. [[nodiscard]] constexpr MsgId topicRootId() const {
  129. const auto max = ServerMaxMsgId.bare;
  130. if (_value > kCloudDraftShift && _value < kCloudDraftShift + max) {
  131. return (_value - kCloudDraftShift);
  132. } else if (_value > kEditDraftShift && _value < kEditDraftShift + max) {
  133. return (_value - kEditDraftShift);
  134. } else if (_value > 0 && _value < max) {
  135. return _value;
  136. }
  137. return 0;
  138. }
  139. friend inline constexpr auto operator<=>(DraftKey, DraftKey) = default;
  140. inline explicit operator bool() const {
  141. return _value != 0;
  142. }
  143. private:
  144. constexpr DraftKey(int64 value) : _value(value) {
  145. }
  146. static constexpr auto kLocalDraftIndex = -1;
  147. static constexpr auto kCloudDraftIndex = -2;
  148. static constexpr auto kScheduledDraftIndex = -3;
  149. static constexpr auto kEditDraftShift = ServerMaxMsgId.bare;
  150. static constexpr auto kCloudDraftShift = 2 * ServerMaxMsgId.bare;
  151. static constexpr auto kShortcutDraftShift = 3 * ServerMaxMsgId.bare;
  152. static constexpr auto kEditDraftShiftOld = 0x3FFF'FFFF;
  153. int64 _value = 0;
  154. };
  155. using HistoryDrafts = base::flat_map<DraftKey, std::unique_ptr<Draft>>;
  156. [[nodiscard]] inline bool DraftStringIsEmpty(const QString &text) {
  157. for (const auto &ch : text) {
  158. if (!ch.isSpace()) {
  159. return false;
  160. }
  161. }
  162. return true;
  163. }
  164. [[nodiscard]] inline bool DraftIsNull(const Draft *draft) {
  165. return !draft
  166. || (!draft->reply.messageId
  167. && DraftStringIsEmpty(draft->textWithTags.text));
  168. }
  169. [[nodiscard]] inline bool DraftsAreEqual(const Draft *a, const Draft *b) {
  170. const auto aIsNull = DraftIsNull(a);
  171. const auto bIsNull = DraftIsNull(b);
  172. if (aIsNull) {
  173. return bIsNull;
  174. } else if (bIsNull) {
  175. return false;
  176. }
  177. return (a->textWithTags == b->textWithTags)
  178. && (a->reply == b->reply)
  179. && (a->webpage == b->webpage);
  180. }
  181. void SetChatLinkDraft(not_null<PeerData*> peer, TextWithEntities draft);
  182. } // namespace Data