1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 #include "base/weak_ptr.h"
11 #include "chat_helpers/bot_command.h"
12 #include "ui/rp_widget.h"
13 #include "ui/effects/animations.h"
14 #include "media/player/media_player_float.h"
15 #include "mtproto/sender.h"
16 #include "data/data_pts_waiter.h"
17 
18 struct HistoryMessageMarkupButton;
19 class MainWindow;
20 class HistoryWidget;
21 class StackItem;
22 struct FileLoadResult;
23 class History;
24 class Image;
25 
26 namespace MTP {
27 class Error;
28 } // namespace MTP
29 
30 namespace Api {
31 struct SendAction;
32 struct SendOptions;
33 } // namespace Api
34 
35 namespace SendMenu {
36 enum class Type;
37 } // namespace SendMenu
38 
39 namespace Main {
40 class Session;
41 } // namespace Main
42 
43 namespace Data {
44 class WallPaper;
45 struct ForwardDraft;
46 } // namespace Data
47 
48 namespace Dialogs {
49 struct RowDescriptor;
50 class Row;
51 class Key;
52 class Widget;
53 } // namespace Dialogs
54 
55 namespace Media {
56 namespace Player {
57 class Widget;
58 class VolumeWidget;
59 class Panel;
60 struct TrackState;
61 } // namespace Player
62 } // namespace Media
63 
64 namespace Export {
65 namespace View {
66 class TopBar;
67 class PanelController;
68 struct Content;
69 } // namespace View
70 } // namespace Export
71 
72 namespace Ui {
73 class ConfirmBox;
74 class ResizeArea;
75 class PlainShadow;
76 class DropdownMenu;
77 enum class ReportReason;
78 template <typename Widget>
79 class SlideWrap;
80 } // namespace Ui
81 
82 namespace Window {
83 class SessionController;
84 template <typename Inner>
85 class TopBarWrapWidget;
86 class SectionMemento;
87 class SectionWidget;
88 class AbstractSectionWidget;
89 class ConnectionState;
90 struct SectionSlideParams;
91 struct SectionShow;
92 enum class Column;
93 class HistoryHider;
94 } // namespace Window
95 
96 namespace Calls {
97 class Call;
98 class GroupCall;
99 class TopBar;
100 } // namespace Calls
101 
102 namespace Core {
103 class Changelogs;
104 } // namespace Core
105 
106 namespace InlineBots {
107 namespace Layout {
108 class ItemBase;
109 } // namespace Layout
110 } // namespace InlineBots
111 
112 class MainWidget
113 	: public Ui::RpWidget
114 	, private Media::Player::FloatDelegate
115 	, private base::Subscriber {
116 	Q_OBJECT
117 
118 public:
119 	using SectionShow = Window::SectionShow;
120 
121 	MainWidget(
122 		QWidget *parent,
123 		not_null<Window::SessionController*> controller);
124 	~MainWidget();
125 
126 	[[nodiscard]] Main::Session &session() const;
127 	[[nodiscard]] not_null<Window::SessionController*> controller() const;
128 
129 	[[nodiscard]] bool isMainSectionShown() const;
130 	[[nodiscard]] bool isThirdSectionShown() const;
131 
132 	void returnTabbedSelector();
133 
134 	void showAnimated(const QPixmap &bgAnimCache, bool back = false);
135 
136 	void activate();
137 
138 	void windowShown();
139 
140 	void dialogsToUp();
141 	void checkHistoryActivation();
142 
143 	PeerData *peer();
144 
145 	int backgroundFromY() const;
146 	void showSection(
147 		std::shared_ptr<Window::SectionMemento> memento,
148 		const SectionShow &params);
149 	void updateColumnLayout();
150 	bool stackIsEmpty() const;
151 	void showBackFromStack(
152 		const SectionShow &params);
153 	void orderWidgets();
154 	QRect historyRect() const;
155 	QPixmap grabForShowAnimation(const Window::SectionSlideParams &params);
156 	void checkMainSectionToLayer();
157 
158 	[[nodiscard]] SendMenu::Type sendMenuType() const;
159 	bool sendExistingDocument(not_null<DocumentData*> document);
160 	bool sendExistingDocument(
161 		not_null<DocumentData*> document,
162 		Api::SendOptions options);
163 
164 	bool isActive() const;
165 	[[nodiscard]] bool doWeMarkAsRead() const;
166 
167 	void saveFieldToHistoryLocalDraft();
168 
169 	int32 dlgsWidth() const;
170 
171 	void showForwardLayer(Data::ForwardDraft &&draft);
172 	void showSendPathsLayer();
173 	void shareUrlLayer(const QString &url, const QString &text);
174 	void inlineSwitchLayer(const QString &botAndQuery);
175 	void hiderLayer(base::unique_qptr<Window::HistoryHider> h);
176 	bool setForwardDraft(PeerId peer, Data::ForwardDraft &&draft);
177 	bool shareUrl(
178 		PeerId peerId,
179 		const QString &url,
180 		const QString &text);
181 	bool inlineSwitchChosen(PeerId peerId, const QString &botAndQuery);
182 	bool sendPaths(PeerId peerId);
183 	void onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data);
184 	bool selectingPeer() const;
185 
186 	void sendBotCommand(Bot::SendCommandRequest request);
187 	void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo);
188 	bool insertBotCommand(const QString &cmd);
189 
190 	void searchMessages(const QString &query, Dialogs::Key inChat);
191 
192 	void setChatBackground(
193 		const Data::WallPaper &background,
194 		QImage &&image = QImage());
195 	bool chatBackgroundLoading();
196 	float64 chatBackgroundProgress() const;
197 	void checkChatBackground();
198 	Image *newBackgroundThumb();
199 
200 	// Does offerPeer or showPeerHistory.
201 	void choosePeer(PeerId peerId, MsgId showAtMsgId);
202 	void clearBotStartToken(PeerData *peer);
203 
204 	void ctrlEnterSubmitUpdated();
205 	void setInnerFocus();
206 
207 	bool contentOverlapped(const QRect &globalRect);
208 
209 	void searchInChat(Dialogs::Key chat);
210 
211 	void showChooseReportMessages(
212 		not_null<PeerData*> peer,
213 		Ui::ReportReason reason,
214 		Fn<void(MessageIdsList)> done);
215 	void clearChooseReportMessages();
216 
217 	void toggleChooseChatTheme(not_null<PeerData*> peer);
218 
219 	void ui_showPeerHistory(
220 		PeerId peer,
221 		const SectionShow &params,
222 		MsgId msgId);
223 
224 	bool notify_switchInlineBotButtonReceived(const QString &query, UserData *samePeerBot, MsgId samePeerReplyTo);
225 
226 	using FloatDelegate::floatPlayerAreaUpdated;
227 
228 	void closeBothPlayers();
229 	void stopAndClosePlayer();
230 
231 	bool preventsCloseSection(Fn<void()> callback) const;
232 	bool preventsCloseSection(
233 		Fn<void()> callback,
234 		const SectionShow &params) const;
235 
236 public Q_SLOTS:
237 	void inlineResultLoadProgress(FileLoader *loader);
238 	void inlineResultLoadFailed(FileLoader *loader, bool started);
239 
240 	void dialogsCancelled();
241 
242 protected:
243 	void paintEvent(QPaintEvent *e) override;
244 	void resizeEvent(QResizeEvent *e) override;
245 	void keyPressEvent(QKeyEvent *e) override;
246 	bool eventFilter(QObject *o, QEvent *e) override;
247 
248 private:
249 	void animationCallback();
250 	void handleAdaptiveLayoutUpdate();
251 	void updateWindowAdaptiveLayout();
252 	void handleAudioUpdate(const Media::Player::TrackState &state);
253 	void updateMediaPlayerPosition();
254 	void updateMediaPlaylistPosition(int x);
255 	void updateControlsGeometry();
256 	void updateDialogsWidthAnimated();
257 	void updateThirdColumnToCurrentChat(
258 		Dialogs::Key key,
259 		bool canWrite);
260 	[[nodiscard]] bool saveThirdSectionToStackBack() const;
261 	[[nodiscard]] auto thirdSectionForCurrentMainSection(Dialogs::Key key)
262 		-> std::shared_ptr<Window::SectionMemento>;
263 
264 	void setupConnectingWidget();
265 	void createPlayer();
266 	void playerHeightUpdated();
267 
268 	void setCurrentCall(Calls::Call *call);
269 	void setCurrentGroupCall(Calls::GroupCall *call);
270 	void createCallTopBar();
271 	void destroyCallTopBar();
272 	void callTopBarHeightUpdated(int callTopBarHeight);
273 
274 	void setCurrentExportView(Export::View::PanelController *view);
275 	void createExportTopBar(Export::View::Content &&data);
276 	void destroyExportTopBar();
277 	void exportTopBarHeightUpdated();
278 
279 	Window::SectionSlideParams prepareShowAnimation(
280 		bool willHaveTopBarShadow);
281 	void showNewSection(
282 		std::shared_ptr<Window::SectionMemento> memento,
283 		const SectionShow &params);
284 	void dropMainSection(Window::SectionWidget *widget);
285 
286 	Window::SectionSlideParams prepareThirdSectionAnimation(Window::SectionWidget *section);
287 
288 	// All this methods use the prepareShowAnimation().
289 	Window::SectionSlideParams prepareMainSectionAnimation(Window::SectionWidget *section);
290 	Window::SectionSlideParams prepareHistoryAnimation(PeerId historyPeerId);
291 	Window::SectionSlideParams prepareDialogsAnimation();
292 
293 	void saveSectionInStack();
294 
295 	int getMainSectionTop() const;
296 	int getThirdSectionTop() const;
297 
298 	void hideAll();
299 	void showAll();
300 	void clearHider(not_null<Window::HistoryHider*> instance);
301 
302 	[[nodiscard]] auto floatPlayerDelegate()
303 		-> not_null<Media::Player::FloatDelegate*>;
304 	not_null<Ui::RpWidget*> floatPlayerWidget() override;
305 	not_null<Media::Player::FloatSectionDelegate*> floatPlayerGetSection(
306 		Window::Column column) override;
307 	void floatPlayerEnumerateSections(Fn<void(
308 		not_null<Media::Player::FloatSectionDelegate*> widget,
309 		Window::Column widgetColumn)> callback) override;
310 	bool floatPlayerIsVisible(not_null<HistoryItem*> item) override;
311 	void floatPlayerClosed(FullMsgId itemId);
312 	void floatPlayerDoubleClickEvent(
313 		not_null<const HistoryItem*> item) override;
314 
315 	void refreshResizeAreas();
316 	template <typename MoveCallback, typename FinishCallback>
317 	void createResizeArea(
318 		object_ptr<Ui::ResizeArea> &area,
319 		MoveCallback &&moveCallback,
320 		FinishCallback &&finishCallback);
321 	void ensureFirstColumnResizeAreaCreated();
322 	void ensureThirdColumnResizeAreaCreated();
323 
324 	bool isReadyChatBackground(
325 		const Data::WallPaper &background,
326 		const QImage &image) const;
327 	void setReadyChatBackground(
328 		const Data::WallPaper &background,
329 		QImage &&image);
330 
331 	void handleHistoryBack();
332 
333 	bool isOneColumn() const;
334 	bool isNormalColumn() const;
335 	bool isThreeColumn() const;
336 
337 	const not_null<Window::SessionController*> _controller;
338 
339 	Ui::Animations::Simple _a_show;
340 	bool _showBack = false;
341 	QPixmap _cacheUnder, _cacheOver;
342 
343 	int _dialogsWidth = 0;
344 	int _thirdColumnWidth = 0;
345 	Ui::Animations::Simple _a_dialogsWidth;
346 
347 	object_ptr<Ui::PlainShadow> _sideShadow;
348 	object_ptr<Ui::PlainShadow> _thirdShadow = { nullptr };
349 	object_ptr<Ui::ResizeArea> _firstColumnResizeArea = { nullptr };
350 	object_ptr<Ui::ResizeArea> _thirdColumnResizeArea = { nullptr };
351 	object_ptr<Dialogs::Widget> _dialogs;
352 	object_ptr<HistoryWidget> _history;
353 	object_ptr<Window::SectionWidget> _mainSection = { nullptr };
354 	object_ptr<Window::SectionWidget> _thirdSection = { nullptr };
355 	std::shared_ptr<Window::SectionMemento> _thirdSectionFromStack;
356 	std::unique_ptr<Window::ConnectionState> _connecting;
357 
358 	base::weak_ptr<Calls::Call> _currentCall;
359 	base::weak_ptr<Calls::GroupCall> _currentGroupCall;
360 	rpl::lifetime _currentCallLifetime;
361 	object_ptr<Ui::SlideWrap<Calls::TopBar>> _callTopBar = { nullptr };
362 
363 	Export::View::PanelController *_currentExportView = nullptr;
364 	object_ptr<Window::TopBarWrapWidget<Export::View::TopBar>> _exportTopBar
365 		= { nullptr };
366 	rpl::lifetime _exportViewLifetime;
367 
368 	object_ptr<Window::TopBarWrapWidget<Media::Player::Widget>> _player
369 		= { nullptr };
370 	object_ptr<Media::Player::VolumeWidget> _playerVolume = { nullptr };
371 	object_ptr<Media::Player::Panel> _playerPlaylist;
372 	bool _playerUsingPanel = false;
373 
374 	base::unique_qptr<Window::HistoryHider> _hider;
375 	std::vector<std::unique_ptr<StackItem>> _stack;
376 
377 	int _playerHeight = 0;
378 	int _callTopBarHeight = 0;
379 	int _exportTopBarHeight = 0;
380 	int _contentScrollAddToY = 0;
381 
382 	PhotoData *_deletingPhoto = nullptr;
383 
384 	struct SettingBackground;
385 	std::unique_ptr<SettingBackground> _background;
386 
387 	bool _firstColumnResizing = false;
388 	int _firstColumnResizingShift = 0;
389 
390 	// _changelogs depends on _data, subscribes on chats loading event.
391 	const std::unique_ptr<Core::Changelogs> _changelogs;
392 
393 };
394 
395 namespace App {
396 MainWidget *main();
397 } // namespace App
398