data_stories_ids.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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_stories_ids.h"
  8. #include "data/data_changes.h"
  9. #include "data/data_peer.h"
  10. #include "data/data_session.h"
  11. #include "data/data_stories.h"
  12. #include "main/main_session.h"
  13. #include "ui/ui_utility.h"
  14. namespace Data {
  15. rpl::producer<StoriesIdsSlice> SavedStoriesIds(
  16. not_null<PeerData*> peer,
  17. StoryId aroundId,
  18. int limit) {
  19. return [=](auto consumer) {
  20. auto lifetime = rpl::lifetime();
  21. struct State {
  22. StoriesIdsSlice slice;
  23. base::has_weak_ptr guard;
  24. bool scheduled = false;
  25. };
  26. const auto state = lifetime.make_state<State>();
  27. const auto push = [=] {
  28. state->scheduled = false;
  29. const auto peerId = peer->id;
  30. const auto stories = &peer->owner().stories();
  31. if (!stories->savedCountKnown(peerId)) {
  32. return;
  33. }
  34. const auto &saved = stories->saved(peerId);
  35. const auto sorted = RespectingPinned(saved);
  36. const auto count = stories->savedCount(peerId);
  37. auto i = ranges::find(sorted, aroundId);
  38. if (i == end(sorted)) {
  39. const auto j = saved.list.lower_bound(aroundId);
  40. i = begin(sorted) + int(j - begin(saved.list));
  41. }
  42. const auto hasBefore = int(i - begin(sorted));
  43. const auto hasAfter = int(end(sorted) - i);
  44. if (hasAfter < limit) {
  45. stories->savedLoadMore(peerId);
  46. }
  47. const auto takeBefore = std::min(hasBefore, limit);
  48. const auto takeAfter = std::min(hasAfter, limit);
  49. auto ids = std::vector<StoryId>();
  50. ids.reserve(takeBefore + takeAfter);
  51. for (auto j = i - takeBefore; j != i + takeAfter; ++j) {
  52. ids.push_back(*j);
  53. }
  54. const auto added = int(ids.size());
  55. state->slice = StoriesIdsSlice(
  56. std::move(ids),
  57. count,
  58. (hasBefore - takeBefore),
  59. count - hasBefore - added);
  60. consumer.put_next_copy(state->slice);
  61. };
  62. const auto schedule = [=] {
  63. if (state->scheduled) {
  64. return;
  65. }
  66. state->scheduled = true;
  67. Ui::PostponeCall(&state->guard, [=] {
  68. if (state->scheduled) {
  69. push();
  70. }
  71. });
  72. };
  73. const auto peerId = peer->id;
  74. const auto stories = &peer->owner().stories();
  75. stories->savedChanged(
  76. ) | rpl::filter(
  77. rpl::mappers::_1 == peerId
  78. ) | rpl::start_with_next(schedule, lifetime);
  79. if (!stories->savedCountKnown(peerId)) {
  80. stories->savedLoadMore(peerId);
  81. }
  82. push();
  83. return lifetime;
  84. };
  85. }
  86. rpl::producer<StoriesIdsSlice> ArchiveStoriesIds(
  87. not_null<PeerData*> peer,
  88. StoryId aroundId,
  89. int limit) {
  90. return [=](auto consumer) {
  91. auto lifetime = rpl::lifetime();
  92. struct State {
  93. StoriesIdsSlice slice;
  94. base::has_weak_ptr guard;
  95. bool scheduled = false;
  96. };
  97. const auto state = lifetime.make_state<State>();
  98. const auto push = [=] {
  99. state->scheduled = false;
  100. const auto peerId = peer->id;
  101. const auto stories = &peer->owner().stories();
  102. if (!stories->archiveCountKnown(peerId)) {
  103. return;
  104. }
  105. const auto &archive = stories->archive(peerId);
  106. const auto sorted = RespectingPinned(archive);
  107. const auto count = stories->savedCount(peerId);
  108. auto i = ranges::find(sorted, aroundId);
  109. if (i == end(sorted)) {
  110. const auto j = archive.list.lower_bound(aroundId);
  111. i = begin(sorted) + int(j - begin(archive.list));
  112. }
  113. const auto hasBefore = int(i - begin(sorted));
  114. const auto hasAfter = int(end(sorted) - i);
  115. if (hasAfter < limit) {
  116. stories->archiveLoadMore(peerId);
  117. }
  118. const auto takeBefore = std::min(hasBefore, limit);
  119. const auto takeAfter = std::min(hasAfter, limit);
  120. auto ids = std::vector<StoryId>();
  121. ids.reserve(takeBefore + takeAfter);
  122. for (auto j = i - takeBefore; j != i + takeAfter; ++j) {
  123. ids.push_back(*j);
  124. }
  125. const auto added = int(ids.size());
  126. state->slice = StoriesIdsSlice(
  127. std::move(ids),
  128. count,
  129. (hasBefore - takeBefore),
  130. count - hasBefore - added);
  131. consumer.put_next_copy(state->slice);
  132. };
  133. const auto schedule = [=] {
  134. if (state->scheduled) {
  135. return;
  136. }
  137. state->scheduled = true;
  138. Ui::PostponeCall(&state->guard, [=] {
  139. if (state->scheduled) {
  140. push();
  141. }
  142. });
  143. };
  144. const auto peerId = peer->id;
  145. const auto stories = &peer->owner().stories();
  146. stories->archiveChanged(
  147. ) | rpl::start_with_next(schedule, lifetime);
  148. if (!stories->archiveCountKnown(peerId)) {
  149. stories->archiveLoadMore(peerId);
  150. }
  151. push();
  152. return lifetime;
  153. };
  154. }
  155. } // namespace Data