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 "window/section_widget.h" 11 #include "window/section_memento.h" 12 #include "history/view/history_view_list_widget.h" 13 #include "data/data_messages.h" 14 #include "base/timer.h" 15 16 class History; 17 enum class SendMediaType; 18 struct SendingAlbum; 19 20 namespace SendMenu { 21 enum class Type; 22 } // namespace SendMenu 23 24 namespace Api { 25 struct SendOptions; 26 } // namespace Api 27 28 namespace Storage { 29 } // namespace Storage 30 31 namespace Ui { 32 class ScrollArea; 33 class PlainShadow; 34 class FlatButton; 35 class HistoryDownButton; 36 class PinnedBar; 37 struct PreparedList; 38 class SendFilesWay; 39 } // namespace Ui 40 41 namespace Profile { 42 class BackButton; 43 } // namespace Profile 44 45 namespace InlineBots { 46 class Result; 47 } // namespace InlineBots 48 49 namespace Data { 50 class RepliesList; 51 } // namespace Data 52 53 namespace HistoryView { 54 55 namespace Controls { 56 struct VoiceToSend; 57 } // namespace Controls 58 59 class Element; 60 class TopBarWidget; 61 class RepliesMemento; 62 class ComposeControls; 63 class SendActionPainter; 64 65 class RepliesWidget final 66 : public Window::SectionWidget 67 , private ListDelegate { 68 public: 69 RepliesWidget( 70 QWidget *parent, 71 not_null<Window::SessionController*> controller, 72 not_null<History*> history, 73 MsgId rootId); 74 ~RepliesWidget(); 75 76 [[nodiscard]] not_null<History*> history() const; 77 Dialogs::RowDescriptor activeChat() const override; 78 bool preventsClose(Fn<void()> &&continueCallback) const override; 79 hasTopBarShadow()80 bool hasTopBarShadow() const override { 81 return true; 82 } 83 84 QPixmap grabForShowAnimation( 85 const Window::SectionSlideParams ¶ms) override; 86 87 bool showInternal( 88 not_null<Window::SectionMemento*> memento, 89 const Window::SectionShow ¶ms) override; 90 std::shared_ptr<Window::SectionMemento> createMemento() override; 91 bool showMessage( 92 PeerId peerId, 93 const Window::SectionShow ¶ms, 94 MsgId messageId) override; 95 96 Window::SectionActionResult sendBotCommand( 97 Bot::SendCommandRequest request) override; 98 99 void setInternalState( 100 const QRect &geometry, 101 not_null<RepliesMemento*> memento); 102 103 // Tabbed selector management. 104 bool pushTabbedSelectorToThirdSection( 105 not_null<PeerData*> peer, 106 const Window::SectionShow ¶ms) override; 107 bool returnTabbedSelector() override; 108 109 // Float player interface. 110 bool floatPlayerHandleWheelEvent(QEvent *e) override; 111 QRect floatPlayerAvailableRect() override; 112 113 // ListDelegate interface. 114 Context listContext() override; 115 void listScrollTo(int top) override; 116 void listCancelRequest() override; 117 void listDeleteRequest() override; 118 rpl::producer<Data::MessagesSlice> listSource( 119 Data::MessagePosition aroundId, 120 int limitBefore, 121 int limitAfter) override; 122 bool listAllowsMultiSelect() override; 123 bool listIsItemGoodForSelection(not_null<HistoryItem*> item) override; 124 bool listIsLessInOrder( 125 not_null<HistoryItem*> first, 126 not_null<HistoryItem*> second) override; 127 void listSelectionChanged(SelectedItems &&items) override; 128 void listVisibleItemsChanged(HistoryItemsList &&items) override; 129 MessagesBarData listMessagesBar( 130 const std::vector<not_null<Element*>> &elements) override; 131 void listContentRefreshed() override; 132 ClickHandlerPtr listDateLink(not_null<Element*> view) override; 133 bool listElementHideReply(not_null<const Element*> view) override; 134 bool listElementShownUnread(not_null<const Element*> view) override; 135 bool listIsGoodForAroundPosition(not_null<const Element*> view) override; 136 void listSendBotCommand( 137 const QString &command, 138 const FullMsgId &context) override; 139 void listHandleViaClick(not_null<UserData*> bot) override; 140 not_null<Ui::ChatTheme*> listChatTheme() override; 141 142 protected: 143 void resizeEvent(QResizeEvent *e) override; 144 void paintEvent(QPaintEvent *e) override; 145 146 void showAnimatedHook( 147 const Window::SectionSlideParams ¶ms) override; 148 void showFinishedHook() override; 149 void doSetInnerFocus() override; 150 151 private: 152 void onScroll(); 153 void updateInnerVisibleArea(); 154 void updateControlsGeometry(); 155 void updateAdaptiveLayout(); 156 void saveState(not_null<RepliesMemento*> memento); 157 void restoreState(not_null<RepliesMemento*> memento); 158 void showAtStart(); 159 void showAtEnd(); 160 void showAtPosition( 161 Data::MessagePosition position, 162 HistoryItem *originItem = nullptr); 163 bool showAtPositionNow( 164 Data::MessagePosition position, 165 HistoryItem *originItem, 166 anim::type animated = anim::type::normal); 167 void finishSending(); 168 169 void setupComposeControls(); 170 171 void setupRoot(); 172 void setupRootView(); 173 void setupDragArea(); 174 void sendReadTillRequest(); 175 void readTill(not_null<HistoryItem*> item); 176 [[nodiscard]] std::optional<int> computeUnreadCountLocally( 177 MsgId afterId) const; 178 179 void setupScrollDownButton(); 180 void scrollDownClicked(); 181 void scrollDownAnimationFinish(); 182 void updateScrollDownVisibility(); 183 void updateScrollDownPosition(); 184 void updatePinnedVisibility(); 185 186 void confirmDeleteSelected(); 187 void confirmForwardSelected(); 188 void clearSelected(); 189 void setPinnedVisibility(bool shown); 190 191 void send(); 192 void send(Api::SendOptions options); 193 void sendVoice(Controls::VoiceToSend &&data); 194 void edit( 195 not_null<HistoryItem*> item, 196 Api::SendOptions options, 197 mtpRequestId *const saveEditMsgRequestId); 198 void chooseAttach(); 199 [[nodiscard]] SendMenu::Type sendMenuType() const; 200 [[nodiscard]] MsgId replyToId() const; 201 [[nodiscard]] HistoryItem *lookupRoot() const; 202 [[nodiscard]] bool computeAreComments() const; 203 [[nodiscard]] std::optional<int> computeUnreadCount() const; 204 void orderWidgets(); 205 206 void pushReplyReturn(not_null<HistoryItem*> item); 207 void computeCurrentReplyReturn(); 208 void calculateNextReplyReturn(); 209 void restoreReplyReturns(const std::vector<MsgId> &list); 210 void checkReplyReturns(); 211 void recountChatWidth(); 212 void replyToMessage(FullMsgId itemId); 213 void refreshTopBarActiveChat(); 214 void refreshUnreadCountBadge(); 215 void reloadUnreadCountIfNeeded(); 216 217 void uploadFile(const QByteArray &fileContent, SendMediaType type); 218 bool confirmSendingFiles( 219 QImage &&image, 220 QByteArray &&content, 221 std::optional<bool> overrideSendImagesAsPhotos = std::nullopt, 222 const QString &insertTextOnCancel = QString()); 223 bool confirmSendingFiles( 224 Ui::PreparedList &&list, 225 const QString &insertTextOnCancel = QString()); 226 bool confirmSendingFiles( 227 not_null<const QMimeData*> data, 228 std::optional<bool> overrideSendImagesAsPhotos = std::nullopt, 229 const QString &insertTextOnCancel = QString()); 230 bool showSendingFilesError(const Ui::PreparedList &list) const; 231 void sendingFilesConfirmed( 232 Ui::PreparedList &&list, 233 Ui::SendFilesWay way, 234 TextWithTags &&caption, 235 Api::SendOptions options, 236 bool ctrlShiftEnter); 237 238 void sendExistingDocument(not_null<DocumentData*> document); 239 bool sendExistingDocument( 240 not_null<DocumentData*> document, 241 Api::SendOptions options); 242 void sendExistingPhoto(not_null<PhotoData*> photo); 243 bool sendExistingPhoto( 244 not_null<PhotoData*> photo, 245 Api::SendOptions options); 246 void sendInlineResult( 247 not_null<InlineBots::Result*> result, 248 not_null<UserData*> bot); 249 void sendInlineResult( 250 not_null<InlineBots::Result*> result, 251 not_null<UserData*> bot, 252 Api::SendOptions options); 253 254 [[nodiscard]] bool showSlowmodeError(); 255 [[nodiscard]] std::optional<QString> writeRestriction() const; 256 257 const not_null<History*> _history; 258 const MsgId _rootId = 0; 259 std::shared_ptr<Ui::ChatTheme> _theme; 260 HistoryItem *_root = nullptr; 261 std::shared_ptr<Data::RepliesList> _replies; 262 rpl::variable<bool> _areComments = false; 263 std::shared_ptr<SendActionPainter> _sendAction; 264 QPointer<ListWidget> _inner; 265 object_ptr<TopBarWidget> _topBar; 266 object_ptr<Ui::PlainShadow> _topBarShadow; 267 std::unique_ptr<ComposeControls> _composeControls; 268 bool _skipScrollEvent = false; 269 270 std::unique_ptr<Ui::PinnedBar> _rootView; 271 int _rootViewHeight = 0; 272 bool _rootViewInited = false; 273 rpl::variable<bool> _rootVisible = false; 274 275 std::unique_ptr<Ui::ScrollArea> _scroll; 276 277 std::vector<MsgId> _replyReturns; 278 HistoryItem *_replyReturn = nullptr; 279 280 Ui::Animations::Simple _scrollDownShown; 281 bool _scrollDownIsShown = false; 282 object_ptr<Ui::HistoryDownButton> _scrollDown; 283 284 bool _choosingAttach = false; 285 286 base::Timer _readRequestTimer; 287 bool _readRequestPending = false; 288 mtpRequestId _readRequestId = 0; 289 290 mtpRequestId _reloadUnreadCountRequestId = 0; 291 bool _loaded = false; 292 293 }; 294 295 296 class RepliesMemento : public Window::SectionMemento { 297 public: 298 RepliesMemento( 299 not_null<History*> history, 300 MsgId rootId, 301 MsgId highlightId = 0) _history(history)302 : _history(history) 303 , _rootId(rootId) 304 , _highlightId(highlightId) { 305 } 306 explicit RepliesMemento( 307 not_null<HistoryItem*> commentsItem, 308 MsgId commentId = 0); 309 310 object_ptr<Window::SectionWidget> createWidget( 311 QWidget *parent, 312 not_null<Window::SessionController*> controller, 313 Window::Column column, 314 const QRect &geometry) override; 315 getHistory()316 [[nodiscard]] not_null<History*> getHistory() const { 317 return _history; 318 } getRootId()319 [[nodiscard]] MsgId getRootId() const { 320 return _rootId; 321 } 322 setReplies(std::shared_ptr<Data::RepliesList> replies)323 void setReplies(std::shared_ptr<Data::RepliesList> replies) { 324 _replies = std::move(replies); 325 } getReplies()326 [[nodiscard]] std::shared_ptr<Data::RepliesList> getReplies() const { 327 return _replies; 328 } 329 setReplyReturns(const std::vector<MsgId> & list)330 void setReplyReturns(const std::vector<MsgId> &list) { 331 _replyReturns = list; 332 } replyReturns()333 const std::vector<MsgId> &replyReturns() const { 334 return _replyReturns; 335 } 336 list()337 [[nodiscard]] not_null<ListMemento*> list() { 338 return &_list; 339 } getHighlightId()340 [[nodiscard]] MsgId getHighlightId() const { 341 return _highlightId; 342 } 343 344 private: 345 const not_null<History*> _history; 346 const MsgId _rootId = 0; 347 const MsgId _highlightId = 0; 348 ListMemento _list; 349 std::shared_ptr<Data::RepliesList> _replies; 350 std::vector<MsgId> _replyReturns; 351 352 }; 353 354 } // namespace HistoryView 355