/* 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 "chat_helpers/bot_command.h" #include "ui/rp_widget.h" #include "ui/effects/animations.h" #include "media/player/media_player_float.h" #include "mtproto/sender.h" #include "data/data_pts_waiter.h" struct HistoryMessageMarkupButton; class MainWindow; class HistoryWidget; class StackItem; struct FileLoadResult; class History; class Image; namespace MTP { class Error; } // namespace MTP namespace Api { struct SendAction; struct SendOptions; } // namespace Api namespace SendMenu { enum class Type; } // namespace SendMenu namespace Main { class Session; } // namespace Main namespace Data { class WallPaper; struct ForwardDraft; } // namespace Data namespace Dialogs { struct RowDescriptor; class Row; class Key; class Widget; } // namespace Dialogs namespace Media { namespace Player { class Widget; class Panel; struct TrackState; } // namespace Player } // namespace Media namespace Export { namespace View { class TopBar; class PanelController; struct Content; } // namespace View } // namespace Export namespace Ui { class ConfirmBox; class ResizeArea; class PlainShadow; class DropdownMenu; enum class ReportReason; template class SlideWrap; } // namespace Ui namespace Window { class SessionController; template class TopBarWrapWidget; class SectionMemento; class SectionWidget; class AbstractSectionWidget; class ConnectionState; struct SectionSlideParams; struct SectionShow; enum class Column; class HistoryHider; } // namespace Window namespace Calls { class Call; class GroupCall; class TopBar; } // namespace Calls namespace Core { class Changelogs; } // namespace Core namespace InlineBots { namespace Layout { class ItemBase; } // namespace Layout } // namespace InlineBots class MainWidget : public Ui::RpWidget , private Media::Player::FloatDelegate , private base::Subscriber { Q_OBJECT public: using SectionShow = Window::SectionShow; MainWidget( QWidget *parent, not_null controller); ~MainWidget(); [[nodiscard]] Main::Session &session() const; [[nodiscard]] not_null controller() const; [[nodiscard]] bool isMainSectionShown() const; [[nodiscard]] bool isThirdSectionShown() const; void returnTabbedSelector(); void showAnimated(const QPixmap &bgAnimCache, bool back = false); void activate(); void windowShown(); void dialogsToUp(); void checkHistoryActivation(); PeerData *peer(); int backgroundFromY() const; void showSection( std::shared_ptr memento, const SectionShow ¶ms); void updateColumnLayout(); bool stackIsEmpty() const; void showBackFromStack( const SectionShow ¶ms); void orderWidgets(); QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms); void checkMainSectionToLayer(); [[nodiscard]] SendMenu::Type sendMenuType() const; bool sendExistingDocument(not_null document); bool sendExistingDocument( not_null document, Api::SendOptions options); bool isActive() const; [[nodiscard]] bool doWeMarkAsRead() const; void saveFieldToHistoryLocalDraft(); int32 dlgsWidth() const; void showForwardLayer(Data::ForwardDraft &&draft); void showSendPathsLayer(); void shareUrlLayer(const QString &url, const QString &text); void inlineSwitchLayer(const QString &botAndQuery); void hiderLayer(base::unique_qptr h); bool setForwardDraft(PeerId peer, Data::ForwardDraft &&draft); bool shareUrl( PeerId peerId, const QString &url, const QString &text); bool inlineSwitchChosen(PeerId peerId, const QString &botAndQuery); bool sendPaths(PeerId peerId); void onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data); bool selectingPeer() const; void sendBotCommand(Bot::SendCommandRequest request); void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo); bool insertBotCommand(const QString &cmd); void searchMessages(const QString &query, Dialogs::Key inChat); void setChatBackground( const Data::WallPaper &background, QImage &&image = QImage()); bool chatBackgroundLoading(); float64 chatBackgroundProgress() const; void checkChatBackground(); Image *newBackgroundThumb(); // Does offerPeer or showPeerHistory. void choosePeer(PeerId peerId, MsgId showAtMsgId); void clearBotStartToken(PeerData *peer); void ctrlEnterSubmitUpdated(); void setInnerFocus(); bool contentOverlapped(const QRect &globalRect); void searchInChat(Dialogs::Key chat); void showChooseReportMessages( not_null peer, Ui::ReportReason reason, Fn done); void clearChooseReportMessages(); void toggleChooseChatTheme(not_null peer); void ui_showPeerHistory( PeerId peer, const SectionShow ¶ms, MsgId msgId); bool notify_switchInlineBotButtonReceived(const QString &query, UserData *samePeerBot, MsgId samePeerReplyTo); using FloatDelegate::floatPlayerAreaUpdated; void closeBothPlayers(); void stopAndClosePlayer(); bool preventsCloseSection(Fn callback) const; bool preventsCloseSection( Fn callback, const SectionShow ¶ms) const; public Q_SLOTS: void inlineResultLoadProgress(FileLoader *loader); void inlineResultLoadFailed(FileLoader *loader, bool started); void dialogsCancelled(); protected: void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; bool eventFilter(QObject *o, QEvent *e) override; private: void animationCallback(); void handleAdaptiveLayoutUpdate(); void updateWindowAdaptiveLayout(); void handleAudioUpdate(const Media::Player::TrackState &state); void updateMediaPlaylistPosition(int x); void updateControlsGeometry(); void updateDialogsWidthAnimated(); void updateThirdColumnToCurrentChat( Dialogs::Key key, bool canWrite); [[nodiscard]] bool saveThirdSectionToStackBack() const; [[nodiscard]] auto thirdSectionForCurrentMainSection(Dialogs::Key key) -> std::shared_ptr; void setupConnectingWidget(); void createPlayer(); void playerHeightUpdated(); void setCurrentCall(Calls::Call *call); void setCurrentGroupCall(Calls::GroupCall *call); void createCallTopBar(); void destroyCallTopBar(); void callTopBarHeightUpdated(int callTopBarHeight); void setCurrentExportView(Export::View::PanelController *view); void createExportTopBar(Export::View::Content &&data); void destroyExportTopBar(); void exportTopBarHeightUpdated(); Window::SectionSlideParams prepareShowAnimation( bool willHaveTopBarShadow); void showNewSection( std::shared_ptr memento, const SectionShow ¶ms); void dropMainSection(Window::SectionWidget *widget); Window::SectionSlideParams prepareThirdSectionAnimation(Window::SectionWidget *section); // All this methods use the prepareShowAnimation(). Window::SectionSlideParams prepareMainSectionAnimation(Window::SectionWidget *section); Window::SectionSlideParams prepareHistoryAnimation(PeerId historyPeerId); Window::SectionSlideParams prepareDialogsAnimation(); void saveSectionInStack(); int getMainSectionTop() const; int getThirdSectionTop() const; void hideAll(); void showAll(); void clearHider(not_null instance); [[nodiscard]] auto floatPlayerDelegate() -> not_null; not_null floatPlayerWidget() override; not_null floatPlayerGetSection( Window::Column column) override; void floatPlayerEnumerateSections(Fn widget, Window::Column widgetColumn)> callback) override; bool floatPlayerIsVisible(not_null item) override; void floatPlayerClosed(FullMsgId itemId); void floatPlayerDoubleClickEvent( not_null item) override; void refreshResizeAreas(); template void createResizeArea( object_ptr &area, MoveCallback &&moveCallback, FinishCallback &&finishCallback); void ensureFirstColumnResizeAreaCreated(); void ensureThirdColumnResizeAreaCreated(); bool isReadyChatBackground( const Data::WallPaper &background, const QImage &image) const; void setReadyChatBackground( const Data::WallPaper &background, QImage &&image); void handleHistoryBack(); bool isOneColumn() const; bool isNormalColumn() const; bool isThreeColumn() const; const not_null _controller; Ui::Animations::Simple _a_show; bool _showBack = false; QPixmap _cacheUnder, _cacheOver; int _dialogsWidth = 0; int _thirdColumnWidth = 0; Ui::Animations::Simple _a_dialogsWidth; object_ptr _sideShadow; object_ptr _thirdShadow = { nullptr }; object_ptr _firstColumnResizeArea = { nullptr }; object_ptr _thirdColumnResizeArea = { nullptr }; object_ptr _dialogs; object_ptr _history; object_ptr _mainSection = { nullptr }; object_ptr _thirdSection = { nullptr }; std::shared_ptr _thirdSectionFromStack; std::unique_ptr _connecting; base::weak_ptr _currentCall; base::weak_ptr _currentGroupCall; rpl::lifetime _currentCallLifetime; object_ptr> _callTopBar = { nullptr }; Export::View::PanelController *_currentExportView = nullptr; object_ptr> _exportTopBar = { nullptr }; rpl::lifetime _exportViewLifetime; object_ptr> _player = { nullptr }; object_ptr _playerPlaylist; bool _playerUsingPanel = false; base::unique_qptr _hider; std::vector> _stack; int _playerHeight = 0; int _callTopBarHeight = 0; int _exportTopBarHeight = 0; int _contentScrollAddToY = 0; PhotoData *_deletingPhoto = nullptr; struct SettingBackground; std::unique_ptr _background; bool _firstColumnResizing = false; int _firstColumnResizingShift = 0; // _changelogs depends on _data, subscribes on chats loading event. const std::unique_ptr _changelogs; }; namespace App { MainWidget *main(); } // namespace App