| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #pragma once
- #include "base/qt/qt_compare.h"
- #include "base/expected.h"
- #include "base/timer.h"
- #include "base/weak_ptr.h"
- #include "data/data_story.h"
- namespace Main {
- class Session;
- } // namespace Main
- namespace Ui {
- class Show;
- } // namespace Ui
- namespace Data {
- class Folder;
- class Session;
- struct StoryView;
- struct StoryIdDates;
- class Story;
- class StoryPreload;
- struct StoriesIds {
- base::flat_set<StoryId, std::greater<>> list;
- std::vector<StoryId> pinnedToTop;
- friend inline bool operator==(
- const StoriesIds&,
- const StoriesIds&) = default;
- };
- [[nodiscard]] std::vector<StoryId> RespectingPinned(const StoriesIds &ids);
- struct StoriesSourceInfo {
- PeerId id = 0;
- TimeId last = 0;
- uint32 count : 15 = 0;
- uint32 unreadCount : 15 = 0;
- uint32 premium : 1 = 0;
- friend inline bool operator==(
- StoriesSourceInfo,
- StoriesSourceInfo) = default;
- };
- struct StoriesSource {
- not_null<PeerData*> peer;
- base::flat_set<StoryIdDates> ids;
- StoryId readTill = 0;
- bool hidden = false;
- [[nodiscard]] StoriesSourceInfo info() const;
- [[nodiscard]] int unreadCount() const;
- [[nodiscard]] StoryIdDates toOpen() const;
- friend inline bool operator==(StoriesSource, StoriesSource) = default;
- };
- enum class NoStory : uchar {
- Unknown,
- Deleted,
- };
- enum class StorySourcesList : uchar {
- NotHidden,
- Hidden,
- };
- struct StoriesContextSingle {
- friend inline auto operator<=>(
- StoriesContextSingle,
- StoriesContextSingle) = default;
- friend inline bool operator==(StoriesContextSingle, StoriesContextSingle) = default;
- };
- struct StoriesContextPeer {
- friend inline auto operator<=>(
- StoriesContextPeer,
- StoriesContextPeer) = default;
- friend inline bool operator==(StoriesContextPeer, StoriesContextPeer) = default;
- };
- struct StoriesContextSaved {
- friend inline auto operator<=>(
- StoriesContextSaved,
- StoriesContextSaved) = default;
- friend inline bool operator==(StoriesContextSaved, StoriesContextSaved) = default;
- };
- struct StoriesContextArchive {
- friend inline auto operator<=>(
- StoriesContextArchive,
- StoriesContextArchive) = default;
- friend inline bool operator==(StoriesContextArchive, StoriesContextArchive) = default;
- };
- struct StoriesContext {
- std::variant<
- StoriesContextSingle,
- StoriesContextPeer,
- StoriesContextSaved,
- StoriesContextArchive,
- StorySourcesList> data;
- friend inline auto operator<=>(
- StoriesContext,
- StoriesContext) = default;
- friend inline bool operator==(StoriesContext, StoriesContext) = default;
- };
- struct StealthMode {
- TimeId enabledTill = 0;
- TimeId cooldownTill = 0;
- friend inline auto operator<=>(StealthMode, StealthMode) = default;
- friend inline bool operator==(StealthMode, StealthMode) = default;
- };
- inline constexpr auto kStorySourcesListCount = 2;
- class Stories final : public base::has_weak_ptr {
- public:
- explicit Stories(not_null<Session*> owner);
- ~Stories();
- static constexpr auto kInProfileToastDuration = 4 * crl::time(1000);
- [[nodiscard]] Session &owner() const;
- [[nodiscard]] Main::Session &session() const;
- void updateDependentMessages(not_null<Data::Story*> story);
- void registerDependentMessage(
- not_null<HistoryItem*> dependent,
- not_null<Data::Story*> dependency);
- void unregisterDependentMessage(
- not_null<HistoryItem*> dependent,
- not_null<Data::Story*> dependency);
- void loadMore(StorySourcesList list);
- void apply(const MTPDupdateStory &data);
- void apply(const MTPDupdateReadStories &data);
- void apply(const MTPStoriesStealthMode &stealthMode);
- void apply(not_null<PeerData*> peer, const MTPPeerStories *data);
- Story *applySingle(PeerId peerId, const MTPstoryItem &story);
- void loadAround(FullStoryId id, StoriesContext context);
- const StoriesSource *source(PeerId id) const;
- [[nodiscard]] const std::vector<StoriesSourceInfo> &sources(
- StorySourcesList list) const;
- [[nodiscard]] bool sourcesLoaded(StorySourcesList list) const;
- [[nodiscard]] rpl::producer<> sourcesChanged(
- StorySourcesList list) const;
- [[nodiscard]] rpl::producer<PeerId> sourceChanged() const;
- [[nodiscard]] rpl::producer<PeerId> itemsChanged() const;
- [[nodiscard]] base::expected<not_null<Story*>, NoStory> lookup(
- FullStoryId id) const;
- void resolve(FullStoryId id, Fn<void()> done, bool force = false);
- [[nodiscard]] std::shared_ptr<HistoryItem> resolveItem(FullStoryId id);
- [[nodiscard]] std::shared_ptr<HistoryItem> resolveItem(
- not_null<Story*> story);
- [[nodiscard]] bool isQuitPrevent();
- void markAsRead(FullStoryId id, bool viewed);
- void toggleHidden(
- PeerId peerId,
- bool hidden,
- std::shared_ptr<Ui::Show> show);
- static constexpr auto kViewsPerPage = 50;
- void loadViewsSlice(
- not_null<PeerData*> peer,
- StoryId id,
- QString offset,
- Fn<void(StoryViews)> done);
- void loadReactionsSlice(
- not_null<PeerData*> peer,
- StoryId id,
- QString offset,
- Fn<void(StoryViews)> done);
- [[nodiscard]] bool hasArchive(not_null<PeerData*> peer) const;
- [[nodiscard]] const StoriesIds &archive(PeerId peerId) const;
- [[nodiscard]] rpl::producer<PeerId> archiveChanged() const;
- [[nodiscard]] int archiveCount(PeerId peerId) const;
- [[nodiscard]] bool archiveCountKnown(PeerId peerId) const;
- [[nodiscard]] bool archiveLoaded(PeerId peerId) const;
- void archiveLoadMore(PeerId peerId);
- [[nodiscard]] const StoriesIds &saved(PeerId peerId) const;
- [[nodiscard]] rpl::producer<PeerId> savedChanged() const;
- [[nodiscard]] int savedCount(PeerId peerId) const;
- [[nodiscard]] bool savedCountKnown(PeerId peerId) const;
- [[nodiscard]] bool savedLoaded(PeerId peerId) const;
- void savedLoadMore(PeerId peerId);
- void deleteList(const std::vector<FullStoryId> &ids);
- void toggleInProfileList(
- const std::vector<FullStoryId> &ids,
- bool inProfile);
- [[nodiscard]] bool canTogglePinnedList(
- const std::vector<FullStoryId> &ids,
- bool pin) const;
- [[nodiscard]] int maxPinnedCount() const;
- void togglePinnedList(const std::vector<FullStoryId> &ids, bool pin);
- void incrementPreloadingMainSources();
- void decrementPreloadingMainSources();
- void incrementPreloadingHiddenSources();
- void decrementPreloadingHiddenSources();
- void setPreloadingInViewer(std::vector<FullStoryId> ids);
- struct PeerSourceState {
- StoryId maxId = 0;
- StoryId readTill = 0;
- };
- [[nodiscard]] std::optional<PeerSourceState> peerSourceState(
- not_null<PeerData*> peer,
- StoryId storyMaxId);
- [[nodiscard]] bool isUnread(not_null<Story*> story);
- enum class Polling {
- Chat,
- Viewer,
- };
- void registerPolling(not_null<Story*> story, Polling polling);
- void unregisterPolling(not_null<Story*> story, Polling polling);
- [[nodiscard]] bool registerPolling(FullStoryId id, Polling polling);
- void unregisterPolling(FullStoryId id, Polling polling);
- void requestPeerStories(
- not_null<PeerData*> peer,
- Fn<void()> done = nullptr);
- void savedStateChanged(not_null<Story*> story);
- [[nodiscard]] std::shared_ptr<HistoryItem> lookupItem(
- not_null<Story*> story);
- [[nodiscard]] StealthMode stealthMode() const;
- [[nodiscard]] rpl::producer<StealthMode> stealthModeValue() const;
- void activateStealthMode(Fn<void()> done = nullptr);
- void sendReaction(FullStoryId id, Data::ReactionId reaction);
- private:
- struct Set {
- StoriesIds ids;
- int total = -1;
- StoryId lastId = 0;
- bool loaded = false;
- mtpRequestId requestId = 0;
- };
- struct PollingSettings {
- int chat = 0;
- int viewer = 0;
- };
- void parseAndApply(const MTPPeerStories &stories);
- [[nodiscard]] Story *parseAndApply(
- not_null<PeerData*> peer,
- const MTPDstoryItem &data,
- TimeId now);
- StoryIdDates parseAndApply(
- not_null<PeerData*> peer,
- const MTPstoryItem &story,
- TimeId now);
- void processResolvedStories(
- not_null<PeerData*> peer,
- const QVector<MTPStoryItem> &list);
- void sendResolveRequests();
- void finalizeResolve(FullStoryId id);
- void updatePeerStoriesState(not_null<PeerData*> peer);
- [[nodiscard]] Set *lookupArchive(not_null<PeerData*> peer);
- void clearArchive(not_null<PeerData*> peer);
- void applyDeleted(not_null<PeerData*> peer, StoryId id);
- void applyExpired(FullStoryId id);
- void applyRemovedFromActive(FullStoryId id);
- void applyDeletedFromSources(PeerId id, StorySourcesList list);
- void removeDependencyStory(not_null<Story*> story);
- void sort(StorySourcesList list);
- bool bumpReadTill(PeerId peerId, StoryId maxReadTill);
- void requestReadTills();
- void sendMarkAsReadRequests();
- void sendMarkAsReadRequest(not_null<PeerData*> peer, StoryId tillId);
- void sendIncrementViewsRequests();
- void checkQuitPreventFinished();
- void registerExpiring(TimeId expires, FullStoryId id);
- void scheduleExpireTimer();
- void processExpired();
- void preloadSourcesChanged(StorySourcesList list);
- bool rebuildPreloadSources(StorySourcesList list);
- void continuePreloading();
- [[nodiscard]] bool shouldContinuePreload(FullStoryId id) const;
- [[nodiscard]] FullStoryId nextPreloadId() const;
- void startPreloading(not_null<Story*> story);
- void preloadFinished(FullStoryId id, bool markAsPreloaded = false);
- void preloadListsMore();
- void notifySourcesChanged(StorySourcesList list);
- void pushHiddenCountsToFolder();
- void setPinnedToTop(
- PeerId peerId,
- std::vector<StoryId> &&pinnedToTop);
- [[nodiscard]] int pollingInterval(
- const PollingSettings &settings) const;
- void maybeSchedulePolling(
- not_null<Story*> story,
- const PollingSettings &settings,
- TimeId now);
- void sendPollingRequests();
- void sendPollingViewsRequests();
- void sendViewsSliceRequest();
- void sendViewsCountsRequest();
- const not_null<Session*> _owner;
- std::unordered_map<
- PeerId,
- base::flat_map<StoryId, std::unique_ptr<Story>>> _stories;
- base::flat_map<FullStoryId, std::unique_ptr<Story>> _deletingStories;
- std::unordered_map<
- PeerId,
- base::flat_map<StoryId, std::weak_ptr<HistoryItem>>> _items;
- base::flat_multi_map<TimeId, FullStoryId> _expiring;
- base::flat_set<PeerId> _peersWithDeletedStories;
- base::flat_set<FullStoryId> _deleted;
- base::Timer _expireTimer;
- bool _expireSchedulePosted = false;
- base::flat_map<
- PeerId,
- base::flat_map<StoryId, std::vector<Fn<void()>>>> _resolvePending;
- base::flat_map<
- PeerId,
- base::flat_map<StoryId, std::vector<Fn<void()>>>> _resolveSent;
- std::unordered_map<
- not_null<Data::Story*>,
- base::flat_set<not_null<HistoryItem*>>> _dependentMessages;
- std::unordered_map<PeerId, StoriesSource> _all;
- std::vector<StoriesSourceInfo> _sources[kStorySourcesListCount];
- rpl::event_stream<> _sourcesChanged[kStorySourcesListCount];
- bool _sourcesLoaded[kStorySourcesListCount] = { false };
- QString _sourcesStates[kStorySourcesListCount];
- Folder *_folderForHidden = nullptr;
- mtpRequestId _loadMoreRequestId[kStorySourcesListCount] = { 0 };
- rpl::event_stream<PeerId> _sourceChanged;
- rpl::event_stream<PeerId> _itemsChanged;
- std::unordered_map<PeerId, Set> _archive;
- rpl::event_stream<PeerId> _archiveChanged;
- std::unordered_map<PeerId, Set> _saved;
- rpl::event_stream<PeerId> _savedChanged;
- base::flat_set<PeerId> _markReadPending;
- base::Timer _markReadTimer;
- base::flat_set<PeerId> _markReadRequests;
- base::flat_map<
- not_null<PeerData*>,
- std::vector<Fn<void()>>> _requestingPeerStories;
- base::flat_map<PeerId, base::flat_set<StoryId>> _incrementViewsPending;
- base::Timer _incrementViewsTimer;
- base::flat_set<PeerId> _incrementViewsRequests;
- PeerData *_viewsStoryPeer = nullptr;
- StoryId _viewsStoryId = 0;
- QString _viewsOffset;
- Fn<void(StoryViews)> _viewsDone;
- mtpRequestId _viewsRequestId = 0;
- PeerData *_reactionsStoryPeer = nullptr;
- StoryId _reactionsStoryId = 0;
- QString _reactionsOffset;
- Fn<void(StoryViews)> _reactionsDone;
- mtpRequestId _reactionsRequestId = 0;
- base::flat_set<FullStoryId> _preloaded;
- std::vector<FullStoryId> _toPreloadSources[kStorySourcesListCount];
- std::vector<FullStoryId> _toPreloadViewer;
- std::unique_ptr<StoryPreload> _preloading;
- int _preloadingHiddenSourcesCounter = 0;
- int _preloadingMainSourcesCounter = 0;
- base::flat_map<PeerId, StoryId> _readTill;
- base::flat_set<FullStoryId> _pendingReadTillItems;
- base::flat_map<not_null<PeerData*>, StoryId> _pendingPeerStateMaxId;
- mtpRequestId _readTillsRequestId = 0;
- bool _readTillReceived = false;
- base::flat_map<not_null<Story*>, PollingSettings> _pollingSettings;
- base::flat_set<not_null<Story*>> _pollingViews;
- base::Timer _pollingTimer;
- base::Timer _pollingViewsTimer;
- rpl::variable<StealthMode> _stealthMode;
- rpl::lifetime _lifetime;
- };
- } // namespace Data
|