577 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			577 lines
		
	
	
	
		
			16 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 "data/data_types.h"
 | |
| #include "data/data_peer.h"
 | |
| #include "dialogs/dialogs_entry.h"
 | |
| #include "ui/effects/send_action_animations.h"
 | |
| #include "base/observer.h"
 | |
| #include "base/timer.h"
 | |
| #include "base/variant.h"
 | |
| #include "base/flat_set.h"
 | |
| #include "base/flags.h"
 | |
| 
 | |
| class History;
 | |
| class HistoryBlock;
 | |
| class HistoryItem;
 | |
| class HistoryMessage;
 | |
| class HistoryService;
 | |
| class HistoryMedia;
 | |
| 
 | |
| namespace Data {
 | |
| struct Draft;
 | |
| } // namespace Data
 | |
| 
 | |
| namespace Dialogs {
 | |
| class Row;
 | |
| class IndexedList;
 | |
| } // namespace Dialogs
 | |
| 
 | |
| namespace HistoryView {
 | |
| class Element;
 | |
| } // namespace HistoryView
 | |
| 
 | |
| namespace AdminLog {
 | |
| class LocalIdManager;
 | |
| } // namespace AdminLog
 | |
| 
 | |
| enum NewMessageType : char {
 | |
| 	NewMessageUnread,
 | |
| 	NewMessageLast,
 | |
| 	NewMessageExisting,
 | |
| };
 | |
| 
 | |
| class Histories {
 | |
| public:
 | |
| 	Histories();
 | |
| 
 | |
| 	void registerSendAction(
 | |
| 		not_null<History*> history,
 | |
| 		not_null<UserData*> user,
 | |
| 		const MTPSendMessageAction &action,
 | |
| 		TimeId when);
 | |
| 	void step_typings(TimeMs ms, bool timer);
 | |
| 
 | |
| 	History *find(PeerId peerId) const;
 | |
| 	not_null<History*> findOrInsert(PeerId peerId);
 | |
| 
 | |
| 	void clear();
 | |
| 	void remove(const PeerId &peer);
 | |
| 
 | |
| 	HistoryItem *addNewMessage(const MTPMessage &msg, NewMessageType type);
 | |
| 
 | |
| 	// When typing in this history started.
 | |
| 	typedef QMap<History*, TimeMs> TypingHistories;
 | |
| 	TypingHistories typing;
 | |
| 	BasicAnimation _a_typings;
 | |
| 
 | |
| 	int unreadBadge() const;
 | |
| 	int unreadMutedCount() const;
 | |
| 	bool unreadOnlyMuted() const;
 | |
| 	void unreadIncrement(int count, bool muted);
 | |
| 	void unreadMuteChanged(int count, bool muted);
 | |
| 
 | |
| 	struct SendActionAnimationUpdate {
 | |
| 		History *history;
 | |
| 		int width;
 | |
| 		int height;
 | |
| 		bool textUpdated;
 | |
| 	};
 | |
| 	base::Observable<SendActionAnimationUpdate> &sendActionAnimationUpdated() {
 | |
| 		return _sendActionAnimationUpdated;
 | |
| 	}
 | |
| 	void selfDestructIn(not_null<HistoryItem*> item, TimeMs delay);
 | |
| 
 | |
| private:
 | |
| 	void checkSelfDestructItems();
 | |
| 
 | |
| 	std::unordered_map<PeerId, std::unique_ptr<History>> _map;
 | |
| 
 | |
| 	int _unreadFull = 0;
 | |
| 	int _unreadMuted = 0;
 | |
| 	base::Observable<SendActionAnimationUpdate> _sendActionAnimationUpdated;
 | |
| 
 | |
| 	base::Timer _selfDestructTimer;
 | |
| 	std::vector<FullMsgId> _selfDestructItems;
 | |
| 
 | |
| };
 | |
| 
 | |
| enum class UnreadMentionType {
 | |
| 	New, // when new message is added to history
 | |
| 	Existing, // when some messages slice was received
 | |
| };
 | |
| 
 | |
| class History : public Dialogs::Entry {
 | |
| public:
 | |
| 	using Element = HistoryView::Element;
 | |
| 
 | |
| 	History(const PeerId &peerId);
 | |
| 	History(const History &) = delete;
 | |
| 	History &operator=(const History &) = delete;
 | |
| 
 | |
| 	ChannelId channelId() const;
 | |
| 	bool isChannel() const;
 | |
| 	bool isMegagroup() const;
 | |
| 	not_null<History*> migrateToOrMe() const;
 | |
| 	History *migrateFrom() const;
 | |
| 	MsgRange rangeForDifferenceRequest() const;
 | |
| 	HistoryService *insertJoinedMessage(bool unread);
 | |
| 	void checkJoinedMessage(bool createUnread = false);
 | |
| 
 | |
| 	bool isEmpty() const;
 | |
| 	bool isDisplayedEmpty() const;
 | |
| 	bool hasOrphanMediaGroupPart() const;
 | |
| 	bool removeOrphanMediaGroupPart();
 | |
| 	QVector<MsgId> collectMessagesFromUserToDelete(
 | |
| 		not_null<UserData*> user) const;
 | |
| 
 | |
| 	void clear();
 | |
| 	void markFullyLoaded();
 | |
| 	void unloadBlocks();
 | |
| 	void clearUpTill(MsgId availableMinId);
 | |
| 
 | |
| 	void applyGroupAdminChanges(
 | |
| 		const base::flat_map<UserId, bool> &changes);
 | |
| 
 | |
| 	HistoryItem *addNewMessage(const MTPMessage &msg, NewMessageType type);
 | |
| 	HistoryItem *addToHistory(const MTPMessage &msg);
 | |
| 	not_null<HistoryItem*> addNewService(
 | |
| 		MsgId msgId,
 | |
| 		TimeId date,
 | |
| 		const QString &text,
 | |
| 		MTPDmessage::Flags flags = 0,
 | |
| 		bool newMsg = true);
 | |
| 	not_null<HistoryItem*> addNewForwarded(
 | |
| 		MsgId id,
 | |
| 		MTPDmessage::Flags flags,
 | |
| 		TimeId date,
 | |
| 		UserId from,
 | |
| 		const QString &postAuthor,
 | |
| 		not_null<HistoryMessage*> original);
 | |
| 	not_null<HistoryItem*> addNewDocument(
 | |
| 		MsgId id,
 | |
| 		MTPDmessage::Flags flags,
 | |
| 		UserId viaBotId,
 | |
| 		MsgId replyTo,
 | |
| 		TimeId date,
 | |
| 		UserId from,
 | |
| 		const QString &postAuthor,
 | |
| 		not_null<DocumentData*> document,
 | |
| 		const TextWithEntities &caption,
 | |
| 		const MTPReplyMarkup &markup);
 | |
| 	not_null<HistoryItem*> addNewPhoto(
 | |
| 		MsgId id,
 | |
| 		MTPDmessage::Flags flags,
 | |
| 		UserId viaBotId,
 | |
| 		MsgId replyTo,
 | |
| 		TimeId date,
 | |
| 		UserId from,
 | |
| 		const QString &postAuthor,
 | |
| 		not_null<PhotoData*> photo,
 | |
| 		const TextWithEntities &caption,
 | |
| 		const MTPReplyMarkup &markup);
 | |
| 	not_null<HistoryItem*> addNewGame(
 | |
| 		MsgId id,
 | |
| 		MTPDmessage::Flags flags,
 | |
| 		UserId viaBotId,
 | |
| 		MsgId replyTo,
 | |
| 		TimeId date,
 | |
| 		UserId from,
 | |
| 		const QString &postAuthor,
 | |
| 		not_null<GameData*> game,
 | |
| 		const MTPReplyMarkup &markup);
 | |
| 
 | |
| 	// Used only internally and for channel admin log.
 | |
| 	HistoryItem *createItem(
 | |
| 		const MTPMessage &message,
 | |
| 		bool detachExistingItem);
 | |
| 	std::vector<not_null<HistoryItem*>> createItems(
 | |
| 		const QVector<MTPMessage> &data);
 | |
| 
 | |
| 	void addOlderSlice(const QVector<MTPMessage> &slice);
 | |
| 	void addNewerSlice(const QVector<MTPMessage> &slice);
 | |
| 
 | |
| 	void newItemAdded(not_null<HistoryItem*> item);
 | |
| 
 | |
| 	int countUnread(MsgId upTo);
 | |
| 	MsgId readInbox();
 | |
| 	void inboxRead(MsgId upTo);
 | |
| 	void inboxRead(not_null<const HistoryItem*> wasRead);
 | |
| 	void outboxRead(MsgId upTo);
 | |
| 	void outboxRead(not_null<const HistoryItem*> wasRead);
 | |
| 	bool isServerSideUnread(not_null<const HistoryItem*> item) const;
 | |
| 	MsgId loadAroundId() const;
 | |
| 
 | |
| 	int unreadCount() const;
 | |
| 	bool unreadCountKnown() const;
 | |
| 	void setUnreadCount(int newUnreadCount);
 | |
| 	void changeUnreadCount(int delta);
 | |
| 	bool mute() const;
 | |
| 	bool changeMute(bool newMute);
 | |
| 	void addUnreadBar();
 | |
| 	void destroyUnreadBar();
 | |
| 	bool hasNotFreezedUnreadBar() const;
 | |
| 	Element *unreadBar() const;
 | |
| 	void calculateFirstUnreadMessage();
 | |
| 	void unsetFirstUnreadMessage();
 | |
| 	Element *firstUnreadMessage() const;
 | |
| 	void clearNotifications();
 | |
| 
 | |
| 	bool loadedAtBottom() const; // last message is in the list
 | |
| 	void setNotLoadedAtBottom();
 | |
| 	bool loadedAtTop() const; // nothing was added after loading history back
 | |
| 	bool isReadyFor(MsgId msgId); // has messages for showing history at msgId
 | |
| 	void getReadyFor(MsgId msgId);
 | |
| 
 | |
| 	HistoryItem *lastMessage() const;
 | |
| 	bool lastMessageKnown() const;
 | |
| 	void unknownMessageDeleted(MsgId messageId);
 | |
| 	void applyDialogTopMessage(MsgId topMessageId);
 | |
| 	void applyDialog(const MTPDdialog &data);
 | |
| 	void applyDialogFields(
 | |
| 		int unreadCount,
 | |
| 		MsgId maxInboxRead,
 | |
| 		MsgId maxOutboxRead);
 | |
| 
 | |
| 	MsgId minMsgId() const;
 | |
| 	MsgId maxMsgId() const;
 | |
| 	MsgId msgIdForRead() const;
 | |
| 
 | |
| 	void resizeToWidth(int newWidth);
 | |
| 	int height() const;
 | |
| 
 | |
| 	void itemRemoved(not_null<HistoryItem*> item);
 | |
| 	void itemVanished(not_null<HistoryItem*> item);
 | |
| 
 | |
| 	HistoryItem *currentNotification();
 | |
| 	bool hasNotification() const;
 | |
| 	void skipNotification();
 | |
| 	void popNotification(HistoryItem *item);
 | |
| 
 | |
| 	bool hasPendingResizedItems() const;
 | |
| 	void setHasPendingResizedItems();
 | |
| 
 | |
| 	bool mySendActionUpdated(SendAction::Type type, bool doing);
 | |
| 	bool paintSendAction(Painter &p, int x, int y, int availableWidth, int outerWidth, style::color color, TimeMs ms);
 | |
| 
 | |
| 	// Interface for Histories
 | |
| 	bool updateSendActionNeedsAnimating(TimeMs ms, bool force = false);
 | |
| 	bool updateSendActionNeedsAnimating(
 | |
| 		not_null<UserData*> user,
 | |
| 		const MTPSendMessageAction &action);
 | |
| 
 | |
| 	void clearLastKeyboard();
 | |
| 
 | |
| 	int getUnreadMentionsLoadedCount() const {
 | |
| 		return _unreadMentions.size();
 | |
| 	}
 | |
| 	MsgId getMinLoadedUnreadMention() const {
 | |
| 		return _unreadMentions.empty() ? 0 : _unreadMentions.front();
 | |
| 	}
 | |
| 	MsgId getMaxLoadedUnreadMention() const {
 | |
| 		return _unreadMentions.empty() ? 0 : _unreadMentions.back();
 | |
| 	}
 | |
| 	int getUnreadMentionsCount(int notLoadedValue = -1) const {
 | |
| 		return _unreadMentionsCount ? *_unreadMentionsCount : notLoadedValue;
 | |
| 	}
 | |
| 	bool hasUnreadMentions() const {
 | |
| 		return (getUnreadMentionsCount() > 0);
 | |
| 	}
 | |
| 	void setUnreadMentionsCount(int count);
 | |
| 	bool addToUnreadMentions(MsgId msgId, UnreadMentionType type);
 | |
| 	void eraseFromUnreadMentions(MsgId msgId);
 | |
| 	void addUnreadMentionsSlice(const MTPmessages_Messages &result);
 | |
| 
 | |
| 	Data::Draft *localDraft() const {
 | |
| 		return _localDraft.get();
 | |
| 	}
 | |
| 	Data::Draft *cloudDraft() const {
 | |
| 		return _cloudDraft.get();
 | |
| 	}
 | |
| 	Data::Draft *editDraft() const {
 | |
| 		return _editDraft.get();
 | |
| 	}
 | |
| 	void setLocalDraft(std::unique_ptr<Data::Draft> &&draft);
 | |
| 	void takeLocalDraft(History *from);
 | |
| 	void createLocalDraftFromCloud();
 | |
| 	void setCloudDraft(std::unique_ptr<Data::Draft> &&draft);
 | |
| 	Data::Draft *createCloudDraft(Data::Draft *fromDraft);
 | |
| 	void setEditDraft(std::unique_ptr<Data::Draft> &&draft);
 | |
| 	void clearLocalDraft();
 | |
| 	void clearCloudDraft();
 | |
| 	void clearEditDraft();
 | |
| 	void draftSavedToCloud();
 | |
| 	Data::Draft *draft() {
 | |
| 		return _editDraft ? editDraft() : localDraft();
 | |
| 	}
 | |
| 
 | |
| 	const MessageIdsList &forwardDraft() const {
 | |
| 		return _forwardDraft;
 | |
| 	}
 | |
| 	HistoryItemsList validateForwardDraft();
 | |
| 	void setForwardDraft(MessageIdsList &&items);
 | |
| 
 | |
| 	void updateChatListExistence() override;
 | |
| 	bool shouldBeInChatList() const override;
 | |
| 	bool toImportant() const override {
 | |
| 		return !mute();
 | |
| 	}
 | |
| 	int chatListUnreadCount() const override;
 | |
| 	bool chatListMutedBadge() const override;
 | |
| 	HistoryItem *chatsListItem() const override;
 | |
| 	const QString &chatsListName() const override;
 | |
| 	const base::flat_set<QString> &chatsListNameWords() const override;
 | |
| 	const base::flat_set<QChar> &chatsListFirstLetters() const override;
 | |
| 	void loadUserpic() override;
 | |
| 	void paintUserpic(
 | |
| 		Painter &p,
 | |
| 		int x,
 | |
| 		int y,
 | |
| 		int size) const override;
 | |
| 
 | |
| 	void forgetScrollState() {
 | |
| 		scrollTopItem = nullptr;
 | |
| 	}
 | |
| 
 | |
| 	// find the correct scrollTopItem and scrollTopOffset using given top
 | |
| 	// of the displayed window relative to the history start coordinate
 | |
| 	void countScrollState(int top);
 | |
| 
 | |
| 	std::shared_ptr<AdminLog::LocalIdManager> adminLogIdManager();
 | |
| 
 | |
| 	virtual ~History();
 | |
| 
 | |
| 	// Still public data.
 | |
| 	std::deque<std::unique_ptr<HistoryBlock>> blocks;
 | |
| 
 | |
| 	not_null<PeerData*> peer;
 | |
| 	HistoryItem *lastSentMsg = nullptr;
 | |
| 
 | |
| 	typedef QList<HistoryItem*> NotifyQueue;
 | |
| 	NotifyQueue notifies;
 | |
| 
 | |
| 	// we save the last showAtMsgId to restore the state when switching
 | |
| 	// between different conversation histories
 | |
| 	MsgId showAtMsgId = ShowAtUnreadMsgId;
 | |
| 
 | |
| 	// we save a pointer of the history item at the top of the displayed window
 | |
| 	// together with an offset from the window top to the top of this message
 | |
| 	// resulting scrollTop = top(scrollTopItem) + scrollTopOffset
 | |
| 	Element *scrollTopItem = nullptr;
 | |
| 	int scrollTopOffset = 0;
 | |
| 
 | |
| 	bool lastKeyboardInited = false;
 | |
| 	bool lastKeyboardUsed = false;
 | |
| 	MsgId lastKeyboardId = 0;
 | |
| 	MsgId lastKeyboardHiddenId = 0;
 | |
| 	PeerId lastKeyboardFrom = 0;
 | |
| 
 | |
| 	mtpRequestId sendRequestId = 0;
 | |
| 
 | |
| 	Text cloudDraftTextCache;
 | |
| 
 | |
| private:
 | |
| 	friend class HistoryBlock;
 | |
| 
 | |
| 	enum class Flag {
 | |
| 		f_has_pending_resized_items = (1 << 0),
 | |
| 	};
 | |
| 	using Flags = base::flags<Flag>;
 | |
| 	friend inline constexpr auto is_flag_type(Flag) {
 | |
| 		return true;
 | |
| 	};
 | |
| 
 | |
| 	// when this item is destroyed scrollTopItem just points to the next one
 | |
| 	// and scrollTopOffset remains the same
 | |
| 	// if we are at the bottom of the window scrollTopItem == nullptr and
 | |
| 	// scrollTopOffset is undefined
 | |
| 	void getNextScrollTopItem(HistoryBlock *block, int32 i);
 | |
| 
 | |
| 	// helper method for countScrollState(int top)
 | |
| 	void countScrollTopItem(int top);
 | |
| 
 | |
| 	HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type);
 | |
| 
 | |
| 	// this method just removes a block from the blocks list
 | |
| 	// when the last item from this block was detached and
 | |
| 	// calls the required previousItemChanged()
 | |
| 	void removeBlock(not_null<HistoryBlock*> block);
 | |
| 
 | |
| 	void clearBlocks(bool leaveItems);
 | |
| 
 | |
| 	not_null<HistoryItem*> addNewItem(
 | |
| 		not_null<HistoryItem*> item,
 | |
| 		bool unread);
 | |
| 	not_null<HistoryItem*> addNewInTheMiddle(
 | |
| 		not_null<HistoryItem*> item,
 | |
| 		int blockIndex,
 | |
| 		int itemIndex);
 | |
| 
 | |
| 	// All this methods add a new item to the first or last block
 | |
| 	// depending on if we are in isBuildingFronBlock() state.
 | |
| 	// The last block is created on the go if it is needed.
 | |
| 
 | |
| 	// Adds the item to the back or front block, depending on
 | |
| 	// isBuildingFrontBlock(), creating the block if necessary.
 | |
| 	void addItemToBlock(not_null<HistoryItem*> item);
 | |
| 
 | |
| 	// Usually all new items are added to the last block.
 | |
| 	// Only when we scroll up and add a new slice to the
 | |
| 	// front we want to create a new front block.
 | |
| 	void startBuildingFrontBlock(int expectedItemsCount = 1);
 | |
| 	void finishBuildingFrontBlock();
 | |
| 	bool isBuildingFrontBlock() const {
 | |
| 		return _buildingFrontBlock != nullptr;
 | |
| 	}
 | |
| 
 | |
| 	void mainViewRemoved(
 | |
| 		not_null<HistoryBlock*> block,
 | |
| 		not_null<Element*> view);
 | |
| 	void removeNotification(not_null<HistoryItem*> item);
 | |
| 
 | |
| 	QDateTime adjustChatListDate() const override;
 | |
| 	void changedInChatListHook(Dialogs::Mode list, bool added) override;
 | |
| 	void changedChatListPinHook() override;
 | |
| 
 | |
| 	void setInboxReadTill(MsgId upTo);
 | |
| 	void setOutboxReadTill(MsgId upTo);
 | |
| 
 | |
| 	void applyMessageChanges(
 | |
| 		not_null<HistoryItem*> item,
 | |
| 		const MTPMessage &original);
 | |
| 	void applyServiceChanges(
 | |
| 		not_null<HistoryItem*> item,
 | |
| 		const MTPDmessageService &data);
 | |
| 
 | |
| 	// After adding a new history slice check lastMessage / loadedAtBottom.
 | |
| 	void checkLastMessage();
 | |
| 	void setLastMessage(HistoryItem *item);
 | |
| 
 | |
| 	// Add all items to the unread mentions if we were not loaded at bottom and now are.
 | |
| 	void checkAddAllToUnreadMentions();
 | |
| 
 | |
| 	void addToSharedMedia(const std::vector<not_null<HistoryItem*>> &items);
 | |
| 	void addEdgesToSharedMedia();
 | |
| 
 | |
| 	void addItemsToLists(const std::vector<not_null<HistoryItem*>> &items);
 | |
| 	void clearSendAction(not_null<UserData*> from);
 | |
| 
 | |
| 	HistoryItem *lastAvailableMessage() const;
 | |
| 	void getNextFirstUnreadMessage();
 | |
| 
 | |
| 	// Creates if necessary a new block for adding item.
 | |
| 	// Depending on isBuildingFrontBlock() gets front or back block.
 | |
| 	HistoryBlock *prepareBlockForAddingItem();
 | |
| 
 | |
| 	void viewReplaced(not_null<const Element*> was, Element *now);
 | |
| 
 | |
| 	Flags _flags = 0;
 | |
| 	bool _mute = false;
 | |
| 	int _width = 0;
 | |
| 	int _height = 0;
 | |
| 	Element *_unreadBarView = nullptr;
 | |
| 	Element *_firstUnreadView = nullptr;
 | |
| 	HistoryService *_joinedMessage = nullptr;
 | |
| 	bool _loadedAtTop = false;
 | |
| 	bool _loadedAtBottom = true;
 | |
| 
 | |
| 	base::optional<MsgId> _inboxReadBefore;
 | |
| 	base::optional<MsgId> _outboxReadBefore;
 | |
| 	base::optional<int> _unreadCount;
 | |
| 	base::optional<int> _unreadMentionsCount;
 | |
| 	base::flat_set<MsgId> _unreadMentions;
 | |
| 	base::optional<HistoryItem*> _lastMessage;
 | |
| 
 | |
| 	// A pointer to the block that is currently being built.
 | |
| 	// We hold this pointer so we can destroy it while building
 | |
| 	// and then create a new one if it is necessary.
 | |
| 	struct BuildingBlock {
 | |
| 		int expectedItemsCount = 0; // optimization for block->items.reserve() call
 | |
| 		HistoryBlock *block = nullptr;
 | |
| 	};
 | |
| 	std::unique_ptr<BuildingBlock> _buildingFrontBlock;
 | |
| 
 | |
| 	std::unique_ptr<Data::Draft> _localDraft, _cloudDraft;
 | |
| 	std::unique_ptr<Data::Draft> _editDraft;
 | |
| 	MessageIdsList _forwardDraft;
 | |
| 
 | |
| 	using TypingUsers = QMap<UserData*, TimeMs>;
 | |
| 	TypingUsers _typing;
 | |
| 	using SendActionUsers = QMap<UserData*, SendAction>;
 | |
| 	SendActionUsers _sendActions;
 | |
| 	QString _sendActionString;
 | |
| 	Text _sendActionText;
 | |
| 	Ui::SendActionAnimation _sendActionAnimation;
 | |
| 	QMap<SendAction::Type, TimeMs> _mySendActions;
 | |
| 
 | |
| 	std::weak_ptr<AdminLog::LocalIdManager> _adminLogIdManager;
 | |
| 
 | |
|  };
 | |
| 
 | |
| class HistoryBlock {
 | |
| public:
 | |
| 	using Element = HistoryView::Element;
 | |
| 
 | |
| 	HistoryBlock(not_null<History*> history);
 | |
| 	HistoryBlock(const HistoryBlock &) = delete;
 | |
| 	HistoryBlock &operator=(const HistoryBlock &) = delete;
 | |
| 	~HistoryBlock();
 | |
| 
 | |
| 	std::vector<std::unique_ptr<Element>> messages;
 | |
| 
 | |
| 	void remove(not_null<Element*> view);
 | |
| 	void refreshView(not_null<Element*> view);
 | |
| 
 | |
| 	int resizeGetHeight(int newWidth, bool resizeAllItems);
 | |
| 	int y() const {
 | |
| 		return _y;
 | |
| 	}
 | |
| 	void setY(int y) {
 | |
| 		_y = y;
 | |
| 	}
 | |
| 	int height() const {
 | |
| 		return _height;
 | |
| 	}
 | |
| 	not_null<History*> history() const {
 | |
| 		return _history;
 | |
| 	}
 | |
| 
 | |
| 	HistoryBlock *previousBlock() const {
 | |
| 		Expects(_indexInHistory >= 0);
 | |
| 
 | |
| 		return (_indexInHistory > 0)
 | |
| 			? _history->blocks[_indexInHistory - 1].get()
 | |
| 			: nullptr;
 | |
| 	}
 | |
| 	HistoryBlock *nextBlock() const {
 | |
| 		Expects(_indexInHistory >= 0);
 | |
| 
 | |
| 		return (_indexInHistory + 1 < _history->blocks.size())
 | |
| 			? _history->blocks[_indexInHistory + 1].get()
 | |
| 			: nullptr;
 | |
| 	}
 | |
| 	void setIndexInHistory(int index) {
 | |
| 		_indexInHistory = index;
 | |
| 	}
 | |
| 	int indexInHistory() const {
 | |
| 		Expects(_indexInHistory >= 0);
 | |
| 		Expects(_indexInHistory < _history->blocks.size());
 | |
| 		Expects(_history->blocks[_indexInHistory].get() == this);
 | |
| 
 | |
| 		return _indexInHistory;
 | |
| 	}
 | |
| 
 | |
| protected:
 | |
| 	const not_null<History*> _history;
 | |
| 
 | |
| 	int _y = 0;
 | |
| 	int _height = 0;
 | |
| 	int _indexInHistory = -1;
 | |
| 
 | |
| };
 | 
