history_unread_things.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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 "history/history_unread_things.h"
  8. #include "data/data_session.h"
  9. #include "data/data_changes.h"
  10. #include "data/data_channel.h"
  11. #include "data/data_forum_topic.h"
  12. #include "data/data_chat_filters.h"
  13. #include "history/history.h"
  14. #include "history/history_item.h"
  15. #include "main/main_session.h"
  16. #include "apiwrap.h"
  17. namespace HistoryUnreadThings {
  18. namespace {
  19. template <typename Update>
  20. [[nodiscard]] typename Update::Flag UpdateFlag(Type type) {
  21. using Flag = typename Update::Flag;
  22. switch (type) {
  23. case Type::Mentions: return Flag::UnreadMentions;
  24. case Type::Reactions: return Flag::UnreadReactions;
  25. }
  26. Unexpected("Type in HistoryUnreadThings::UpdateFlag.");
  27. }
  28. [[nodiscard]] Data::HistoryUpdate::Flag HistoryUpdateFlag(Type type) {
  29. return UpdateFlag<Data::HistoryUpdate>(type);
  30. }
  31. [[nodiscard]] Data::TopicUpdate::Flag TopicUpdateFlag(Type type) {
  32. return UpdateFlag<Data::TopicUpdate>(type);
  33. }
  34. } // namespace
  35. void Proxy::setCount(int count) {
  36. if (!_known) {
  37. _thread->setUnreadThingsKnown();
  38. }
  39. if (!_data) {
  40. if (!count) {
  41. return;
  42. }
  43. createData();
  44. }
  45. auto &list = resolveList();
  46. const auto loaded = list.loadedCount();
  47. if (loaded > count) {
  48. LOG(("API Warning: "
  49. "real count is greater than received unread count"));
  50. count = loaded;
  51. }
  52. const auto had = (list.count() > 0);
  53. const auto &other = (_type == Type::Mentions)
  54. ? _data->reactions
  55. : _data->mentions;
  56. if (!count && other.count(-1) == 0) {
  57. _data = nullptr;
  58. } else {
  59. list.setCount(count);
  60. }
  61. const auto has = (count > 0);
  62. if (has != had && _thread->inChatList()) {
  63. if (_type == Type::Mentions) {
  64. _thread->hasUnreadMentionChanged(has);
  65. } else if (_type == Type::Reactions) {
  66. _thread->hasUnreadReactionChanged(has);
  67. }
  68. }
  69. }
  70. bool Proxy::add(MsgId msgId, AddType type) {
  71. if (const auto history = _thread->asHistory()) {
  72. if (history->peer->isBroadcast()) {
  73. return false;
  74. }
  75. }
  76. if (!_data) {
  77. createData();
  78. }
  79. auto &list = resolveList();
  80. const auto count = list.count();
  81. const auto loaded = list.loadedCount();
  82. const auto allLoaded = (count >= 0) && (loaded >= count);
  83. if (allLoaded) {
  84. if (type == AddType::New || !list.contains(msgId)) {
  85. list.insert(msgId);
  86. setCount(count + 1);
  87. return true;
  88. }
  89. } else if (loaded > 0 && type != AddType::New) {
  90. list.insert(msgId);
  91. return true;
  92. }
  93. return false;
  94. }
  95. void Proxy::erase(MsgId msgId) {
  96. if (!_data) {
  97. return;
  98. }
  99. auto &list = resolveList();
  100. list.erase(msgId);
  101. if (const auto count = list.count(); count > 0) {
  102. setCount(count - 1);
  103. }
  104. notifyUpdated();
  105. }
  106. void Proxy::clear() {
  107. if (!_data || !count()) {
  108. return;
  109. }
  110. auto &list = resolveList();
  111. list.clear();
  112. setCount(0);
  113. notifyUpdated();
  114. }
  115. void Proxy::addSlice(const MTPmessages_Messages &slice, int alreadyLoaded) {
  116. if (!alreadyLoaded && _data) {
  117. resolveList().clear();
  118. }
  119. const auto history = _thread->owningHistory();
  120. auto fullCount = slice.match([&](
  121. const MTPDmessages_messagesNotModified &) {
  122. LOG(("API Error: received messages.messagesNotModified! "
  123. "(Proxy::addSlice)"));
  124. return 0;
  125. }, [&](const MTPDmessages_messages &data) {
  126. return int(data.vmessages().v.size());
  127. }, [&](const MTPDmessages_messagesSlice &data) {
  128. return data.vcount().v;
  129. }, [&](const MTPDmessages_channelMessages &data) {
  130. if (const auto channel = history->peer->asChannel()) {
  131. channel->ptsReceived(data.vpts().v);
  132. channel->processTopics(data.vtopics());
  133. } else {
  134. LOG(("API Error: received messages.channelMessages when "
  135. "no channel was passed! (Proxy::addSlice)"));
  136. }
  137. return data.vcount().v;
  138. });
  139. auto &owner = _thread->owner();
  140. const auto messages = slice.match([&](
  141. const MTPDmessages_messagesNotModified &) {
  142. LOG(("API Error: received messages.messagesNotModified! "
  143. "(Proxy::addSlice)"));
  144. return QVector<MTPMessage>();
  145. }, [&](const auto &data) {
  146. owner.processUsers(data.vusers());
  147. owner.processChats(data.vchats());
  148. return data.vmessages().v;
  149. });
  150. if (!messages.isEmpty() && !_data) {
  151. createData();
  152. }
  153. auto added = false;
  154. const auto list = _data ? &resolveList() : nullptr;
  155. const auto localFlags = MessageFlags();
  156. const auto type = NewMessageType::Existing;
  157. for (const auto &message : messages) {
  158. const auto item = history->addNewMessage(
  159. IdFromMessage(message),
  160. message,
  161. localFlags,
  162. type);
  163. const auto is = [&] {
  164. switch (_type) {
  165. case Type::Mentions: return item->isUnreadMention();
  166. case Type::Reactions: return item->hasUnreadReaction();
  167. }
  168. Unexpected("Type in Proxy::addSlice.");
  169. }();
  170. if (is) {
  171. list->insert(item->id);
  172. added = true;
  173. }
  174. }
  175. if (!added) {
  176. fullCount = loadedCount();
  177. }
  178. setCount(fullCount);
  179. notifyUpdated();
  180. }
  181. void Proxy::checkAdd(MsgId msgId, bool resolved) {
  182. Expects(_type == Type::Reactions);
  183. if (!_data) {
  184. return;
  185. }
  186. auto &list = resolveList();
  187. if (!list.loadedCount() || list.maxLoaded() <= msgId) {
  188. return;
  189. }
  190. const auto history = _thread->owningHistory();
  191. const auto peer = history->peer;
  192. const auto item = peer->owner().message(peer, msgId);
  193. if (item && item->hasUnreadReaction()) {
  194. item->addToUnreadThings(AddType::Existing);
  195. } else if (!item && !resolved) {
  196. peer->session().api().requestMessageData(peer, msgId, [=] {
  197. history->unreadReactions().checkAdd(msgId, true);
  198. });
  199. }
  200. }
  201. void Proxy::notifyUpdated() {
  202. if (const auto history = _thread->asHistory()) {
  203. history->session().changes().historyUpdated(
  204. history,
  205. HistoryUpdateFlag(_type));
  206. } else if (const auto topic = _thread->asTopic()) {
  207. topic->session().changes().topicUpdated(
  208. topic,
  209. TopicUpdateFlag(_type));
  210. }
  211. }
  212. void Proxy::createData() {
  213. _data = std::make_unique<All>();
  214. if (_known) {
  215. _data->mentions.setCount(0);
  216. _data->reactions.setCount(0);
  217. }
  218. }
  219. List &Proxy::resolveList() {
  220. Expects(_data != nullptr);
  221. switch (_type) {
  222. case Type::Mentions: return _data->mentions;
  223. case Type::Reactions: return _data->reactions;
  224. }
  225. Unexpected("Unread things type in Proxy::resolveList.");
  226. }
  227. } // namespace HistoryUnreadThings