data_drafts.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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 "data/data_drafts.h"
  8. #include "api/api_text_entities.h"
  9. #include "ui/widgets/fields/input_field.h"
  10. #include "chat_helpers/message_field.h"
  11. #include "history/history.h"
  12. #include "history/history_widget.h"
  13. #include "history/history_item_components.h"
  14. #include "main/main_session.h"
  15. #include "data/data_changes.h"
  16. #include "data/data_session.h"
  17. #include "data/data_web_page.h"
  18. #include "mainwidget.h"
  19. #include "storage/localstorage.h"
  20. namespace Data {
  21. WebPageDraft WebPageDraft::FromItem(not_null<HistoryItem*> item) {
  22. const auto previewMedia = item->media();
  23. const auto previewPage = previewMedia
  24. ? previewMedia->webpage()
  25. : nullptr;
  26. using PageFlag = MediaWebPageFlag;
  27. const auto previewFlags = previewMedia
  28. ? previewMedia->webpageFlags()
  29. : PageFlag();
  30. return {
  31. .id = previewPage ? previewPage->id : 0,
  32. .url = previewPage ? previewPage->url : QString(),
  33. .forceLargeMedia = !!(previewFlags & PageFlag::ForceLargeMedia),
  34. .forceSmallMedia = !!(previewFlags & PageFlag::ForceSmallMedia),
  35. .invert = item->invertMedia(),
  36. .manual = !!(previewFlags & PageFlag::Manual),
  37. .removed = !previewPage,
  38. };
  39. }
  40. Draft::Draft(
  41. const TextWithTags &textWithTags,
  42. FullReplyTo reply,
  43. const MessageCursor &cursor,
  44. WebPageDraft webpage,
  45. mtpRequestId saveRequestId)
  46. : textWithTags(textWithTags)
  47. , reply(std::move(reply))
  48. , cursor(cursor)
  49. , webpage(webpage)
  50. , saveRequestId(saveRequestId) {
  51. }
  52. Draft::Draft(
  53. not_null<const Ui::InputField*> field,
  54. FullReplyTo reply,
  55. WebPageDraft webpage,
  56. mtpRequestId saveRequestId)
  57. : textWithTags(field->getTextWithTags())
  58. , reply(std::move(reply))
  59. , cursor(field)
  60. , webpage(webpage) {
  61. }
  62. void ApplyPeerCloudDraft(
  63. not_null<Main::Session*> session,
  64. PeerId peerId,
  65. MsgId topicRootId,
  66. const MTPDdraftMessage &draft) {
  67. const auto history = session->data().history(peerId);
  68. const auto date = draft.vdate().v;
  69. if (history->skipCloudDraftUpdate(topicRootId, date)) {
  70. return;
  71. }
  72. const auto textWithTags = TextWithTags{
  73. qs(draft.vmessage()),
  74. TextUtilities::ConvertEntitiesToTextTags(
  75. Api::EntitiesFromMTP(
  76. session,
  77. draft.ventities().value_or_empty()))
  78. };
  79. auto replyTo = draft.vreply_to()
  80. ? ReplyToFromMTP(history, *draft.vreply_to())
  81. : FullReplyTo();
  82. replyTo.topicRootId = topicRootId;
  83. auto webpage = WebPageDraft{
  84. .invert = draft.is_invert_media(),
  85. .removed = draft.is_no_webpage(),
  86. };
  87. if (const auto media = draft.vmedia()) {
  88. media->match([&](const MTPDmessageMediaWebPage &data) {
  89. const auto parsed = session->data().processWebpage(
  90. data.vwebpage());
  91. if (!parsed->failed) {
  92. webpage.forceLargeMedia = data.is_force_large_media();
  93. webpage.forceSmallMedia = data.is_force_small_media();
  94. webpage.manual = data.is_manual();
  95. webpage.url = parsed->url;
  96. webpage.id = parsed->id;
  97. }
  98. }, [](const auto &) {});
  99. }
  100. auto cloudDraft = std::make_unique<Draft>(
  101. textWithTags,
  102. replyTo,
  103. MessageCursor(Ui::kQFixedMax, Ui::kQFixedMax, Ui::kQFixedMax),
  104. std::move(webpage));
  105. cloudDraft->date = date;
  106. history->setCloudDraft(std::move(cloudDraft));
  107. history->applyCloudDraft(topicRootId);
  108. }
  109. void ClearPeerCloudDraft(
  110. not_null<Main::Session*> session,
  111. PeerId peerId,
  112. MsgId topicRootId,
  113. TimeId date) {
  114. const auto history = session->data().history(peerId);
  115. if (history->skipCloudDraftUpdate(topicRootId, date)) {
  116. return;
  117. }
  118. history->clearCloudDraft(topicRootId);
  119. history->applyCloudDraft(topicRootId);
  120. }
  121. void SetChatLinkDraft(not_null<PeerData*> peer, TextWithEntities draft) {
  122. static const auto kInlineStart = QRegularExpression("^@[a-zA-Z0-9_]");
  123. if (kInlineStart.match(draft.text).hasMatch()) {
  124. draft = TextWithEntities().append(' ').append(std::move(draft));
  125. }
  126. const auto textWithTags = TextWithTags{
  127. draft.text,
  128. TextUtilities::ConvertEntitiesToTextTags(draft.entities)
  129. };
  130. const auto cursor = MessageCursor{
  131. int(textWithTags.text.size()),
  132. int(textWithTags.text.size()),
  133. Ui::kQFixedMax
  134. };
  135. const auto history = peer->owner().history(peer->id);
  136. const auto topicRootId = MsgId();
  137. history->setLocalDraft(std::make_unique<Data::Draft>(
  138. textWithTags,
  139. FullReplyTo{ .topicRootId = topicRootId },
  140. cursor,
  141. Data::WebPageDraft()));
  142. history->clearLocalEditDraft(topicRootId);
  143. history->session().changes().entryUpdated(
  144. history,
  145. Data::EntryUpdate::Flag::LocalDraftSet);
  146. }
  147. } // namespace Data