tdesktop/Telegram/SourceFiles/history/history_item.h

512 lines
14 KiB
C
Raw Normal View History

/*
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
2017-04-06 14:38:10 +00:00
#include "base/runtime_composer.h"
2017-08-31 16:28:58 +00:00
#include "base/flags.h"
#include "data/data_media_types.h"
#include "history/history_item_edition.h"
2021-10-02 11:28:21 +00:00
#include "history/history_item_reply_markup.h"
#include <any>
struct HistoryMessageReplyMarkup;
class ReplyKeyboard;
class HistoryMessage;
namespace base {
template <typename Enum>
class enum_mask;
} // namespace base
namespace Storage {
enum class SharedMediaType : signed char;
using SharedMediaTypesMask = base::enum_mask<SharedMediaType>;
} // namespace Storage
namespace Ui {
class RippleAnimation;
} // namespace Ui
namespace style {
struct BotKeyboardButton;
struct RippleAnimation;
} // namespace style
2018-01-09 17:08:31 +00:00
namespace Data {
struct MessagePosition;
struct RecentReaction;
2022-08-16 11:28:17 +00:00
struct ReactionId;
class Media;
struct MessageReaction;
2019-09-11 09:26:13 +00:00
class MessageReactions;
class ForumTopic;
class Thread;
2018-01-09 17:08:31 +00:00
} // namespace Data
2022-08-15 09:20:17 +00:00
namespace Main {
class Session;
} // namespace Main
namespace Window {
class SessionController;
} // namespace Window
namespace HistoryUnreadThings {
enum class AddType;
} // namespace HistoryUnreadThings
namespace HistoryView {
struct TextState;
struct StateRequest;
enum class CursorState : char;
enum class PointState : char;
enum class Context : char;
class ElementDelegate;
} // namespace HistoryView
2022-08-09 11:12:19 +00:00
class HiddenSenderInfo;
class History;
[[nodiscard]] MessageFlags FlagsFromMTP(
MsgId id,
MTPDmessage::Flags flags,
MessageFlags localFlags);
[[nodiscard]] MessageFlags FlagsFromMTP(
MsgId id,
MTPDmessageService::Flags flags,
MessageFlags localFlags);
2021-07-28 11:55:02 +00:00
class HistoryItem : public RuntimeComposer<HistoryItem> {
public:
static not_null<HistoryItem*> Create(
not_null<History*> history,
MsgId id,
const MTPMessage &message,
2021-07-28 11:55:02 +00:00
MessageFlags localFlags);
2018-02-05 20:19:51 +00:00
struct Destroyer {
void operator()(HistoryItem *value);
};
virtual void dependencyItemRemoved(HistoryItem *dependency) {
}
virtual bool updateDependencyItem() {
return true;
}
virtual MsgId dependencyMsgId() const {
return 0;
}
virtual void checkBuyButton() {
}
[[nodiscard]] virtual bool notificationReady() const {
return true;
}
[[nodiscard]] PeerData *specialNotificationPeer() const;
[[nodiscard]] UserData *viaBot() const;
[[nodiscard]] UserData *getMessageBot() const;
[[nodiscard]] bool isHistoryEntry() const;
[[nodiscard]] bool isAdminLogEntry() const;
[[nodiscard]] bool isFromScheduled() const;
[[nodiscard]] bool isScheduled() const;
2021-09-26 18:24:47 +00:00
[[nodiscard]] bool isSponsored() const;
[[nodiscard]] bool skipNotification() const;
void addLogEntryOriginal(
WebPageId localId,
const QString &label,
const TextWithEntities &content);
[[nodiscard]] not_null<Data::Thread*> thread() const;
[[nodiscard]] not_null<History*> history() const {
return _history;
}
[[nodiscard]] Data::ForumTopic *topic() const;
[[nodiscard]] not_null<PeerData*> from() const {
return _from;
}
[[nodiscard]] HistoryView::Element *mainView() const {
return _mainView;
}
void setMainView(not_null<HistoryView::Element*> view) {
_mainView = view;
}
2018-01-18 13:59:22 +00:00
void refreshMainView();
void clearMainView();
void removeMainView();
void invalidateChatListEntry();
void destroy();
[[nodiscard]] bool out() const {
2021-07-28 11:55:02 +00:00
return _flags & MessageFlag::Outgoing;
}
[[nodiscard]] bool isPinned() const {
2021-07-28 11:55:02 +00:00
return _flags & MessageFlag::Pinned;
}
[[nodiscard]] bool unread() const;
[[nodiscard]] bool showNotification() const;
void markClientSideAsRead();
[[nodiscard]] bool mentionsMe() const;
[[nodiscard]] bool isUnreadMention() const;
[[nodiscard]] bool hasUnreadReaction() const;
[[nodiscard]] bool isUnreadMedia() const;
[[nodiscard]] bool isIncomingUnreadMedia() const;
[[nodiscard]] bool hasUnreadMediaFlag() const;
void markReactionsRead();
void markMediaAndMentionRead();
2022-01-28 11:44:33 +00:00
bool markContentsRead(bool fromThisClient = false);
void setIsPinned(bool isPinned);
// For edit media in history_message.
virtual void returnSavedMedia();
void savePreviousMedia();
[[nodiscard]] bool isEditingMedia() const;
void clearSavedMedia();
// Zero result means this message is not self-destructing right now.
virtual crl::time getSelfDestructIn(crl::time now) {
return 0;
}
2019-08-01 21:14:19 +00:00
[[nodiscard]] bool definesReplyKeyboard() const;
2021-07-28 07:33:52 +00:00
[[nodiscard]] ReplyMarkupFlags replyKeyboardFlags() const;
2019-08-01 21:14:19 +00:00
[[nodiscard]] bool hasSwitchInlineButton() const {
2021-07-28 11:55:02 +00:00
return _flags & MessageFlag::HasSwitchInlineButton;
}
2019-08-01 21:14:19 +00:00
[[nodiscard]] bool hasTextLinks() const {
2021-07-28 11:55:02 +00:00
return _flags & MessageFlag::HasTextLinks;
}
2019-08-01 21:14:19 +00:00
[[nodiscard]] bool isGroupEssential() const {
2021-07-28 11:55:02 +00:00
return _flags & MessageFlag::IsGroupEssential;
}
2019-08-01 21:14:19 +00:00
[[nodiscard]] bool isLocalUpdateMedia() const {
2021-07-28 11:55:02 +00:00
return _flags & MessageFlag::IsLocalUpdateMedia;
}
void setIsLocalUpdateMedia(bool flag) {
if (flag) {
2021-07-28 11:55:02 +00:00
_flags |= MessageFlag::IsLocalUpdateMedia;
} else {
2021-07-28 11:55:02 +00:00
_flags &= ~MessageFlag::IsLocalUpdateMedia;
}
}
2019-08-01 21:14:19 +00:00
[[nodiscard]] bool isGroupMigrate() const {
2019-01-22 07:50:21 +00:00
return isGroupEssential() && isEmpty();
}
2019-08-01 21:14:19 +00:00
[[nodiscard]] bool hasViews() const {
2021-07-28 11:55:02 +00:00
return _flags & MessageFlag::HasViews;
}
2019-08-01 21:14:19 +00:00
[[nodiscard]] bool isPost() const {
2021-07-28 11:55:02 +00:00
return _flags & MessageFlag::Post;
}
2019-08-01 21:14:19 +00:00
[[nodiscard]] bool isSilent() const {
2021-07-28 11:55:02 +00:00
return _flags & MessageFlag::Silent;
}
2019-08-01 21:14:19 +00:00
[[nodiscard]] bool isSending() const {
2021-07-28 11:55:02 +00:00
return _flags & MessageFlag::BeingSent;
2019-07-17 14:34:39 +00:00
}
2019-08-01 21:14:19 +00:00
[[nodiscard]] bool hasFailed() const {
2021-07-28 11:55:02 +00:00
return _flags & MessageFlag::SendingFailed;
2019-07-17 14:34:39 +00:00
}
[[nodiscard]] bool hideEditedBadge() const {
return (_flags & MessageFlag::HideEdited);
}
[[nodiscard]] bool isLocal() const {
return _flags & MessageFlag::Local;
}
[[nodiscard]] bool isRegular() const;
[[nodiscard]] bool isUploading() const;
2019-07-17 14:34:39 +00:00
void sendFailed();
2019-08-12 16:33:36 +00:00
[[nodiscard]] virtual int viewsCount() const {
return hasViews() ? 1 : -1;
}
[[nodiscard]] virtual int repliesCount() const {
return 0;
}
2020-09-03 07:19:02 +00:00
[[nodiscard]] virtual bool repliesAreComments() const {
return false;
}
[[nodiscard]] virtual bool externalReply() const {
return false;
}
2022-09-12 14:18:31 +00:00
[[nodiscard]] bool hasExtendedMediaPreview() const;
virtual void setCommentsInboxReadTill(MsgId readTillId) {
2020-09-03 08:21:31 +00:00
}
virtual void setCommentsMaxId(MsgId maxId) {
2020-09-03 08:21:31 +00:00
}
virtual void setCommentsPossibleMaxId(MsgId possibleMaxId) {
2020-09-15 08:39:39 +00:00
}
[[nodiscard]] virtual bool areCommentsUnread() const {
2020-09-15 08:39:39 +00:00
return false;
}
[[nodiscard]] virtual FullMsgId commentsItemId() const {
return FullMsgId();
}
virtual void setCommentsItemId(FullMsgId id) {
}
2019-08-12 16:33:36 +00:00
[[nodiscard]] virtual bool needCheck() const;
[[nodiscard]] virtual bool isService() const {
return false;
}
virtual void applyEdition(HistoryMessageEdition &&edition) {
}
virtual void applyEdition(const MTPDmessageService &message) {
}
virtual void applyEdition(const MTPMessageExtendedMedia &media) {
}
2019-04-08 09:16:45 +00:00
void applyEditionToHistoryCleared();
virtual void updateSentContent(
const TextWithEntities &textWithEntities,
const MTPMessageMedia *media) {
}
2021-10-02 11:28:21 +00:00
virtual void updateReplyMarkup(HistoryMessageMarkupData &&markup) {
}
virtual void updateForwardedInfo(const MTPMessageFwdHeader *fwd) {
}
2019-08-20 09:42:13 +00:00
virtual void contributeToSlowmode(TimeId realDate = 0) {
}
virtual void addToUnreadThings(HistoryUnreadThings::AddType type);
virtual void destroyHistoryEntry() {
}
2019-08-12 16:33:36 +00:00
[[nodiscard]] virtual Storage::SharedMediaTypesMask sharedMediaTypes() const = 0;
2021-02-02 16:38:30 +00:00
virtual void applySentMessage(const MTPDmessage &data);
virtual void applySentMessage(
const QString &text,
const MTPDupdateShortSentMessage &data,
bool wasAlready);
void indexAsNewItem();
2019-08-12 16:33:36 +00:00
[[nodiscard]] virtual QString notificationHeader() const {
return QString();
}
[[nodiscard]] virtual TextWithEntities notificationText() const;
using ToPreviewOptions = HistoryView::ToPreviewOptions;
using ItemPreview = HistoryView::ItemPreview;
// Returns text with link-start and link-end commands for service-color highlighting.
// Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text"
[[nodiscard]] virtual ItemPreview toPreview(
ToPreviewOptions options) const;
[[nodiscard]] virtual TextWithEntities inReplyText() const;
2019-08-12 16:33:36 +00:00
[[nodiscard]] virtual TextWithEntities originalText() const {
return TextWithEntities();
}
[[nodiscard]] virtual auto originalTextWithLocalEntities() const
-> TextWithEntities {
return TextWithEntities();
}
[[nodiscard]] virtual auto customTextLinks() const
-> const std::vector<ClickHandlerPtr> &;
2019-08-12 16:33:36 +00:00
[[nodiscard]] virtual TextForMimeData clipboardText() const {
return TextForMimeData();
}
virtual bool changeViewsCount(int count) {
return false;
}
virtual void setForwardsCount(int count) {
}
2021-10-07 18:52:27 +00:00
virtual void setReplies(HistoryMessageRepliesData &&data) {
2020-09-03 07:19:02 +00:00
}
virtual void clearReplies() {
}
virtual void changeRepliesCount(int delta, PeerId replier) {
}
2022-10-04 15:34:45 +00:00
virtual void setReplyFields(
MsgId replyTo,
MsgId replyToTop,
bool isForumPost) = 0;
virtual void setPostAuthor(const QString &author) {
}
virtual void setRealId(MsgId newId);
virtual void incrementReplyToTopCounter() {
}
2019-08-12 16:33:36 +00:00
[[nodiscard]] bool emptyText() const {
return _text.empty();
}
2019-08-12 16:33:36 +00:00
[[nodiscard]] bool canPin() const;
2021-11-10 06:10:35 +00:00
[[nodiscard]] bool canBeEdited() const;
2019-08-12 16:33:36 +00:00
[[nodiscard]] bool canStopPoll() const;
[[nodiscard]] bool forbidsForward() const;
2019-08-12 16:33:36 +00:00
[[nodiscard]] virtual bool allowsSendNow() const;
[[nodiscard]] virtual bool allowsForward() const;
[[nodiscard]] virtual bool allowsEdit(TimeId now) const;
[[nodiscard]] bool canDelete() const;
[[nodiscard]] bool canDeleteForEveryone(TimeId now) const;
[[nodiscard]] bool suggestReport() const;
[[nodiscard]] bool suggestBanReport() const;
[[nodiscard]] bool suggestDeleteAllReport() const;
2019-09-11 09:26:13 +00:00
[[nodiscard]] bool canReact() const;
enum class ReactionSource {
Selector,
Quick,
Existing,
};
void toggleReaction(
const Data::ReactionId &reaction,
ReactionSource source);
void updateReactions(const MTPMessageReactions *reactions);
void updateReactionsUnknown();
2022-08-16 11:28:17 +00:00
[[nodiscard]] auto reactions() const
-> const std::vector<Data::MessageReaction> &;
[[nodiscard]] auto recentReactions() const
2022-08-16 11:28:17 +00:00
-> const base::flat_map<
Data::ReactionId,
std::vector<Data::RecentReaction>> &;
[[nodiscard]] bool canViewReactions() const;
[[nodiscard]] std::vector<Data::ReactionId> chosenReactions() const;
2022-08-16 11:28:17 +00:00
[[nodiscard]] Data::ReactionId lookupUnreadReaction(
not_null<UserData*> from) const;
2021-12-28 18:20:32 +00:00
[[nodiscard]] crl::time lastReactionsRefreshTime() const;
2019-09-11 09:26:13 +00:00
2019-08-12 16:33:36 +00:00
[[nodiscard]] bool hasDirectLink() const;
[[nodiscard]] FullMsgId fullId() const;
[[nodiscard]] GlobalMsgId globalId() const;
2019-08-12 16:33:36 +00:00
[[nodiscard]] Data::MessagePosition position() const;
[[nodiscard]] TimeId date() const;
[[nodiscard]] static TimeId NewMessageDate(TimeId scheduled);
2019-08-12 16:33:36 +00:00
[[nodiscard]] Data::Media *media() const {
return _media.get();
}
[[nodiscard]] bool computeDropForwardedInfo() const;
virtual void setText(const TextWithEntities &textWithEntities) {
}
[[nodiscard]] virtual MsgId replyToId() const = 0;
[[nodiscard]] virtual MsgId replyToTop() const = 0;
[[nodiscard]] virtual MsgId topicRootId() const = 0;
[[nodiscard]] bool inThread(MsgId rootId) const;
2019-08-12 16:33:36 +00:00
[[nodiscard]] not_null<PeerData*> author() const;
2019-08-12 16:33:36 +00:00
[[nodiscard]] TimeId dateOriginal() const;
[[nodiscard]] PeerData *senderOriginal() const;
[[nodiscard]] const HiddenSenderInfo *hiddenSenderInfo() const;
2019-08-12 16:33:36 +00:00
[[nodiscard]] not_null<PeerData*> fromOriginal() const;
[[nodiscard]] QString authorOriginal() const;
[[nodiscard]] MsgId idOriginal() const;
2019-08-12 16:33:36 +00:00
[[nodiscard]] bool isEmpty() const;
2017-12-13 18:10:48 +00:00
2019-08-12 16:33:36 +00:00
[[nodiscard]] MessageGroupId groupId() const;
2019-08-12 16:33:36 +00:00
[[nodiscard]] const HistoryMessageReplyMarkup *inlineReplyMarkup() const {
2019-05-25 14:42:01 +00:00
return const_cast<HistoryItem*>(this)->inlineReplyMarkup();
}
2019-08-12 16:33:36 +00:00
[[nodiscard]] const ReplyKeyboard *inlineReplyKeyboard() const {
2019-05-25 14:42:01 +00:00
return const_cast<HistoryItem*>(this)->inlineReplyKeyboard();
}
2019-08-12 16:33:36 +00:00
[[nodiscard]] HistoryMessageReplyMarkup *inlineReplyMarkup();
[[nodiscard]] ReplyKeyboard *inlineReplyKeyboard();
2019-05-25 14:42:01 +00:00
[[nodiscard]] ChannelData *discussionPostOriginalSender() const;
[[nodiscard]] bool isDiscussionPost() const;
2020-09-15 08:39:39 +00:00
[[nodiscard]] HistoryItem *lookupDiscussionPostOriginal() const;
[[nodiscard]] PeerData *displayFrom() const;
2019-08-12 16:33:36 +00:00
[[nodiscard]] virtual std::unique_ptr<HistoryView::Element> createView(
not_null<HistoryView::ElementDelegate*> delegate,
HistoryView::Element *replacing = nullptr) = 0;
void updateDate(TimeId newDate);
[[nodiscard]] bool canUpdateDate() const;
void customEmojiRepaint();
[[nodiscard]] TimeId ttlDestroyAt() const {
return _ttlDestroyAt;
}
virtual ~HistoryItem();
2019-08-12 16:33:36 +00:00
MsgId id;
protected:
HistoryItem(
not_null<History*> history,
MsgId id,
2021-07-28 11:55:02 +00:00
MessageFlags flags,
TimeId date,
PeerId from);
virtual void markMediaAsReadHook() {
}
void applyServiceDateEdition(const MTPDmessageService &data);
void finishEdition(int oldKeyboardTop);
void finishEditionToEmpty();
void setReactions(const MTPMessageReactions *reactions);
[[nodiscard]] bool changeReactions(const MTPMessageReactions *reactions);
const not_null<History*> _history;
const not_null<PeerData*> _from;
2021-07-28 11:55:02 +00:00
MessageFlags _flags = 0;
void setGroupId(MessageGroupId groupId);
void applyTTL(const MTPDmessage &data);
void applyTTL(const MTPDmessageService &data);
void applyTTL(TimeId destroyAt);
TextWithEntities _text;
struct SavedMediaData {
TextWithEntities text;
std::unique_ptr<Data::Media> media;
};
std::unique_ptr<SavedMediaData> _savedLocalEditMediaData;
std::unique_ptr<Data::Media> _media;
2019-09-11 09:26:13 +00:00
std::unique_ptr<Data::MessageReactions> _reactions;
crl::time _reactionsLastRefreshed = 0;
private:
TimeId _date = 0;
TimeId _ttlDestroyAt = 0;
HistoryView::Element *_mainView = nullptr;
friend class HistoryView::Element;
2019-05-31 21:51:57 +00:00
MessageGroupId _groupId = MessageGroupId();
};
[[nodiscard]] Main::Session *SessionByUniqueId(uint64 sessionUniqueId);
[[nodiscard]] HistoryItem *MessageByGlobalId(GlobalMsgId globalId);
[[nodiscard]] QDateTime ItemDateTime(not_null<const HistoryItem*> item);
[[nodiscard]] QString ItemDateText(
not_null<const HistoryItem*> item,
bool isUntilOnline);
[[nodiscard]] bool IsItemScheduledUntilOnline(
not_null<const HistoryItem*> item);
ClickHandlerPtr goToMessageClickHandler(
not_null<PeerData*> peer,
MsgId msgId,
FullMsgId returnToId = FullMsgId());
ClickHandlerPtr goToMessageClickHandler(
not_null<HistoryItem*> item,
FullMsgId returnToId = FullMsgId());