/* 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/runtime_composer.h" #include "base/flags.h" #include "base/value_ordering.h" #include "data/data_media_types.h" enum class UnreadMentionType; struct HistoryMessageReplyMarkup; class ReplyKeyboard; class HistoryMessage; class HistoryMedia; namespace base { template class enum_mask; } // namespace base namespace Storage { enum class SharedMediaType : signed char; using SharedMediaTypesMask = base::enum_mask; } // namespace Storage namespace Ui { class RippleAnimation; } // namespace Ui namespace style { struct BotKeyboardButton; struct RippleAnimation; } // namespace style namespace Data { struct MessagePosition; class Media; } // namespace Data namespace Window { class Controller; } // namespace Window namespace HistoryView { struct TextState; struct StateRequest; enum class CursorState : char; enum class PointState : char; enum class Context : char; class ElementDelegate; } // namespace HistoryView struct HiddenSenderInfo; class HistoryItem : public RuntimeComposer { public: static not_null Create( not_null history, const MTPMessage &message); struct Destroyer { void operator()(HistoryItem *value); }; virtual void dependencyItemRemoved(HistoryItem *dependency) { } virtual bool updateDependencyItem() { return true; } virtual MsgId dependencyMsgId() const { return 0; } virtual bool notificationReady() const { return true; } virtual void applyGroupAdminChanges( const base::flat_map &changes) { } UserData *viaBot() const; UserData *getMessageBot() const; bool isLogEntry() const { return (id > ServerMaxMsgId); } void addLogEntryOriginal( WebPageId localId, const QString &label, const TextWithEntities &content); not_null history() const { return _history; } not_null from() const { return _from; } HistoryView::Element *mainView() const { return _mainView; } void setMainView(not_null view) { _mainView = view; } void refreshMainView(); void clearMainView(); void removeMainView(); void destroy(); [[nodiscard]] bool out() const { return _flags & MTPDmessage::Flag::f_out; } [[nodiscard]] bool unread() const; void markClientSideAsRead(); [[nodiscard]] bool mentionsMe() const { return _flags & MTPDmessage::Flag::f_mentioned; } [[nodiscard]] bool isUnreadMention() const; [[nodiscard]] bool isUnreadMedia() const; [[nodiscard]] bool hasUnreadMediaFlag() const; void markMediaRead(); // For edit media in history_message. virtual void returnSavedMedia() {}; void savePreviousMedia() { _savedMedia = _media->clone(this); } [[nodiscard]] bool isEditingMedia() const { return _savedMedia != nullptr; } void clearSavedMedia() { _savedMedia = nullptr; } // Zero result means this message is not self-destructing right now. virtual crl::time getSelfDestructIn(crl::time now) { return 0; } bool definesReplyKeyboard() const; MTPDreplyKeyboardMarkup::Flags replyKeyboardFlags() const; bool hasSwitchInlineButton() const { return _flags & MTPDmessage_ClientFlag::f_has_switch_inline_button; } bool hasTextLinks() const { return _flags & MTPDmessage_ClientFlag::f_has_text_links; } bool isGroupEssential() const { return _flags & MTPDmessage_ClientFlag::f_is_group_essential; } bool isLocalUpdateMedia() const { return _flags & MTPDmessage_ClientFlag::f_is_local_update_media; } void setIsLocalUpdateMedia(bool flag) { if (flag) { _flags |= MTPDmessage_ClientFlag::f_is_local_update_media; } else { _flags &= ~MTPDmessage_ClientFlag::f_is_local_update_media; } } bool isGroupMigrate() const { return isGroupEssential() && isEmpty(); } bool hasViews() const { return _flags & MTPDmessage::Flag::f_views; } bool isPost() const { return _flags & MTPDmessage::Flag::f_post; } bool isSilent() const { return _flags & MTPDmessage::Flag::f_silent; } virtual int viewsCount() const { return hasViews() ? 1 : -1; } virtual bool needCheck() const; virtual bool serviceMsg() const { return false; } virtual void applyEdition(const MTPDmessage &message) { } virtual void applyEdition(const MTPDmessageService &message) { } void applyEditionToHistoryCleared(); virtual void updateSentMedia(const MTPMessageMedia *media) { } virtual void updateReplyMarkup(const MTPReplyMarkup *markup) { } virtual void updateForwardedInfo(const MTPMessageFwdHeader *fwd) { } virtual void addToUnreadMentions(UnreadMentionType type); virtual void eraseFromUnreadMentions() { } virtual Storage::SharedMediaTypesMask sharedMediaTypes() const = 0; void indexAsNewItem(); virtual QString notificationHeader() const { return QString(); } virtual QString notificationText() const; enum class DrawInDialog { Normal, WithoutSender, }; // 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" virtual QString inDialogsText(DrawInDialog way) const; virtual QString inReplyText() const { return inDialogsText(DrawInDialog::WithoutSender); } virtual TextWithEntities originalText() const { return TextWithEntities(); } virtual TextForMimeData clipboardText() const { return TextForMimeData(); } virtual void setViewsCount(int32 count) { } virtual void setRealId(MsgId newId); void drawInDialog( Painter &p, const QRect &r, bool active, bool selected, DrawInDialog way, const HistoryItem *&cacheFor, Text &cache) const; bool emptyText() const { return _text.isEmpty(); } bool isPinned() const; bool canPin() const; bool canStopPoll() const; virtual bool allowsForward() const; virtual bool allowsEdit(TimeId now) const; bool canDelete() const; bool canDeleteForEveryone(TimeId now) const; bool suggestReport() const; bool suggestBanReport() const; bool suggestDeleteAllReport() const; bool hasDirectLink() const; MsgId id; ChannelId channelId() const; FullMsgId fullId() const { return FullMsgId(channelId(), id); } Data::MessagePosition position() const; TimeId date() const; Data::Media *media() const { return _media.get(); } virtual void setText(const TextWithEntities &textWithEntities) { } virtual bool textHasLinks() const { return false; } virtual HistoryMessage *toHistoryMessage() { // dynamic_cast optimize return nullptr; } virtual const HistoryMessage *toHistoryMessage() const { // dynamic_cast optimize return nullptr; } MsgId replyToId() const; not_null author() const; TimeId dateOriginal() const; PeerData *senderOriginal() const; const HiddenSenderInfo *hiddenForwardedInfo() const; not_null fromOriginal() const; QString authorOriginal() const; MsgId idOriginal() const; bool isEmpty() const; MessageGroupId groupId() const; const HistoryMessageReplyMarkup *inlineReplyMarkup() const { return const_cast(this)->inlineReplyMarkup(); } const ReplyKeyboard *inlineReplyKeyboard() const { return const_cast(this)->inlineReplyKeyboard(); } HistoryMessageReplyMarkup *inlineReplyMarkup(); ReplyKeyboard *inlineReplyKeyboard(); [[nodiscard]] ChannelData *discussionPostOriginalSender() const; [[nodiscard]] bool isDiscussionPost() const; [[nodiscard]] PeerData *displayFrom() const; virtual std::unique_ptr createView( not_null delegate) = 0; virtual ~HistoryItem(); protected: HistoryItem( not_null history, MsgId id, MTPDmessage::Flags flags, TimeId date, UserId from); virtual void markMediaAsReadHook() { } void finishEdition(int oldKeyboardTop); void finishEditionToEmpty(); const not_null _history; not_null _from; MTPDmessage::Flags _flags = 0; void invalidateChatListEntry(); void setGroupId(MessageGroupId groupId); Text _text = { st::msgMinWidth }; int _textWidth = -1; int _textHeight = 0; std::unique_ptr _savedMedia; std::unique_ptr _media; private: TimeId _date = 0; HistoryView::Element *_mainView = nullptr; friend class HistoryView::Element; MessageGroupId _groupId = MessageGroupId::None; }; QDateTime ItemDateTime(not_null item); ClickHandlerPtr goToMessageClickHandler( not_null peer, MsgId msgId, FullMsgId returnToId = FullMsgId()); ClickHandlerPtr goToMessageClickHandler( not_null item, FullMsgId returnToId = FullMsgId());