tdesktop/Telegram/SourceFiles/data/data_story.h

289 lines
7.0 KiB
C++

/*
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/weak_ptr.h"
#include "data/data_location.h"
#include "data/data_message_reaction_id.h"
class Image;
class PhotoData;
class DocumentData;
namespace Main {
class Session;
} // namespace Main
namespace Data {
class Session;
class Thread;
class PhotoMedia;
enum class StoryPrivacy : uchar {
Public,
CloseFriends,
Contacts,
SelectedContacts,
Other,
};
struct StoryIdDates {
StoryId id = 0;
TimeId date = 0;
TimeId expires = 0;
[[nodiscard]] bool valid() const {
return id != 0;
}
explicit operator bool() const {
return valid();
}
friend inline auto operator<=>(StoryIdDates, StoryIdDates) = default;
friend inline bool operator==(StoryIdDates, StoryIdDates) = default;
};
struct StoryMedia {
std::variant<
v::null_t,
not_null<PhotoData*>,
not_null<DocumentData*>> data;
friend inline bool operator==(StoryMedia, StoryMedia) = default;
};
struct StoryView {
not_null<PeerData*> peer;
Data::ReactionId reaction;
StoryId repostId = 0;
MsgId forwardId = 0;
TimeId date = 0;
friend inline bool operator==(StoryView, StoryView) = default;
};
struct StoryViews {
std::vector<StoryView> list;
QString nextOffset;
int reactions = 0;
int forwards = 0;
int views = 0;
int total = 0;
bool known = false;
};
struct StoryArea {
QRectF geometry;
float64 rotation = 0;
friend inline bool operator==(
const StoryArea &,
const StoryArea &) = default;
};
struct StoryLocation {
StoryArea area;
Data::LocationPoint point;
QString title;
QString address;
QString provider;
QString venueId;
QString venueType;
friend inline bool operator==(
const StoryLocation &,
const StoryLocation &) = default;
};
struct SuggestedReaction {
StoryArea area;
Data::ReactionId reaction;
int count = 0;
bool flipped = false;
bool dark = false;
friend inline bool operator==(
const SuggestedReaction &,
const SuggestedReaction &) = default;
};
struct ChannelPost {
StoryArea area;
FullMsgId itemId;
friend inline bool operator==(
const ChannelPost &,
const ChannelPost &) = default;
};
class Story final {
public:
Story(
StoryId id,
not_null<PeerData*> peer,
StoryMedia media,
const MTPDstoryItem &data,
TimeId now);
static constexpr int kRecentViewersMax = 3;
[[nodiscard]] Session &owner() const;
[[nodiscard]] Main::Session &session() const;
[[nodiscard]] not_null<PeerData*> peer() const;
[[nodiscard]] StoryId id() const;
[[nodiscard]] bool mine() const;
[[nodiscard]] StoryIdDates idDates() const;
[[nodiscard]] FullStoryId fullId() const;
[[nodiscard]] TimeId date() const;
[[nodiscard]] TimeId expires() const;
[[nodiscard]] bool unsupported() const;
[[nodiscard]] bool expired(TimeId now = 0) 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 setInProfile(bool value);
[[nodiscard]] bool inProfile() const;
[[nodiscard]] StoryPrivacy privacy() const;
[[nodiscard]] bool forbidsForward() const;
[[nodiscard]] bool edited() const;
[[nodiscard]] bool out() const;
[[nodiscard]] bool canDownloadIfPremium() const;
[[nodiscard]] bool canDownloadChecked() const;
[[nodiscard]] bool canShare() const;
[[nodiscard]] bool canDelete() const;
[[nodiscard]] bool canReport() const;
[[nodiscard]] bool hasDirectLink() const;
[[nodiscard]] std::optional<QString> errorTextForForward(
not_null<Thread*> to) const;
void setCaption(TextWithEntities &&caption);
[[nodiscard]] const TextWithEntities &caption() const;
[[nodiscard]] Data::ReactionId sentReactionId() const;
void setReactionId(Data::ReactionId id);
[[nodiscard]] auto recentViewers() const
-> const std::vector<not_null<PeerData*>> &;
[[nodiscard]] const StoryViews &viewsList() const;
[[nodiscard]] const StoryViews &channelReactionsList() const;
[[nodiscard]] int interactions() const;
[[nodiscard]] int views() const;
[[nodiscard]] int forwards() const;
[[nodiscard]] int reactions() const;
void applyViewsSlice(const QString &offset, const StoryViews &slice);
void applyChannelReactionsSlice(
const QString &offset,
const StoryViews &slice);
[[nodiscard]] const std::vector<StoryLocation> &locations() const;
[[nodiscard]] auto suggestedReactions() const
-> const std::vector<SuggestedReaction> &;
[[nodiscard]] auto channelPosts() const
-> const std::vector<ChannelPost> &;
void applyChanges(
StoryMedia media,
const MTPDstoryItem &data,
TimeId now);
void applyViewsCounts(const MTPDstoryViews &data);
[[nodiscard]] TimeId lastUpdateTime() const;
[[nodiscard]] bool repost() const;
[[nodiscard]] bool repostModified() const;
[[nodiscard]] PeerData *repostSourcePeer() const;
[[nodiscard]] QString repostSourceName() const;
[[nodiscard]] StoryId repostSourceId() const;
[[nodiscard]] PeerData *fromPeer() const;
private:
struct ViewsCounts {
int views = 0;
int forwards = 0;
int reactions = 0;
base::flat_map<Data::ReactionId, int> reactionsCounts;
std::vector<not_null<PeerData*>> viewers;
};
void changeSuggestedReactionCount(Data::ReactionId id, int delta);
void applyFields(
StoryMedia media,
const MTPDstoryItem &data,
TimeId now,
bool initial);
void updateViewsCounts(ViewsCounts &&counts, bool known, bool initial);
[[nodiscard]] ViewsCounts parseViewsCounts(
const MTPDstoryViews &data,
const Data::ReactionId &mine);
const StoryId _id = 0;
const not_null<PeerData*> _peer;
PeerData * const _repostSourcePeer = nullptr;
const QString _repostSourceName;
const StoryId _repostSourceId = 0;
PeerData * const _fromPeer = nullptr;
Data::ReactionId _sentReactionId;
StoryMedia _media;
TextWithEntities _caption;
std::vector<not_null<PeerData*>> _recentViewers;
std::vector<StoryLocation> _locations;
std::vector<SuggestedReaction> _suggestedReactions;
std::vector<ChannelPost> _channelPosts;
StoryViews _views;
StoryViews _channelReactions;
const TimeId _date = 0;
const TimeId _expires = 0;
TimeId _lastUpdateTime = 0;
bool _out : 1 = false;
bool _inProfile : 1 = false;
bool _privacyPublic : 1 = false;
bool _privacyCloseFriends : 1 = false;
bool _privacyContacts : 1 = false;
bool _privacySelectedContacts : 1 = false;
const bool _repostModified : 1 = false;
bool _noForwards : 1 = false;
bool _edited : 1 = false;
};
class StoryPreload final : public base::has_weak_ptr {
public:
StoryPreload(not_null<Story*> story, Fn<void()> done);
~StoryPreload();
[[nodiscard]] FullStoryId id() const;
[[nodiscard]] not_null<Story*> story() const;
private:
class LoadTask;
void start();
void load();
void callDone();
const not_null<Story*> _story;
Fn<void()> _done;
std::shared_ptr<Data::PhotoMedia> _photo;
std::unique_ptr<LoadTask> _task;
rpl::lifetime _lifetime;
};
} // namespace Data