/* 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/expected.h" #include "base/timer.h" class Image; class PhotoData; class DocumentData; namespace Main { class Session; } // namespace Main namespace Data { class Session; struct StoryMedia { std::variant, not_null> data; friend inline bool operator==(StoryMedia, StoryMedia) = default; }; struct StoryView { not_null peer; TimeId date = 0; friend inline bool operator==(StoryView, StoryView) = default; }; class Story { public: Story( StoryId id, not_null peer, StoryMedia media, TimeId date); [[nodiscard]] Session &owner() const; [[nodiscard]] Main::Session &session() const; [[nodiscard]] not_null peer() const; [[nodiscard]] StoryId id() const; [[nodiscard]] FullStoryId fullId() const; [[nodiscard]] TimeId date() const; [[nodiscard]] const StoryMedia &media() const; [[nodiscard]] PhotoData *photo() const; [[nodiscard]] DocumentData *document() const; [[nodiscard]] bool hasReplyPreview() const; [[nodiscard]] Image *replyPreview() const; [[nodiscard]] TextWithEntities inReplyText() const; void setPinned(bool pinned); [[nodiscard]] bool pinned() const; void setCaption(TextWithEntities &&caption); [[nodiscard]] const TextWithEntities &caption() const; void setViewsData(std::vector> recent, int total); [[nodiscard]] auto recentViewers() const -> const std::vector> &; [[nodiscard]] const std::vector &viewsList() const; [[nodiscard]] int views() const; void applyViewsSlice( const std::optional &offset, const std::vector &slice, int total); bool applyChanges(StoryMedia media, const MTPDstoryItem &data); private: const StoryId _id = 0; const not_null _peer; StoryMedia _media; TextWithEntities _caption; std::vector> _recentViewers; std::vector _viewsList; int _views = 0; const TimeId _date = 0; bool _pinned = false; }; struct StoriesList { not_null user; base::flat_set ids; StoryId readTill = 0; int total = 0; [[nodiscard]] bool unread() const; friend inline bool operator==(StoriesList, StoriesList) = default; }; enum class NoStory : uchar { Unknown, Deleted, }; class Stories final { public: explicit Stories(not_null owner); ~Stories(); [[nodiscard]] Session &owner() const; [[nodiscard]] Main::Session &session() const; void updateDependentMessages(not_null story); void registerDependentMessage( not_null dependent, not_null dependency); void unregisterDependentMessage( not_null dependent, not_null dependency); void loadMore(); void apply(const MTPDupdateStories &data); void loadAround(FullStoryId id); [[nodiscard]] const std::vector &all(); [[nodiscard]] bool allLoaded() const; [[nodiscard]] rpl::producer<> allChanged() const; [[nodiscard]] rpl::producer itemsChanged() const; [[nodiscard]] base::expected, NoStory> lookup( FullStoryId id) const; void resolve(FullStoryId id, Fn done); [[nodiscard]] bool isQuitPrevent(); void markAsRead(FullStoryId id, bool viewed); static constexpr auto kViewsPerPage = 50; void loadViewsSlice( StoryId id, std::optional offset, Fn)> done); private: [[nodiscard]] StoriesList parse(const MTPUserStories &stories); [[nodiscard]] Story *parseAndApply( not_null peer, const MTPDstoryItem &data); void processResolvedStories( not_null peer, const QVector &list); void sendResolveRequests(); void finalizeResolve(FullStoryId id); void pushToBack(StoriesList &&list); void applyChanges(StoriesList &&list); void applyDeleted(FullStoryId id); void removeDependencyStory(not_null story); void sendMarkAsReadRequests(); void sendMarkAsReadRequest(not_null peer, StoryId tillId); const not_null _owner; base::flat_map< PeerId, base::flat_map>> _stories; base::flat_set _deleted; base::flat_map< PeerId, base::flat_map>>> _resolvePending; base::flat_map< PeerId, base::flat_map>>> _resolveSent; std::map< not_null, base::flat_set>> _dependentMessages; std::vector _all; rpl::event_stream<> _allChanged; rpl::event_stream _itemsChanged; QString _state; bool _allLoaded = false; mtpRequestId _loadMoreRequestId = 0; base::flat_set _markReadPending; base::Timer _markReadTimer; base::flat_set _markReadRequests; StoryId _viewsStoryId = 0; std::optional _viewsOffset; Fn)> _viewsDone; mtpRequestId _viewsRequestId = 0; }; } // namespace Data