801 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			801 lines
		
	
	
	
		
			23 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 "ui/widgets/tooltip.h"
 | 
						|
#include "mainwidget.h"
 | 
						|
#include "chat_helpers/field_autocomplete.h"
 | 
						|
#include "window/section_widget.h"
 | 
						|
#include "ui/widgets/input_fields.h"
 | 
						|
#include "ui/effects/animations.h"
 | 
						|
#include "ui/rp_widget.h"
 | 
						|
#include "base/flags.h"
 | 
						|
#include "base/timer.h"
 | 
						|
 | 
						|
struct FileLoadResult;
 | 
						|
struct FileMediaInformation;
 | 
						|
struct SendingAlbum;
 | 
						|
enum class SendMediaType;
 | 
						|
enum class CompressConfirm;
 | 
						|
class MessageLinksParser;
 | 
						|
enum class SendMenuType;
 | 
						|
 | 
						|
namespace Api {
 | 
						|
struct SendOptions;
 | 
						|
} // namespace Api
 | 
						|
 | 
						|
namespace InlineBots {
 | 
						|
namespace Layout {
 | 
						|
class ItemBase;
 | 
						|
class Widget;
 | 
						|
} // namespace Layout
 | 
						|
class Result;
 | 
						|
} // namespace InlineBots
 | 
						|
 | 
						|
namespace Data {
 | 
						|
struct Draft;
 | 
						|
} // namespace Data
 | 
						|
 | 
						|
namespace Support {
 | 
						|
class Autocomplete;
 | 
						|
struct Contact;
 | 
						|
} // namespace Support
 | 
						|
 | 
						|
namespace Ui {
 | 
						|
class AbstractButton;
 | 
						|
class InnerDropdown;
 | 
						|
class DropdownMenu;
 | 
						|
class PlainShadow;
 | 
						|
class PopupMenu;
 | 
						|
class IconButton;
 | 
						|
class HistoryDownButton;
 | 
						|
class EmojiButton;
 | 
						|
class SendButton;
 | 
						|
class SilentToggle;
 | 
						|
class FlatButton;
 | 
						|
class LinkButton;
 | 
						|
class RoundButton;
 | 
						|
} // namespace Ui
 | 
						|
 | 
						|
namespace Window {
 | 
						|
class SessionController;
 | 
						|
} // namespace Window
 | 
						|
 | 
						|
namespace ChatHelpers {
 | 
						|
class TabbedPanel;
 | 
						|
class TabbedSection;
 | 
						|
class TabbedSelector;
 | 
						|
} // namespace ChatHelpers
 | 
						|
 | 
						|
namespace Storage {
 | 
						|
enum class MimeDataState;
 | 
						|
struct PreparedList;
 | 
						|
struct UploadedPhoto;
 | 
						|
struct UploadedDocument;
 | 
						|
struct UploadedThumbDocument;
 | 
						|
} // namespace Storage
 | 
						|
 | 
						|
namespace HistoryView {
 | 
						|
class TopBarWidget;
 | 
						|
class ContactStatus;
 | 
						|
} // namespace HistoryView
 | 
						|
 | 
						|
class DragArea;
 | 
						|
class SendFilesBox;
 | 
						|
class BotKeyboard;
 | 
						|
class MessageField;
 | 
						|
class HistoryInner;
 | 
						|
struct HistoryMessageMarkupButton;
 | 
						|
 | 
						|
class HistoryWidget final
 | 
						|
	: public Window::AbstractSectionWidget
 | 
						|
	, public RPCSender {
 | 
						|
	Q_OBJECT
 | 
						|
 | 
						|
public:
 | 
						|
	using FieldHistoryAction = Ui::InputField::HistoryAction;
 | 
						|
 | 
						|
	HistoryWidget(QWidget *parent, not_null<Window::SessionController*> controller);
 | 
						|
 | 
						|
	void start();
 | 
						|
 | 
						|
	void messagesReceived(PeerData *peer, const MTPmessages_Messages &messages, mtpRequestId requestId);
 | 
						|
	void historyLoaded();
 | 
						|
 | 
						|
	void windowShown();
 | 
						|
	bool doWeReadServerHistory() const;
 | 
						|
	bool doWeReadMentions() const;
 | 
						|
	bool skipItemRepaint();
 | 
						|
 | 
						|
	void leaveToChildEvent(QEvent *e, QWidget *child) override;
 | 
						|
	void dragEnterEvent(QDragEnterEvent *e) override;
 | 
						|
	void dragLeaveEvent(QDragLeaveEvent *e) override;
 | 
						|
    void dropEvent(QDropEvent *e) override;
 | 
						|
 | 
						|
	bool isItemCompletelyHidden(HistoryItem *item) const;
 | 
						|
	void updateTopBarSelection();
 | 
						|
 | 
						|
	void loadMessages();
 | 
						|
	void loadMessagesDown();
 | 
						|
	void firstLoadMessages();
 | 
						|
	void delayedShowAt(MsgId showAtMsgId);
 | 
						|
 | 
						|
	void historyToDown(History *history);
 | 
						|
 | 
						|
	QRect historyRect() const;
 | 
						|
 | 
						|
	void updateFieldPlaceholder();
 | 
						|
	void updateStickersByEmoji();
 | 
						|
 | 
						|
	bool confirmSendingFiles(const QStringList &files);
 | 
						|
	bool confirmSendingFiles(not_null<const QMimeData*> data);
 | 
						|
	void sendFileConfirmed(const std::shared_ptr<FileLoadResult> &file,
 | 
						|
		const std::optional<FullMsgId> &oldId = std::nullopt);
 | 
						|
 | 
						|
	void updateControlsVisibility();
 | 
						|
	void updateControlsGeometry();
 | 
						|
 | 
						|
	History *history() const;
 | 
						|
	PeerData *peer() const;
 | 
						|
	void setMsgId(MsgId showAtMsgId);
 | 
						|
	MsgId msgId() const;
 | 
						|
 | 
						|
	bool hasTopBarShadow() const {
 | 
						|
		return peer() != nullptr;
 | 
						|
	}
 | 
						|
	void showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams ¶ms);
 | 
						|
	void finishAnimating();
 | 
						|
 | 
						|
	void doneShow();
 | 
						|
 | 
						|
	QPoint clampMousePosition(QPoint point);
 | 
						|
 | 
						|
	void checkSelectingScroll(QPoint point);
 | 
						|
	void noSelectingScroll();
 | 
						|
 | 
						|
	bool touchScroll(const QPoint &delta);
 | 
						|
 | 
						|
	void enqueueMessageHighlight(not_null<HistoryView::Element*> view);
 | 
						|
	crl::time highlightStartTime(not_null<const HistoryItem*> item) const;
 | 
						|
 | 
						|
	MessageIdsList getSelectedItems() const;
 | 
						|
	void itemEdited(HistoryItem *item);
 | 
						|
 | 
						|
	void updateScrollColors();
 | 
						|
 | 
						|
	void replyToMessage(FullMsgId itemId);
 | 
						|
	void replyToMessage(not_null<HistoryItem*> item);
 | 
						|
	void editMessage(FullMsgId itemId);
 | 
						|
	void editMessage(not_null<HistoryItem*> item);
 | 
						|
	void pinMessage(FullMsgId itemId);
 | 
						|
	void unpinMessage(FullMsgId itemId);
 | 
						|
 | 
						|
	MsgId replyToId() const;
 | 
						|
	void messageDataReceived(ChannelData *channel, MsgId msgId);
 | 
						|
	bool lastForceReplyReplied(const FullMsgId &replyTo) const;
 | 
						|
	bool lastForceReplyReplied() const;
 | 
						|
	bool cancelReply(bool lastKeyboardUsed = false);
 | 
						|
	void cancelEdit();
 | 
						|
	void updateForwarding();
 | 
						|
	void updateForwardingTexts();
 | 
						|
 | 
						|
	void clearReplyReturns();
 | 
						|
	void pushReplyReturn(not_null<HistoryItem*> item);
 | 
						|
	QList<MsgId> replyReturns();
 | 
						|
	void setReplyReturns(PeerId peer, const QList<MsgId> &replyReturns);
 | 
						|
	void calcNextReplyReturn();
 | 
						|
 | 
						|
	void updatePreview();
 | 
						|
	void previewCancel();
 | 
						|
 | 
						|
	bool recordingAnimationCallback(crl::time now);
 | 
						|
	void stopRecording(bool send);
 | 
						|
 | 
						|
	void escape();
 | 
						|
 | 
						|
	void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo);
 | 
						|
	void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo);
 | 
						|
	bool insertBotCommand(const QString &cmd);
 | 
						|
 | 
						|
	bool eventFilter(QObject *obj, QEvent *e) override;
 | 
						|
 | 
						|
	// With force=true the markup is updated even if it is
 | 
						|
	// already shown for the passed history item.
 | 
						|
	void updateBotKeyboard(History *h = nullptr, bool force = false);
 | 
						|
 | 
						|
	void fastShowAtEnd(not_null<History*> history);
 | 
						|
	void applyDraft(
 | 
						|
		FieldHistoryAction fieldHistoryAction = FieldHistoryAction::Clear);
 | 
						|
	void showHistory(const PeerId &peer, MsgId showAtMsgId, bool reload = false);
 | 
						|
	void clearDelayedShowAt();
 | 
						|
	void clearAllLoadRequests();
 | 
						|
	void saveFieldToHistoryLocalDraft();
 | 
						|
 | 
						|
	void applyCloudDraft(History *history);
 | 
						|
 | 
						|
	void updateHistoryDownPosition();
 | 
						|
	void updateHistoryDownVisibility();
 | 
						|
	void updateUnreadMentionsPosition();
 | 
						|
	void updateUnreadMentionsVisibility();
 | 
						|
 | 
						|
	void updateFieldSubmitSettings();
 | 
						|
 | 
						|
	void setInnerFocus();
 | 
						|
 | 
						|
	void updateNotifyControls();
 | 
						|
 | 
						|
	bool contentOverlapped(const QRect &globalRect);
 | 
						|
 | 
						|
	QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms);
 | 
						|
 | 
						|
	void forwardSelected();
 | 
						|
	void confirmDeleteSelected();
 | 
						|
	void clearSelected();
 | 
						|
 | 
						|
	bool sendExistingDocument(not_null<DocumentData*> document);
 | 
						|
	bool sendExistingPhoto(not_null<PhotoData*> photo);
 | 
						|
 | 
						|
	// Tabbed selector management.
 | 
						|
	void pushTabbedSelectorToThirdSection(
 | 
						|
		const Window::SectionShow ¶ms) override;
 | 
						|
	bool returnTabbedSelector() override;
 | 
						|
 | 
						|
	// Float player interface.
 | 
						|
	bool wheelEventFromFloatPlayer(QEvent *e) override;
 | 
						|
	QRect rectForFloatPlayer() const override;
 | 
						|
 | 
						|
	void app_sendBotCallback(
 | 
						|
		not_null<const HistoryMessageMarkupButton*> button,
 | 
						|
		not_null<const HistoryItem*> msg,
 | 
						|
		int row,
 | 
						|
		int column);
 | 
						|
 | 
						|
	PeerData *ui_getPeerForMouseAction();
 | 
						|
 | 
						|
	void notify_botCommandsChanged(UserData *user);
 | 
						|
	void notify_inlineBotRequesting(bool requesting);
 | 
						|
	void notify_replyMarkupUpdated(const HistoryItem *item);
 | 
						|
	void notify_inlineKeyboardMoved(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop);
 | 
						|
	bool notify_switchInlineBotButtonReceived(const QString &query, UserData *samePeerBot, MsgId samePeerReplyTo);
 | 
						|
	void notify_userIsBotChanged(UserData *user);
 | 
						|
 | 
						|
	~HistoryWidget();
 | 
						|
 | 
						|
protected:
 | 
						|
	void resizeEvent(QResizeEvent *e) override;
 | 
						|
	void keyPressEvent(QKeyEvent *e) override;
 | 
						|
	void mousePressEvent(QMouseEvent *e) override;
 | 
						|
	void paintEvent(QPaintEvent *e) override;
 | 
						|
	void leaveEventHook(QEvent *e) override;
 | 
						|
	void mouseReleaseEvent(QMouseEvent *e) override;
 | 
						|
	void mouseMoveEvent(QMouseEvent *e) override;
 | 
						|
 | 
						|
signals:
 | 
						|
	void cancelled();
 | 
						|
 | 
						|
public slots:
 | 
						|
	void onScroll();
 | 
						|
 | 
						|
	void onBroadcastSilentChange();
 | 
						|
 | 
						|
	void activate();
 | 
						|
	void onTextChange();
 | 
						|
 | 
						|
	void onFieldTabbed();
 | 
						|
 | 
						|
	void onWindowVisibleChanged();
 | 
						|
 | 
						|
	void onFieldFocused();
 | 
						|
	void onFieldResize();
 | 
						|
	void onCheckFieldAutocomplete();
 | 
						|
	void onScrollTimer();
 | 
						|
 | 
						|
	void onDraftSaveDelayed();
 | 
						|
	void onDraftSave(bool delayed = false);
 | 
						|
	void onCloudDraftSave();
 | 
						|
 | 
						|
	void onRecordError();
 | 
						|
	void onRecordDone(QByteArray result, VoiceWaveform waveform, qint32 samples);
 | 
						|
	void onRecordUpdate(quint16 level, qint32 samples);
 | 
						|
 | 
						|
	void onUpdateHistoryItems();
 | 
						|
 | 
						|
	// checks if we are too close to the top or to the bottom
 | 
						|
	// in the scroll area and preloads history if needed
 | 
						|
	void preloadHistoryIfNeeded();
 | 
						|
 | 
						|
private slots:
 | 
						|
	void onHashtagOrBotCommandInsert(QString str, FieldAutocomplete::ChooseMethod method);
 | 
						|
	void onMentionInsert(UserData *user);
 | 
						|
	void onInlineBotCancel();
 | 
						|
	void onMembersDropdownShow();
 | 
						|
 | 
						|
	void onModerateKeyActivate(int index, bool *outHandled);
 | 
						|
 | 
						|
private:
 | 
						|
	using TabbedPanel = ChatHelpers::TabbedPanel;
 | 
						|
	using TabbedSelector = ChatHelpers::TabbedSelector;
 | 
						|
	using DragState = Storage::MimeDataState;
 | 
						|
	struct BotCallbackInfo {
 | 
						|
		UserData *bot;
 | 
						|
		FullMsgId msgId;
 | 
						|
		int row, col;
 | 
						|
		bool game;
 | 
						|
	};
 | 
						|
	struct PinnedBar {
 | 
						|
		PinnedBar(MsgId msgId, HistoryWidget *parent);
 | 
						|
		~PinnedBar();
 | 
						|
 | 
						|
		MsgId msgId = 0;
 | 
						|
		HistoryItem *msg = nullptr;
 | 
						|
		Ui::Text::String text;
 | 
						|
		object_ptr<Ui::IconButton> cancel;
 | 
						|
		object_ptr<Ui::PlainShadow> shadow;
 | 
						|
	};
 | 
						|
	enum ScrollChangeType {
 | 
						|
		ScrollChangeNone,
 | 
						|
 | 
						|
		// When we toggle a pinned message.
 | 
						|
		ScrollChangeAdd,
 | 
						|
 | 
						|
		// When loading a history part while scrolling down.
 | 
						|
		ScrollChangeNoJumpToBottom,
 | 
						|
	};
 | 
						|
	struct ScrollChange {
 | 
						|
		ScrollChangeType type;
 | 
						|
		int value;
 | 
						|
	};
 | 
						|
	enum class TextUpdateEvent {
 | 
						|
		SaveDraft = (1 << 0),
 | 
						|
		SendTyping = (1 << 1),
 | 
						|
	};
 | 
						|
	using TextUpdateEvents = base::flags<TextUpdateEvent>;
 | 
						|
	friend inline constexpr bool is_flag_type(TextUpdateEvent) { return true; };
 | 
						|
 | 
						|
	void initTabbedSelector();
 | 
						|
	void refreshTabbedPanel();
 | 
						|
	void createTabbedPanel();
 | 
						|
	void setTabbedPanel(std::unique_ptr<TabbedPanel> panel);
 | 
						|
	void updateField();
 | 
						|
 | 
						|
	void send(Api::SendOptions options);
 | 
						|
	void sendWithModifiers(Qt::KeyboardModifiers modifiers);
 | 
						|
	void sendSilent();
 | 
						|
	void sendScheduled();
 | 
						|
	[[nodiscard]] SendMenuType sendMenuType() const;
 | 
						|
	void handlePendingHistoryUpdate();
 | 
						|
	void fullPeerUpdated(PeerData *peer);
 | 
						|
	void toggleTabbedSelectorMode();
 | 
						|
	void recountChatWidth();
 | 
						|
	void historyDownClicked();
 | 
						|
	void showNextUnreadMention();
 | 
						|
	void handlePeerUpdate();
 | 
						|
	void setMembersShowAreaActive(bool active);
 | 
						|
	void handleHistoryChange(not_null<const History*> history);
 | 
						|
	void refreshAboutProxyPromotion();
 | 
						|
	void unreadCountUpdated();
 | 
						|
 | 
						|
	[[nodiscard]] int computeMaxFieldHeight() const;
 | 
						|
	void toggleMuteUnmute();
 | 
						|
	void toggleKeyboard(bool manual = true);
 | 
						|
	void startBotCommand();
 | 
						|
	void hidePinnedMessage();
 | 
						|
	void cancelFieldAreaState();
 | 
						|
	void unblockUser();
 | 
						|
	void sendBotStartCommand();
 | 
						|
	void joinChannel();
 | 
						|
	void goToDiscussionGroup();
 | 
						|
 | 
						|
	[[nodiscard]] bool hasDiscussionGroup() const;
 | 
						|
 | 
						|
	void supportInitAutocomplete();
 | 
						|
	void supportInsertText(const QString &text);
 | 
						|
	void supportShareContact(Support::Contact contact);
 | 
						|
 | 
						|
	void highlightMessage(MsgId universalMessageId);
 | 
						|
	void checkNextHighlight();
 | 
						|
	void updateHighlightedMessage();
 | 
						|
	void clearHighlightMessages();
 | 
						|
	void stopMessageHighlight();
 | 
						|
 | 
						|
	void updateSendAction(
 | 
						|
		not_null<History*> history,
 | 
						|
		SendAction::Type type,
 | 
						|
		int32 progress = 0);
 | 
						|
	void cancelSendAction(
 | 
						|
		not_null<History*> history,
 | 
						|
		SendAction::Type type);
 | 
						|
	void cancelTypingAction();
 | 
						|
	void sendActionDone(const MTPBool &result, mtpRequestId req);
 | 
						|
 | 
						|
	void animationCallback();
 | 
						|
	void updateOverStates(QPoint pos);
 | 
						|
	void recordStartCallback();
 | 
						|
	void recordStopCallback(bool active);
 | 
						|
	void recordUpdateCallback(QPoint globalPos);
 | 
						|
	void chooseAttach();
 | 
						|
	void historyDownAnimationFinish();
 | 
						|
	void unreadMentionsAnimationFinish();
 | 
						|
	void sendButtonClicked();
 | 
						|
	void unreadMessageAdded(not_null<HistoryItem*> item);
 | 
						|
 | 
						|
	bool canSendFiles(not_null<const QMimeData*> data) const;
 | 
						|
	bool confirmSendingFiles(
 | 
						|
		const QStringList &files,
 | 
						|
		CompressConfirm compressed,
 | 
						|
		const QString &insertTextOnCancel = QString());
 | 
						|
	bool confirmSendingFiles(
 | 
						|
		QImage &&image,
 | 
						|
		QByteArray &&content,
 | 
						|
		CompressConfirm compressed,
 | 
						|
		const QString &insertTextOnCancel = QString());
 | 
						|
	bool confirmSendingFiles(
 | 
						|
		not_null<const QMimeData*> data,
 | 
						|
		CompressConfirm compressed,
 | 
						|
		const QString &insertTextOnCancel = QString());
 | 
						|
	bool confirmSendingFiles(
 | 
						|
		Storage::PreparedList &&list,
 | 
						|
		CompressConfirm compressed,
 | 
						|
		const QString &insertTextOnCancel = QString());
 | 
						|
	bool showSendingFilesError(const Storage::PreparedList &list) const;
 | 
						|
 | 
						|
	void uploadFile(const QByteArray &fileContent, SendMediaType type);
 | 
						|
 | 
						|
	void uploadFilesAfterConfirmation(
 | 
						|
		Storage::PreparedList &&list,
 | 
						|
		SendMediaType type,
 | 
						|
		TextWithTags &&caption,
 | 
						|
		MsgId replyTo,
 | 
						|
		Api::SendOptions options,
 | 
						|
		std::shared_ptr<SendingAlbum> album = nullptr);
 | 
						|
 | 
						|
	void subscribeToUploader();
 | 
						|
 | 
						|
	void photoUploaded(
 | 
						|
		const FullMsgId &msgId,
 | 
						|
		Api::SendOptions options,
 | 
						|
		const MTPInputFile &file);
 | 
						|
	void photoProgress(const FullMsgId &msgId);
 | 
						|
	void photoFailed(const FullMsgId &msgId);
 | 
						|
	void documentUploaded(
 | 
						|
		const FullMsgId &msgId,
 | 
						|
		Api::SendOptions options,
 | 
						|
		const MTPInputFile &file);
 | 
						|
	void thumbDocumentUploaded(
 | 
						|
		const FullMsgId &msgId,
 | 
						|
		Api::SendOptions options,
 | 
						|
		const MTPInputFile &file,
 | 
						|
		const MTPInputFile &thumb,
 | 
						|
		bool edit = false);
 | 
						|
	void documentProgress(const FullMsgId &msgId);
 | 
						|
	void documentFailed(const FullMsgId &msgId);
 | 
						|
 | 
						|
	void documentEdited(
 | 
						|
		const FullMsgId &msgId,
 | 
						|
		Api::SendOptions options,
 | 
						|
		const MTPInputFile &file);
 | 
						|
 | 
						|
	void photoEdited(
 | 
						|
		const FullMsgId &msgId,
 | 
						|
		Api::SendOptions options,
 | 
						|
		const MTPInputFile &file);
 | 
						|
 | 
						|
	void itemRemoved(not_null<const HistoryItem*> item);
 | 
						|
 | 
						|
	// Updates position of controls around the message field,
 | 
						|
	// like send button, emoji button and others.
 | 
						|
	void moveFieldControls();
 | 
						|
	void updateFieldSize();
 | 
						|
 | 
						|
	bool canWriteMessage() const;
 | 
						|
	std::optional<QString> writeRestriction() const;
 | 
						|
	void orderWidgets();
 | 
						|
 | 
						|
	void clearInlineBot();
 | 
						|
	void inlineBotChanged();
 | 
						|
 | 
						|
	// Look in the _field for the inline bot and query string.
 | 
						|
	void updateInlineBotQuery();
 | 
						|
 | 
						|
	// Request to show results in the emoji panel.
 | 
						|
	void applyInlineBotQuery(UserData *bot, const QString &query);
 | 
						|
 | 
						|
	void cancelReplyAfterMediaSend(bool lastKeyboardUsed);
 | 
						|
	void replyToPreviousMessage();
 | 
						|
	void replyToNextMessage();
 | 
						|
	[[nodiscard]] bool showSlowmodeError();
 | 
						|
 | 
						|
	void hideSelectorControlsAnimated();
 | 
						|
	int countMembersDropdownHeightMax() const;
 | 
						|
 | 
						|
	void updateReplyToName();
 | 
						|
	void checkForwardingInfo();
 | 
						|
	bool editingMessage() const {
 | 
						|
		return _editMsgId != 0;
 | 
						|
	}
 | 
						|
	bool jumpToDialogRow(const Dialogs::RowDescriptor &to);
 | 
						|
 | 
						|
	void setupShortcuts();
 | 
						|
	bool showNextChat();
 | 
						|
	bool showPreviousChat();
 | 
						|
 | 
						|
	void handlePeerMigration();
 | 
						|
 | 
						|
	void updateReplyEditTexts(bool force = false);
 | 
						|
	void updateReplyEditText(not_null<HistoryItem*> item);
 | 
						|
 | 
						|
	void updatePinnedBar(bool force = false);
 | 
						|
	bool pinnedMsgVisibilityUpdated();
 | 
						|
	void destroyPinnedBar();
 | 
						|
	void unpinDone(const MTPUpdates &updates);
 | 
						|
 | 
						|
	void sendInlineResult(
 | 
						|
		not_null<InlineBots::Result*> result,
 | 
						|
		not_null<UserData*> bot);
 | 
						|
 | 
						|
	void drawField(Painter &p, const QRect &rect);
 | 
						|
	void paintEditHeader(
 | 
						|
		Painter &p,
 | 
						|
		const QRect &rect,
 | 
						|
		int left,
 | 
						|
		int top) const;
 | 
						|
	void drawRecording(Painter &p, float64 recordActive);
 | 
						|
	void drawPinnedBar(Painter &p);
 | 
						|
	void drawRestrictedWrite(Painter &p, const QString &error);
 | 
						|
	bool paintShowAnimationFrame();
 | 
						|
 | 
						|
	void updateMouseTracking();
 | 
						|
 | 
						|
	// destroys _history and _migrated unread bars
 | 
						|
	void destroyUnreadBar();
 | 
						|
 | 
						|
	void saveEditMsg();
 | 
						|
	void saveEditMsgDone(History *history, const MTPUpdates &updates, mtpRequestId req);
 | 
						|
	bool saveEditMsgFail(History *history, const RPCError &error, mtpRequestId req);
 | 
						|
 | 
						|
	void checkPreview();
 | 
						|
	void requestPreview();
 | 
						|
	void gotPreview(QString links, const MTPMessageMedia &media, mtpRequestId req);
 | 
						|
	bool messagesFailed(const RPCError &error, mtpRequestId requestId);
 | 
						|
	void addMessagesToFront(PeerData *peer, const QVector<MTPMessage> &messages);
 | 
						|
	void addMessagesToBack(PeerData *peer, const QVector<MTPMessage> &messages);
 | 
						|
 | 
						|
	void botCallbackDone(BotCallbackInfo info, const MTPmessages_BotCallbackAnswer &answer, mtpRequestId req);
 | 
						|
	bool botCallbackFail(BotCallbackInfo info, const RPCError &error, mtpRequestId req);
 | 
						|
 | 
						|
	void updateHistoryGeometry(bool initial = false, bool loadedDown = false, const ScrollChange &change = { ScrollChangeNone, 0 });
 | 
						|
	void updateListSize();
 | 
						|
 | 
						|
	// Does any of the shown histories has this flag set.
 | 
						|
	bool hasPendingResizedItems() const;
 | 
						|
 | 
						|
	// Counts scrollTop for placing the scroll right at the unread
 | 
						|
	// messages bar, choosing from _history and _migrated unreadBar.
 | 
						|
	std::optional<int> unreadBarTop() const;
 | 
						|
	int itemTopForHighlight(not_null<HistoryView::Element*> view) const;
 | 
						|
	void scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId);
 | 
						|
	HistoryView::Element *firstUnreadMessage() const;
 | 
						|
 | 
						|
	// Scroll to current y without updating the _lastUserScrolled time.
 | 
						|
	// Used to distinguish between user scrolls and syntetic scrolls.
 | 
						|
	// This one is syntetic.
 | 
						|
	void synteticScrollToY(int y);
 | 
						|
 | 
						|
	void countHistoryShowFrom();
 | 
						|
 | 
						|
	void writeDrafts(Data::Draft **localDraft, Data::Draft **editDraft);
 | 
						|
	void writeDrafts(History *history);
 | 
						|
	void setFieldText(
 | 
						|
		const TextWithTags &textWithTags,
 | 
						|
		TextUpdateEvents events = 0,
 | 
						|
		FieldHistoryAction fieldHistoryAction = FieldHistoryAction::Clear);
 | 
						|
	void clearFieldText(
 | 
						|
		TextUpdateEvents events = 0,
 | 
						|
		FieldHistoryAction fieldHistoryAction = FieldHistoryAction::Clear);
 | 
						|
 | 
						|
	HistoryItem *getItemFromHistoryOrMigrated(MsgId genericMsgId) const;
 | 
						|
	void animatedScrollToItem(MsgId msgId);
 | 
						|
	void animatedScrollToY(int scrollTo, HistoryItem *attachTo = nullptr);
 | 
						|
 | 
						|
	void updateDragAreas();
 | 
						|
 | 
						|
	// when scroll position or scroll area size changed this method
 | 
						|
	// updates the boundings of the visible area in HistoryInner
 | 
						|
	void visibleAreaUpdated();
 | 
						|
	int countInitialScrollTop();
 | 
						|
	int countAutomaticScrollTop();
 | 
						|
	void preloadHistoryByScroll();
 | 
						|
	void checkReplyReturns();
 | 
						|
	void scrollToAnimationCallback(FullMsgId attachToId, int relativeTo);
 | 
						|
 | 
						|
	bool readyToForward() const;
 | 
						|
	bool hasSilentToggle() const;
 | 
						|
 | 
						|
	void handleSupportSwitch(not_null<History*> updated);
 | 
						|
 | 
						|
	void inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result);
 | 
						|
	bool inlineBotResolveFail(QString name, const RPCError &error);
 | 
						|
 | 
						|
	bool isBotStart() const;
 | 
						|
	bool isBlocked() const;
 | 
						|
	bool isJoinChannel() const;
 | 
						|
	bool isMuteUnmute() const;
 | 
						|
	bool updateCmdStartShown();
 | 
						|
	void updateSendButtonType();
 | 
						|
	bool showRecordButton() const;
 | 
						|
	bool showInlineBotCancel() const;
 | 
						|
	void refreshSilentToggle();
 | 
						|
 | 
						|
	void setupScheduledToggle();
 | 
						|
	void refreshScheduledToggle();
 | 
						|
 | 
						|
	MsgId _replyToId = 0;
 | 
						|
	Ui::Text::String _replyToName;
 | 
						|
	int _replyToNameVersion = 0;
 | 
						|
 | 
						|
	HistoryItemsList _toForward;
 | 
						|
	Ui::Text::String _toForwardFrom, _toForwardText;
 | 
						|
	int _toForwardNameVersion = 0;
 | 
						|
 | 
						|
	MsgId _editMsgId = 0;
 | 
						|
 | 
						|
	HistoryItem *_replyEditMsg = nullptr;
 | 
						|
	Ui::Text::String _replyEditMsgText;
 | 
						|
	mutable base::Timer _updateEditTimeLeftDisplay;
 | 
						|
 | 
						|
	object_ptr<Ui::IconButton> _fieldBarCancel;
 | 
						|
 | 
						|
	std::unique_ptr<PinnedBar> _pinnedBar;
 | 
						|
 | 
						|
	mtpRequestId _saveEditMsgRequestId = 0;
 | 
						|
 | 
						|
	QStringList _parsedLinks;
 | 
						|
	QString _previewLinks;
 | 
						|
	WebPageData *_previewData = nullptr;
 | 
						|
	typedef QMap<QString, WebPageId> PreviewCache;
 | 
						|
	PreviewCache _previewCache;
 | 
						|
	mtpRequestId _previewRequest = 0;
 | 
						|
	Ui::Text::String _previewTitle;
 | 
						|
	Ui::Text::String _previewDescription;
 | 
						|
	base::Timer _previewTimer;
 | 
						|
	bool _previewCancelled = false;
 | 
						|
 | 
						|
	bool _replyForwardPressed = false;
 | 
						|
 | 
						|
	HistoryItem *_replyReturn = nullptr;
 | 
						|
	QList<MsgId> _replyReturns;
 | 
						|
 | 
						|
	PeerData *_peer = nullptr;
 | 
						|
 | 
						|
	ChannelId _channel = NoChannel;
 | 
						|
	bool _canSendMessages = false;
 | 
						|
	MsgId _showAtMsgId = ShowAtUnreadMsgId;
 | 
						|
 | 
						|
	mtpRequestId _firstLoadRequest = 0;
 | 
						|
	mtpRequestId _preloadRequest = 0;
 | 
						|
	mtpRequestId _preloadDownRequest = 0;
 | 
						|
 | 
						|
	MsgId _delayedShowAtMsgId = -1;
 | 
						|
	mtpRequestId _delayedShowAtRequest = 0;
 | 
						|
 | 
						|
	object_ptr<HistoryView::TopBarWidget> _topBar;
 | 
						|
	object_ptr<Ui::ScrollArea> _scroll;
 | 
						|
	QPointer<HistoryInner> _list;
 | 
						|
	History *_migrated = nullptr;
 | 
						|
	History *_history = nullptr;
 | 
						|
	// Initial updateHistoryGeometry() was called.
 | 
						|
	bool _historyInited = false;
 | 
						|
	// If updateListSize() was called without updateHistoryGeometry().
 | 
						|
	bool _updateHistoryGeometryRequired = false;
 | 
						|
	int _addToScroll = 0;
 | 
						|
 | 
						|
	int _lastScrollTop = 0; // gifs optimization
 | 
						|
	crl::time _lastScrolled = 0;
 | 
						|
	QTimer _updateHistoryItems;
 | 
						|
 | 
						|
	crl::time _lastUserScrolled = 0;
 | 
						|
	bool _synteticScrollEvent = false;
 | 
						|
	Ui::Animations::Simple _scrollToAnimation;
 | 
						|
 | 
						|
	Ui::Animations::Simple _historyDownShown;
 | 
						|
	bool _historyDownIsShown = false;
 | 
						|
	object_ptr<Ui::HistoryDownButton> _historyDown;
 | 
						|
 | 
						|
	Ui::Animations::Simple _unreadMentionsShown;
 | 
						|
	bool _unreadMentionsIsShown = false;
 | 
						|
	object_ptr<Ui::HistoryDownButton> _unreadMentions;
 | 
						|
 | 
						|
	object_ptr<FieldAutocomplete> _fieldAutocomplete;
 | 
						|
	object_ptr<Support::Autocomplete> _supportAutocomplete;
 | 
						|
	std::unique_ptr<MessageLinksParser> _fieldLinksParser;
 | 
						|
 | 
						|
	UserData *_inlineBot = nullptr;
 | 
						|
	QString _inlineBotUsername;
 | 
						|
	bool _inlineLookingUpBot = false;
 | 
						|
	mtpRequestId _inlineBotResolveRequestId = 0;
 | 
						|
	bool _isInlineBot = false;
 | 
						|
 | 
						|
	std::unique_ptr<HistoryView::ContactStatus> _contactStatus;
 | 
						|
 | 
						|
	object_ptr<Ui::SendButton> _send;
 | 
						|
	object_ptr<Ui::FlatButton> _unblock;
 | 
						|
	object_ptr<Ui::FlatButton> _botStart;
 | 
						|
	object_ptr<Ui::FlatButton> _joinChannel;
 | 
						|
	object_ptr<Ui::FlatButton> _muteUnmute;
 | 
						|
	object_ptr<Ui::FlatButton> _discuss;
 | 
						|
	object_ptr<Ui::RpWidget> _aboutProxyPromotion = { nullptr };
 | 
						|
	object_ptr<Ui::IconButton> _attachToggle;
 | 
						|
	object_ptr<Ui::EmojiButton> _tabbedSelectorToggle;
 | 
						|
	object_ptr<Ui::IconButton> _botKeyboardShow;
 | 
						|
	object_ptr<Ui::IconButton> _botKeyboardHide;
 | 
						|
	object_ptr<Ui::IconButton> _botCommandStart;
 | 
						|
	object_ptr<Ui::SilentToggle> _silent = { nullptr };
 | 
						|
	object_ptr<Ui::IconButton> _scheduled = { nullptr };
 | 
						|
	bool _cmdStartShown = false;
 | 
						|
	object_ptr<Ui::InputField> _field;
 | 
						|
	bool _recording = false;
 | 
						|
	bool _inField = false;
 | 
						|
	bool _inReplyEditForward = false;
 | 
						|
	bool _inPinnedMsg = false;
 | 
						|
	bool _inClickable = false;
 | 
						|
	int _recordingSamples = 0;
 | 
						|
	int _recordCancelWidth;
 | 
						|
 | 
						|
	rpl::lifetime _uploaderSubscriptions;
 | 
						|
 | 
						|
	// This can animate for a very long time (like in music playing),
 | 
						|
	// so it should be a Basic, not a Simple animation.
 | 
						|
	Ui::Animations::Basic _recordingAnimation;
 | 
						|
	anim::value _recordingLevel;
 | 
						|
 | 
						|
	bool kbWasHidden() const;
 | 
						|
 | 
						|
	bool _kbShown = false;
 | 
						|
	HistoryItem *_kbReplyTo = nullptr;
 | 
						|
	object_ptr<Ui::ScrollArea> _kbScroll;
 | 
						|
	QPointer<BotKeyboard> _keyboard;
 | 
						|
 | 
						|
	object_ptr<Ui::InnerDropdown> _membersDropdown = { nullptr };
 | 
						|
	QTimer _membersDropdownShowTimer;
 | 
						|
 | 
						|
	object_ptr<InlineBots::Layout::Widget> _inlineResults = { nullptr };
 | 
						|
	std::unique_ptr<TabbedPanel> _tabbedPanel;
 | 
						|
	DragState _attachDragState;
 | 
						|
	object_ptr<DragArea> _attachDragDocument, _attachDragPhoto;
 | 
						|
 | 
						|
	Fn<void()> _raiseEmojiSuggestions;
 | 
						|
 | 
						|
	bool _nonEmptySelection = false;
 | 
						|
 | 
						|
	TextUpdateEvents _textUpdateEvents = (TextUpdateEvents() | TextUpdateEvent::SaveDraft | TextUpdateEvent::SendTyping);
 | 
						|
 | 
						|
	QString _confirmSource;
 | 
						|
 | 
						|
	Ui::Animations::Simple _a_show;
 | 
						|
	Window::SlideDirection _showDirection;
 | 
						|
	QPixmap _cacheUnder, _cacheOver;
 | 
						|
 | 
						|
	QTimer _scrollTimer;
 | 
						|
	int32 _scrollDelta = 0;
 | 
						|
 | 
						|
	MsgId _highlightedMessageId = 0;
 | 
						|
	std::deque<MsgId> _highlightQueue;
 | 
						|
	base::Timer _highlightTimer;
 | 
						|
	crl::time _highlightStart = 0;
 | 
						|
 | 
						|
	QMap<QPair<not_null<History*>, SendAction::Type>, mtpRequestId> _sendActionRequests;
 | 
						|
	base::Timer _sendActionStopTimer;
 | 
						|
 | 
						|
	crl::time _saveDraftStart = 0;
 | 
						|
	bool _saveDraftText = false;
 | 
						|
	QTimer _saveDraftTimer, _saveCloudDraftTimer;
 | 
						|
 | 
						|
	object_ptr<Ui::PlainShadow> _topShadow;
 | 
						|
	bool _inGrab = false;
 | 
						|
 | 
						|
};
 |