diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 614ebac0c..49534db40 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -68,6 +68,7 @@ History::History(not_null owner, PeerId peerId) : Entry(owner, Type::History) , peer(owner->peer(peerId)) , cloudDraftTextCache(st::dialogsTextWidthMin) +, _delegateMixin(HistoryInner::DelegateMixin()) , _mute(owner->notifyIsMuted(peer)) , _chatListNameSortKey(owner->nameSortKey(peer->name)) , _sendActionPainter(this) { @@ -1244,8 +1245,7 @@ void History::addItemToBlock(not_null item) { auto block = prepareBlockForAddingItem(); - block->messages.push_back(item->createView( - HistoryInner::ElementDelegate())); + block->messages.push_back(item->createView(_delegateMixin->delegate())); const auto view = block->messages.back().get(); view->attachToBlock(block, block->messages.size() - 1); @@ -2011,8 +2011,7 @@ not_null History::addNewInTheMiddle( const auto it = block->messages.insert( block->messages.begin() + itemIndex, - item->createView( - HistoryInner::ElementDelegate())); + item->createView(_delegateMixin->delegate())); (*it)->attachToBlock(block.get(), itemIndex); if (itemIndex + 1 < block->messages.size()) { for (auto i = itemIndex + 1, l = int(block->messages.size()); i != l; ++i) { @@ -3287,7 +3286,7 @@ void HistoryBlock::refreshView(not_null view) { const auto item = view->data(); auto refreshed = item->createView( - HistoryInner::ElementDelegate(), + _history->delegateMixin()->delegate(), view); auto blockIndex = indexInHistory(); diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index f70d0ba79..bae332352 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -25,6 +25,7 @@ class HistoryItem; class HistoryMessage; class HistoryService; struct HistoryMessageMarkupData; +class HistoryMainElementDelegateMixin; namespace Main { class Session; @@ -84,6 +85,11 @@ public: History &operator=(const History &) = delete; ~History(); + [[nodiscard]] auto delegateMixin() const + -> not_null { + return _delegateMixin.get(); + } + not_null migrateToOrMe() const; History *migrateFrom() const; MsgRange rangeForDifferenceRequest() const; @@ -585,6 +591,8 @@ private: void setFolderPointer(Data::Folder *folder); + const std::unique_ptr _delegateMixin; + Flags _flags = 0; bool _mute = false; int _width = 0; diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index adc27e192..bd09e9707 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -120,7 +120,148 @@ int BinarySearchBlocksOrItems(const T &list, int edge) { // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html -HistoryInner *HistoryInner::Instance = nullptr; +HistoryMainElementDelegateMixin::HistoryMainElementDelegateMixin() = default; + +HistoryMainElementDelegateMixin::~HistoryMainElementDelegateMixin() + = default; + +class HistoryMainElementDelegate final + : public HistoryView::ElementDelegate + , public HistoryMainElementDelegateMixin { +public: + using Element = HistoryView::Element; + + HistoryView::Context elementContext() override { + return HistoryView::Context::History; + } + std::unique_ptr elementCreate( + not_null message, + Element *replacing = nullptr) override { + return std::make_unique( + this, + message, + replacing); + } + std::unique_ptr elementCreate( + not_null message, + Element *replacing = nullptr) override { + return std::make_unique( + this, + message, + replacing); + } + bool elementUnderCursor( + not_null view) override { + return (App::mousedItem() == view); + } + crl::time elementHighlightTime( + not_null item) override { + return _widget ? _widget->elementHighlightTime(item) : 0; + } + bool elementInSelectionMode() override { + return _widget ? _widget->inSelectionMode() : false; + } + bool elementIntersectsRange( + not_null view, + int from, + int till) override { + return _widget + ? _widget->elementIntersectsRange(view, from, till) + : false; + } + void elementStartStickerLoop( + not_null view) override { + if (_widget) { + _widget->elementStartStickerLoop(view); + } + } + void elementShowPollResults( + not_null poll, + FullMsgId context) override { + if (_widget) { + _widget->elementShowPollResults(poll, context); + } + } + void elementOpenPhoto( + not_null photo, + FullMsgId context) override { + if (_widget) { + _widget->elementOpenPhoto(photo, context); + } + } + void elementOpenDocument( + not_null document, + FullMsgId context, + bool showInMediaView = false) override { + if (_widget) { + _widget->elementOpenDocument( + document, + context, + showInMediaView); + } + } + void elementCancelUpload(const FullMsgId &context) override { + if (_widget) { + _widget->elementCancelUpload(context); + } + } + void elementShowTooltip( + const TextWithEntities &text, + Fn hiddenCallback) override { + if (_widget) { + _widget->elementShowTooltip(text, hiddenCallback); + } + } + bool elementIsGifPaused() override { + return _widget ? _widget->elementIsGifPaused() : false; + } + bool elementHideReply(not_null view) override { + return false; + } + bool elementShownUnread(not_null view) override { + return view->data()->unread(); + } + void elementSendBotCommand( + const QString &command, + const FullMsgId &context) override { + if (_widget) { + _widget->elementSendBotCommand(command, context); + } + } + void elementHandleViaClick(not_null bot) override { + if (_widget) { + _widget->elementHandleViaClick(bot); + } + } + bool elementIsChatWide() override { + return _widget ? _widget->elementIsChatWide() : false; + } + not_null elementPathShiftGradient() override { + Expects(_widget != nullptr); + + return _widget->elementPathShiftGradient(); + } + void elementReplyTo(const FullMsgId &to) override { + if (_widget) { + _widget->elementReplyTo(to); + } + } + void elementStartInteraction(not_null view) override { + if (_widget) { + _widget->elementStartInteraction(view); + } + } + void elementShowSpoilerAnimation() override { + if (_widget) { + _widget->elementShowSpoilerAnimation(); + } + } + + not_null delegate() override { + return this; + } + +}; class HistoryInner::BotAbout : public ClickHandlerHost { public: @@ -170,6 +311,7 @@ HistoryInner::HistoryInner( , _controller(controller) , _peer(history->peer) , _history(history) +, _elementDelegate(_history->delegateMixin()->delegate()) , _emojiInteractions(std::make_unique( &controller->session())) , _migrated(history->migrateFrom()) @@ -185,7 +327,10 @@ HistoryInner::HistoryInner( , _touchScrollTimer([=] { onTouchScrollTimer(); }) , _scrollDateCheck([this] { scrollDateCheck(); }) , _scrollDateHideTimer([this] { scrollDateHideByTimer(); }) { - Instance = this; + _history->delegateMixin()->setCurrent(this); + if (_migrated) { + _migrated->delegateMixin()->setCurrent(this); + } Window::ChatThemeValueFromPeer( controller, @@ -1531,16 +1676,24 @@ void HistoryInner::mouseActionFinish( const auto pressedItemId = pressedItemView ? pressedItemView->data()->fullId() : FullMsgId(); + const auto weak = base::make_weak(_controller.get()); + const auto history = pressedItemView->data()->history(); + const auto delegate = history->delegateMixin()->delegate(); ActivateClickHandler(window(), activated, { button, QVariant::fromValue(ClickHandlerContext{ .itemId = pressedItemId, - .elementDelegate = [weak = Ui::MakeWeak(this)] { - return weak - ? HistoryInner::ElementDelegate().get() - : nullptr; + .elementDelegate = [=]() -> HistoryView::ElementDelegate* { + if (const auto strong = weak.get()) { + auto &data = strong->session().data(); + if (const auto item = data.message(pressedItemId)) { + const auto history = item->history(); + return history->delegateMixin()->delegate(); + } + } + return nullptr; }, - .sessionWindow = base::make_weak(_controller.get()), + .sessionWindow = weak, }) }); return; @@ -2551,7 +2704,13 @@ void HistoryInner::visibleAreaUpdated(int top, int bottom) { const auto pages = kUnloadHeavyPartsPages; const auto from = _visibleAreaTop - pages * visibleAreaHeight; const auto till = _visibleAreaBottom + pages * visibleAreaHeight; - session().data().unloadHeavyViewParts(ElementDelegate(), from, till); + session().data().unloadHeavyViewParts(_elementDelegate, from, till); + if (_migratedElementDelegate) { + session().data().unloadHeavyViewParts( + _migratedElementDelegate, + from, + till); + } checkHistoryActivation(); _emojiInteractions->visibleAreaUpdated( @@ -2701,8 +2860,9 @@ HistoryInner::~HistoryInner() { } } } - if (Instance == this) { - Instance = nullptr; + _history->delegateMixin()->setCurrent(nullptr); + if (_migrated) { + _migrated->delegateMixin()->setCurrent(nullptr); } delete _menu; _mouseAction = MouseAction::None; @@ -3737,139 +3897,7 @@ void HistoryInner::onParentGeometryChanged() { } } -not_null HistoryInner::ElementDelegate() { - class Result final : public HistoryView::ElementDelegate { - public: - HistoryView::Context elementContext() override { - return HistoryView::Context::History; - } - std::unique_ptr elementCreate( - not_null message, - Element *replacing = nullptr) override { - return std::make_unique( - this, - message, - replacing); - } - std::unique_ptr elementCreate( - not_null message, - Element *replacing = nullptr) override { - return std::make_unique( - this, - message, - replacing); - } - bool elementUnderCursor( - not_null view) override { - return (App::mousedItem() == view); - } - crl::time elementHighlightTime( - not_null item) override { - return Instance ? Instance->elementHighlightTime(item) : 0; - } - bool elementInSelectionMode() override { - return Instance ? Instance->inSelectionMode() : false; - } - bool elementIntersectsRange( - not_null view, - int from, - int till) override { - return Instance - ? Instance->elementIntersectsRange(view, from, till) - : false; - } - void elementStartStickerLoop( - not_null view) override { - if (Instance) { - Instance->elementStartStickerLoop(view); - } - } - void elementShowPollResults( - not_null poll, - FullMsgId context) override { - if (Instance) { - Instance->elementShowPollResults(poll, context); - } - } - void elementOpenPhoto( - not_null photo, - FullMsgId context) override { - if (Instance) { - Instance->elementOpenPhoto(photo, context); - } - } - void elementOpenDocument( - not_null document, - FullMsgId context, - bool showInMediaView = false) override { - if (Instance) { - Instance->elementOpenDocument( - document, - context, - showInMediaView); - } - } - void elementCancelUpload(const FullMsgId &context) override { - if (Instance) { - Instance->elementCancelUpload(context); - } - } - void elementShowTooltip( - const TextWithEntities &text, - Fn hiddenCallback) override { - if (Instance) { - Instance->elementShowTooltip(text, hiddenCallback); - } - } - bool elementIsGifPaused() override { - return Instance ? Instance->elementIsGifPaused() : false; - } - bool elementHideReply(not_null view) override { - return false; - } - bool elementShownUnread(not_null view) override { - return view->data()->unread(); - } - void elementSendBotCommand( - const QString &command, - const FullMsgId &context) override { - if (Instance) { - Instance->elementSendBotCommand(command, context); - } - } - void elementHandleViaClick(not_null bot) override { - if (Instance) { - Instance->elementHandleViaClick(bot); - } - } - bool elementIsChatWide() override { - return Instance - ? Instance->elementIsChatWide() - : false; - } - not_null elementPathShiftGradient() override { - Expects(Instance != nullptr); - - return Instance->elementPathShiftGradient(); - } - void elementReplyTo(const FullMsgId &to) override { - if (Instance) { - Instance->elementReplyTo(to); - } - } - void elementStartInteraction(not_null view) override { - if (Instance) { - Instance->elementStartInteraction(view); - } - } - void elementShowSpoilerAnimation() override { - if (Instance) { - Instance->elementShowSpoilerAnimation(); - } - } - - }; - - static Result result; - return &result; +auto HistoryInner::DelegateMixin() +-> std::unique_ptr { + return std::make_unique(); } diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h index e03150843..5645236a4 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.h +++ b/Telegram/SourceFiles/history/history_inner_widget.h @@ -47,6 +47,26 @@ enum class ReportReason; class PathShiftGradient; } // namespace Ui +class HistoryInner; +class HistoryMainElementDelegate; +class HistoryMainElementDelegateMixin { +public: + void setCurrent(HistoryInner *widget) { + _widget = widget; + } + + virtual not_null delegate() = 0; + virtual ~HistoryMainElementDelegateMixin(); + +private: + friend class HistoryMainElementDelegate; + + HistoryMainElementDelegateMixin(); + + HistoryInner *_widget = nullptr; + +}; + class HistoryWidget; class HistoryInner : public Ui::RpWidget @@ -160,8 +180,8 @@ public: void onParentGeometryChanged(); - // HistoryView::ElementDelegate interface. - static not_null ElementDelegate(); + [[nodiscard]] static auto DelegateMixin() + -> std::unique_ptr; protected: bool focusNextPrevChild(bool next) override; @@ -364,17 +384,17 @@ private: // Does any of the shown histories has this flag set. bool hasPendingResizedItems() const; - static HistoryInner *Instance; - const not_null _widget; const not_null _scroll; const not_null _controller; const not_null _peer; const not_null _history; + const not_null _elementDelegate; const std::unique_ptr _emojiInteractions; std::shared_ptr _theme; History *_migrated = nullptr; + HistoryView::ElementDelegate *_migratedElementDelegate = nullptr; int _contentWidth = 0; int _historyPaddingTop = 0; int _revealHeight = 0; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index ed9273eab..190a29a5e 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2056,9 +2056,6 @@ void HistoryWidget::showHistory( _historyInited = false; _contactStatus = nullptr; - // Unload lottie animations. - session().data().unloadHeavyViewParts(HistoryInner::ElementDelegate()); - if (peerId) { _peer = session().data().peer(peerId); _canSendMessages = _peer->canWrite(); @@ -2240,13 +2237,19 @@ void HistoryWidget::setHistory(History *history) { if (_history == history) { return; } + + // Unload lottie animations. + const auto unloadHeavyViewParts = [](History *history) { + if (history) { + history->owner().unloadHeavyViewParts( + history->delegateMixin()->delegate()); + history->forceFullResize(); + } + }; + unloadHeavyViewParts(_history); + unloadHeavyViewParts(_migrated); + unregisterDraftSources(); - if (_history) { - _history->forceFullResize(); - } - if (_migrated) { - _migrated->forceFullResize(); - } _history = history; _migrated = _history ? _history->migrateFrom() : nullptr; registerDraftSource();