From eec4b72d9ad42e176d1bfbcf6c008b48dc2a4b7d Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 11 Oct 2022 15:55:36 +0400 Subject: [PATCH] Implement correct jump to message / unread / bottom. --- .../SourceFiles/data/data_forum_topic.cpp | 2 +- .../SourceFiles/history/history_widget.cpp | 7 +- Telegram/SourceFiles/history/history_widget.h | 1 + .../view/history_view_corner_buttons.cpp | 144 ++++++----- .../view/history_view_corner_buttons.h | 20 +- .../history/view/history_view_list_widget.cpp | 110 ++++++++- .../history/view/history_view_list_widget.h | 42 +++- .../view/history_view_pinned_section.cpp | 170 ++++--------- .../view/history_view_pinned_section.h | 31 ++- .../view/history_view_replies_section.cpp | 83 ++----- .../view/history_view_replies_section.h | 7 +- .../view/history_view_scheduled_section.cpp | 227 +++++------------- .../view/history_view_scheduled_section.h | 42 ++-- 13 files changed, 402 insertions(+), 484 deletions(-) diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp index eff99d5c9..3a40af836 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.cpp +++ b/Telegram/SourceFiles/data/data_forum_topic.cpp @@ -540,7 +540,7 @@ bool ForumTopic::chatListUnreadMark() const { } bool ForumTopic::chatListMutedBadge() const { - return true; + return history()->mute(); } HistoryItem *ForumTopic::chatListMessage() const { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 9d0308461..b1ff16ec2 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -5233,9 +5233,6 @@ void HistoryWidget::itemRemoved(not_null item) { if (item == _replyEditMsg && _replyToId) { cancelReply(); } - while (item == _cornerButtons.replyReturn()) { - _cornerButtons.calculateNextReplyReturn(); - } if (_kbReplyTo && item == _kbReplyTo) { toggleKeyboard(); _kbReplyTo = nullptr; @@ -5806,6 +5803,10 @@ bool HistoryWidget::cornerButtonsUnreadMayBeShown() { return !_firstLoadRequest && !_voiceRecordBar->isLockPresent(); } +bool HistoryWidget::cornerButtonsHas(HistoryView::CornerButtonType type) { + return true; +} + void HistoryWidget::mousePressEvent(QMouseEvent *e) { const auto hasSecondLayer = (_editMsgId || _replyToId diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 91c1daede..6757a88cc 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -330,6 +330,7 @@ private: bool cornerButtonsIgnoreVisibility() override; std::optional cornerButtonsDownShown() override; bool cornerButtonsUnreadMayBeShown() override; + bool cornerButtonsHas(HistoryView::CornerButtonType type) override; void checkSuggestToGigagroup(); diff --git a/Telegram/SourceFiles/history/view/history_view_corner_buttons.cpp b/Telegram/SourceFiles/history/view/history_view_corner_buttons.cpp index 4fe297baf..7482a40e3 100644 --- a/Telegram/SourceFiles/history/view/history_view_corner_buttons.cpp +++ b/Telegram/SourceFiles/history/view/history_view_corner_buttons.cpp @@ -23,6 +23,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_messages.h" #include "data/data_session.h" #include "data/data_forum_topic.h" +#include "lang/lang_keys.h" +#include "ui/toast/toast.h" #include "styles/style_chat.h" namespace HistoryView { @@ -31,41 +33,41 @@ CornerButtons::CornerButtons( not_null parent, not_null st, not_null delegate) -: down( +: _scroll(parent) +, _delegate(delegate) +, _down( parent, st->value(parent->lifetime(), st::historyToDown)) -, mentions( +, _mentions( parent, st->value(parent->lifetime(), st::historyUnreadMentions)) -, reactions( - parent, - st->value(parent->lifetime(), st::historyUnreadReactions)) -, _scroll(parent) -, _delegate(delegate) { - down.widget->addClickHandler([=] { downClick(); }); - mentions.widget->addClickHandler([=] { mentionsClick(); }); - reactions.widget->addClickHandler([=] { reactionsClick(); }); +, _reactions( + parent, + st->value(parent->lifetime(), st::historyUnreadReactions)) { + _down.widget->addClickHandler([=] { downClick(); }); + _mentions.widget->addClickHandler([=] { mentionsClick(); }); + _reactions.widget->addClickHandler([=] { reactionsClick(); }); const auto filterScroll = [&](CornerButton &button) { button.widget->installEventFilter(this); }; - filterScroll(down); - filterScroll(mentions); - filterScroll(reactions); + filterScroll(_down); + filterScroll(_mentions); + filterScroll(_reactions); - SendMenu::SetupUnreadMentionsMenu(mentions.widget.data(), [=] { + SendMenu::SetupUnreadMentionsMenu(_mentions.widget.data(), [=] { return _delegate->cornerButtonsEntry(); }); - SendMenu::SetupUnreadReactionsMenu(reactions.widget.data(), [=] { + SendMenu::SetupUnreadReactionsMenu(_reactions.widget.data(), [=] { return _delegate->cornerButtonsEntry(); }); } bool CornerButtons::eventFilter(QObject *o, QEvent *e) { if (e->type() == QEvent::Wheel - && (o == down.widget - || o == mentions.widget - || o == reactions.widget)) { + && (o == _down.widget + || o == _mentions.widget + || o == _reactions.widget)) { return _scroll->viewportEvent(e); } return QObject::eventFilter(o, e); @@ -164,13 +166,23 @@ void CornerButtons::calculateNextReplyReturn() { void CornerButtons::pushReplyReturn(not_null item) { _replyReturns.push_back(item->fullId()); _replyReturn = item; + + if (!_replyReturnStarted) { + _replyReturnStarted = true; + item->history()->owner().itemRemoved( + ) | rpl::start_with_next([=](not_null item) { + while (item == _replyReturn) { + calculateNextReplyReturn(); + } + }, _down.widget->lifetime()); + } } -CornerButton &CornerButtons::buttonByType(CornerButtonType type) { +CornerButton &CornerButtons::buttonByType(Type type) { switch (type) { - case CornerButtonType::Down: return down; - case CornerButtonType::Mentions: return mentions; - case CornerButtonType::Reactions: return reactions; + case Type::Down: return _down; + case Type::Mentions: return _mentions; + case Type::Reactions: return _reactions; } Unexpected("Type in CornerButtons::buttonByType."); } @@ -215,47 +227,49 @@ void CornerButtons::updateUnreadThingsVisibility() { } const auto entry = _delegate->cornerButtonsEntry(); if (!entry) { - updateVisibility(CornerButtonType::Mentions, false); - updateVisibility(CornerButtonType::Reactions, false); + updateVisibility(Type::Mentions, false); + updateVisibility(Type::Reactions, false); return; } auto &unreadThings = entry->session().api().unreadThings(); unreadThings.preloadEnough(entry); - const auto updateWithCount = [&](CornerButtonType type, int count) { + const auto updateWithCount = [&](Type type, int count) { updateVisibility( type, (count > 0) && _delegate->cornerButtonsUnreadMayBeShown()); }; - if (unreadThings.trackMentions(entry)) { + if (_delegate->cornerButtonsHas(Type::Mentions) + && unreadThings.trackMentions(entry)) { if (const auto count = entry->unreadMentions().count(0)) { - mentions.widget->setUnreadCount(count); + _mentions.widget->setUnreadCount(count); } updateWithCount( - CornerButtonType::Mentions, + Type::Mentions, entry->unreadMentions().loadedCount()); } else { - updateVisibility(CornerButtonType::Mentions, false); + updateVisibility(Type::Mentions, false); } - if (unreadThings.trackReactions(entry)) { + if (_delegate->cornerButtonsHas(Type::Reactions) + && unreadThings.trackReactions(entry)) { if (const auto count = entry->unreadReactions().count(0)) { - reactions.widget->setUnreadCount(count); + _reactions.widget->setUnreadCount(count); } updateWithCount( - CornerButtonType::Reactions, + Type::Reactions, entry->unreadReactions().loadedCount()); } else { - updateVisibility(CornerButtonType::Reactions, false); + updateVisibility(Type::Reactions, false); } } void CornerButtons::updateJumpDownVisibility(std::optional counter) { if (const auto shown = _delegate->cornerButtonsDownShown()) { - updateVisibility(CornerButtonType::Down, *shown); + updateVisibility(Type::Down, *shown); } if (counter) { - down.widget->setUnreadCount(*counter); + _down.widget->setUnreadCount(*counter); } } @@ -273,64 +287,84 @@ void CornerButtons::updatePositions() { // All corner buttons is a child widgets of _scroll, not me. - const auto historyDownShown = shown(down); - const auto unreadMentionsShown = shown(mentions); - const auto unreadReactionsShown = shown(reactions); + const auto historyDownShown = shown(_down); + const auto unreadMentionsShown = shown(_mentions); + const auto unreadReactionsShown = shown(_reactions); const auto skip = st::historyUnreadThingsSkip; { const auto top = anim::interpolate( 0, - down.widget->height() + st::historyToDownPosition.y(), + _down.widget->height() + st::historyToDownPosition.y(), historyDownShown); - down.widget->moveToRight( + _down.widget->moveToRight( st::historyToDownPosition.x(), _scroll->height() - top); } { const auto right = anim::interpolate( - -mentions.widget->width(), + -_mentions.widget->width(), st::historyToDownPosition.x(), unreadMentionsShown); const auto shift = anim::interpolate( 0, - down.widget->height() + skip, + _down.widget->height() + skip, historyDownShown); const auto top = _scroll->height() - - mentions.widget->height() + - _mentions.widget->height() - st::historyToDownPosition.y() - shift; - mentions.widget->moveToRight(right, top); + _mentions.widget->moveToRight(right, top); } { const auto right = anim::interpolate( - -reactions.widget->width(), + -_reactions.widget->width(), st::historyToDownPosition.x(), unreadReactionsShown); const auto shift = anim::interpolate( 0, - down.widget->height() + skip, + _down.widget->height() + skip, historyDownShown ) + anim::interpolate( 0, - mentions.widget->height() + skip, + _mentions.widget->height() + skip, unreadMentionsShown); const auto top = _scroll->height() - - reactions.widget->height() + - _reactions.widget->height() - st::historyToDownPosition.y() - shift; - reactions.widget->moveToRight(right, top); + _reactions.widget->moveToRight(right, top); } - checkVisibility(down); - checkVisibility(mentions); - checkVisibility(reactions); + checkVisibility(_down); + checkVisibility(_mentions); + checkVisibility(_reactions); } void CornerButtons::finishAnimations() { - down.animation.stop(); - mentions.animation.stop(); - reactions.animation.stop(); + _down.animation.stop(); + _mentions.animation.stop(); + _reactions.animation.stop(); updatePositions(); } +Fn CornerButtons::doneJumpFrom( + FullMsgId targetId, + FullMsgId originId) { + return [=](bool found) { + skipReplyReturn(targetId); + if (originId) { + if (const auto entry = _delegate->cornerButtonsEntry()) { + if (const auto item = entry->owner().message(originId)) { + pushReplyReturn(item); + } + } + } + if (!found) { + Ui::Toast::Show( + _scroll.get(), + tr::lng_message_not_found(tr::now)); + } + }; +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_corner_buttons.h b/Telegram/SourceFiles/history/view/history_view_corner_buttons.h index 8cdf0309e..6caa9994d 100644 --- a/Telegram/SourceFiles/history/view/history_view_corner_buttons.h +++ b/Telegram/SourceFiles/history/view/history_view_corner_buttons.h @@ -55,6 +55,7 @@ public: [[nodiscard]] virtual bool cornerButtonsIgnoreVisibility() = 0; [[nodiscard]] virtual std::optional cornerButtonsDownShown() = 0; [[nodiscard]] virtual bool cornerButtonsUnreadMayBeShown() = 0; + [[nodiscard]] virtual bool cornerButtonsHas(CornerButtonType type) = 0; }; class CornerButtons final : private QObject { @@ -64,6 +65,8 @@ public: not_null st, not_null delegate); + using Type = CornerButtonType; + void downClick(); void mentionsClick(); void reactionsClick(); @@ -75,7 +78,7 @@ public: void skipReplyReturn(FullMsgId id); void calculateNextReplyReturn(); - void updateVisibility(CornerButtonType type, bool shown); + void updateVisibility(Type type, bool shown); void updateUnreadThingsVisibility(); void updateJumpDownVisibility(std::optional counter = {}); void updatePositions(); @@ -85,26 +88,31 @@ public: [[nodiscard]] HistoryItem *replyReturn() const { return _replyReturn; } - - CornerButton down; - CornerButton mentions; - CornerButton reactions; + [[nodiscard]] Fn doneJumpFrom( + FullMsgId targetId, + FullMsgId originId); private: bool eventFilter(QObject *o, QEvent *e) override; void computeCurrentReplyReturn(); - [[nodiscard]] CornerButton &buttonByType(CornerButtonType type); + [[nodiscard]] CornerButton &buttonByType(Type type); [[nodiscard]] History *lookupHistory() const; void showAt(MsgId id); const not_null _scroll; const not_null _delegate; + CornerButton _down; + CornerButton _mentions; + CornerButton _reactions; + HistoryItem *_replyReturn = nullptr; QVector _replyReturns; + bool _replyReturnStarted = false; + }; } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index f9f953639..a46987b58 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -482,9 +482,18 @@ void ListWidget::refreshRows(const Data::MessagesSlice &old) { std::optional ListWidget::scrollTopForPosition( Data::MessagePosition position) const { - if (position == Data::MaxMessagePosition) { + if (position == Data::UnreadMessagePosition) { + if (_bar.element && !_bar.hidden && _bar.focus) { + const auto shift = st::lineWidth + st::historyUnreadBarMargin; + return itemTop(_bar.element) + shift; + } + position = Data::MaxMessagePosition; + } + if (_visibleTop >= _visibleBottom) { + return std::nullopt; + } else if (position == Data::MaxMessagePosition) { if (loadedAtBottom()) { - return height(); + return height() - (_visibleBottom - _visibleTop); } return std::nullopt; } else if (_items.empty() @@ -609,6 +618,101 @@ void ListWidget::showAroundPosition( refreshViewer(); } +bool ListWidget::jumpToBottomInsteadOfUnread() const { + // If we want to jump to unread, but we're at the unread already, + // then jump to the end of the list. + // + // That means there is no read inbox messages below us. + const auto firstReadMessage = [&]() -> Element* { + for (const auto &view : ranges::views::reverse(_items)) { + const auto item = view->data(); + if (item->isRegular() + && (item->out() + || !_delegate->listElementShownUnread(view))) { + return view; + } + } + return nullptr; + }(); + return !firstReadMessage || (itemTop(firstReadMessage) < _visibleBottom); +} + +void ListWidget::showAtPosition( + Data::MessagePosition position, + anim::type animated, + Fn done) { + const auto showAtUnread = (position == Data::UnreadMessagePosition); + const auto showAtStart = (position == Data::MinMessagePosition); + const auto showAtEnd = (position == Data::MaxMessagePosition); + + if (showAtUnread && jumpToBottomInsteadOfUnread()) { + showAtPosition(Data::MaxMessagePosition, animated, std::move(done)); + return; + } + + if (position.fullId.peer && position.fullId.msg) { + if (const auto item = session().data().message(position.fullId)) { + position = item->position(); + } + } + + if (showAtUnread) { + showAroundPosition(position, [=] { + if (_bar.element) { + _bar.element->destroyUnreadBar(); + const auto i = ranges::find(_items, not_null{ _bar.element }); + Assert(i != end(_items)); + refreshAttachmentsAtIndex(i - begin(_items)); + _bar = {}; + } + checkUnreadBarCreation(); + return showAtPositionNow(position, animated, done); + }); + } else if (!showAtPositionNow(position, animated, done)) { + showAroundPosition(position, [=] { + return showAtPositionNow(position, animated, done); + }); + } +} + +bool ListWidget::showAtPositionNow( + Data::MessagePosition position, + anim::type animated, + Fn done) { + if (const auto scrollTop = scrollTopForPosition(position)) { + computeScrollTo(*scrollTop, position, animated); + if (position != Data::MaxMessagePosition + && position != Data::UnreadMessagePosition) { + highlightMessage(position.fullId); + } + done(!position.fullId.peer + || !position.fullId.msg + || viewForItem(position.fullId)); + return true; + } + return false; +} + +void ListWidget::computeScrollTo( + int to, + Data::MessagePosition position, + anim::type animated) { + const auto currentScrollHeight = (_visibleBottom - _visibleTop); + const auto currentScrollTop = _visibleTop; + const auto wanted = std::max( + std::min(to, height() - currentScrollHeight), + 0); + const auto fullDelta = (wanted - currentScrollTop); + const auto limit = currentScrollHeight; + const auto scrollDelta = std::clamp(fullDelta, -limit, limit); + const auto type = (animated == anim::type::instant) + ? AnimatedScroll::None + : (std::abs(fullDelta) > limit) + ? AnimatedScroll::Part + : AnimatedScroll::Full; + scrollTo(wanted, position, scrollDelta, type); +} + void ListWidget::checkUnreadBarCreation() { if (!_bar.element) { if (auto data = _delegate->listMessagesBar(_items); data.bar.element) { @@ -1672,7 +1776,7 @@ int ListWidget::resizeGetHeight(int newWidth) { const auto resizeAllItems = (_itemsWidth != newWidth); auto newHeight = 0; - for (auto &view : _items) { + for (const auto &view : _items) { view->setY(newHeight); if (view->pendingResize() || resizeAllItems) { newHeight += view->resizeGetHeight(newWidth); diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index dfdd2dd0f..7935598b6 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -202,23 +202,16 @@ public: Data::MessagePosition position) const; Element *viewByPosition(Data::MessagePosition position) const; std::optional scrollTopForView(not_null view) const; - enum class AnimatedScroll { - Full, - Part, - None, - }; - void scrollTo( - int scrollTop, - Data::MessagePosition attachPosition, - int delta, - AnimatedScroll type); [[nodiscard]] bool animatedScrolling() const; bool isAbovePosition(Data::MessagePosition position) const; bool isBelowPosition(Data::MessagePosition position) const; void highlightMessage(FullMsgId itemId); - void showAroundPosition( + + void showAtPosition( Data::MessagePosition position, - Fn overrideInitialScroll); + anim::type animated = anim::type::normal, + Fn done = nullptr); + void refreshViewer(); [[nodiscard]] TextForMimeData getSelectedText() const; [[nodiscard]] MessageIdsList getSelectedIds() const; @@ -391,13 +384,21 @@ private: void onTouchSelect(); void onTouchScrollTimer(); - void refreshViewer(); void updateAroundPositionFromNearest(int nearestIndex); void refreshRows(const Data::MessagesSlice &old); ScrollTopState countScrollState() const; void saveScrollState(); void restoreScrollState(); + [[nodiscard]] bool jumpToBottomInsteadOfUnread() const; + void showAroundPosition( + Data::MessagePosition position, + Fn overrideInitialScroll); + bool showAtPositionNow( + Data::MessagePosition position, + anim::type animated, + Fn done); + Ui::ChatPaintContext preparePaintContext(const QRect &clip) const; Element *viewForItem(FullMsgId itemId) const; @@ -453,6 +454,21 @@ private: void scrollDateHideByTimer(); void keepScrollDateForNow(); + void computeScrollTo( + int to, + Data::MessagePosition position, + anim::type animated); + enum class AnimatedScroll { + Full, + Part, + None, + }; + void scrollTo( + int scrollTop, + Data::MessagePosition attachPosition, + int delta, + AnimatedScroll type); + void trySwitchToWordSelection(); void switchToWordSelection(); void validateTrippleClickStartTime(); diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp index defd0887e..bb2740f70 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.cpp @@ -102,9 +102,10 @@ PinnedWidget::PinnedWidget( this, QString(), st::historyComposeButton)) -, _scrollDown( +, _cornerButtons( _scroll.get(), - controller->chatStyle()->value(lifetime(), st::historyToDown)) { + controller->chatStyle(), + static_cast(this)) { controller->chatStyle()->paletteChanged( ) | rpl::start_with_next([=] { _scroll->updateBars(); @@ -161,26 +162,10 @@ PinnedWidget::PinnedWidget( }, lifetime()); setupClearButton(); - setupScrollDownButton(); } PinnedWidget::~PinnedWidget() = default; -void PinnedWidget::setupScrollDownButton() { - _scrollDown->setClickedCallback([=] { - scrollDownClicked(); - }); - base::install_event_filter(_scrollDown, [=](not_null event) { - if (event->type() != QEvent::Wheel) { - return base::EventFilterResult::Continue; - } - return _scroll->viewportEvent(event) - ? base::EventFilterResult::Cancel - : base::EventFilterResult::Continue; - }); - updateScrollDownVisibility(); -} - void PinnedWidget::setupClearButton() { Data::CanPinMessagesValue( _history->peer @@ -203,118 +188,48 @@ void PinnedWidget::setupClearButton() { }); } -void PinnedWidget::scrollDownClicked() { - if (base::IsCtrlPressed()) { - showAtEnd(); - //} else if (_replyReturn) { - // showAtPosition(_replyReturn->position()); - } else { - showAtEnd(); +void PinnedWidget::cornerButtonsShowAtPosition( + Data::MessagePosition position) { + showAtPosition(position); +} + +Dialogs::Entry *PinnedWidget::cornerButtonsEntry() { + return _history; +} + +FullMsgId PinnedWidget::cornerButtonsCurrentId() { + return {}; +} + +bool PinnedWidget::cornerButtonsIgnoreVisibility() { + return animatingShow(); +} + +std::optional PinnedWidget::cornerButtonsDownShown() { + const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; + if (top < _scroll->scrollTopMax() || _cornerButtons.replyReturn()) { + return true; + } else if (_inner->loadedAtBottomKnown()) { + return !_inner->loadedAtBottom(); } + return std::nullopt; } -void PinnedWidget::showAtStart() { - showAtPosition(Data::MinMessagePosition); +bool PinnedWidget::cornerButtonsUnreadMayBeShown() { + return _inner->loadedAtBottomKnown(); } -void PinnedWidget::showAtEnd() { - showAtPosition(Data::MaxMessagePosition); +bool PinnedWidget::cornerButtonsHas(CornerButtonType type) { + return (type == CornerButtonType::Down); } void PinnedWidget::showAtPosition( Data::MessagePosition position, - HistoryItem *originItem) { - if (!showAtPositionNow(position, originItem)) { - _inner->showAroundPosition(position, [=] { - return showAtPositionNow(position, originItem); - }); - } -} - -bool PinnedWidget::showAtPositionNow( - Data::MessagePosition position, - HistoryItem *originItem, - anim::type animated) { - using AnimatedScroll = HistoryView::ListWidget::AnimatedScroll; - - const auto item = position.fullId - ? _history->owner().message(position.fullId) - : nullptr; - const auto use = item ? item->position() : position; - if (const auto scrollTop = _inner->scrollTopForPosition(use)) { - const auto currentScrollTop = _scroll->scrollTop(); - const auto wanted = std::clamp( - *scrollTop, - 0, - _scroll->scrollTopMax()); - const auto fullDelta = (wanted - currentScrollTop); - const auto limit = _scroll->height(); - const auto scrollDelta = std::clamp(fullDelta, -limit, limit); - const auto type = (animated == anim::type::instant) - ? AnimatedScroll::None - : (std::abs(fullDelta) > limit) - ? AnimatedScroll::Part - : AnimatedScroll::Full; - _inner->scrollTo( - wanted, - use, - scrollDelta, - type); - if (use != Data::MaxMessagePosition - && use != Data::UnreadMessagePosition) { - _inner->highlightMessage(use.fullId); - } - return true; - } - return false; -} - -void PinnedWidget::updateScrollDownVisibility() { - if (animatingShow()) { - return; - } - - const auto scrollDownIsVisible = [&]() -> std::optional { - const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; - if (top < _scroll->scrollTopMax()) { - return true; - } else if (_inner->loadedAtBottomKnown()) { - return !_inner->loadedAtBottom(); - } - return std::nullopt; - }; - const auto scrollDownIsShown = scrollDownIsVisible(); - if (!scrollDownIsShown) { - return; - } - if (_scrollDownIsShown != *scrollDownIsShown) { - _scrollDownIsShown = *scrollDownIsShown; - _scrollDownShown.start( - [=] { updateScrollDownPosition(); }, - _scrollDownIsShown ? 0. : 1., - _scrollDownIsShown ? 1. : 0., - st::historyToDownDuration); - } -} - -void PinnedWidget::updateScrollDownPosition() { - // _scrollDown is a child widget of _scroll, not me. - auto top = anim::interpolate( - 0, - _scrollDown->height() + st::historyToDownPosition.y(), - _scrollDownShown.value(_scrollDownIsShown ? 1. : 0.)); - _scrollDown->moveToRight( - st::historyToDownPosition.x(), - _scroll->height() - top); - auto shouldBeHidden = !_scrollDownIsShown && !_scrollDownShown.animating(); - if (shouldBeHidden != _scrollDown->isHidden()) { - _scrollDown->setVisible(!shouldBeHidden); - } -} - -void PinnedWidget::scrollDownAnimationFinish() { - _scrollDownShown.stop(); - updateScrollDownPosition(); + FullMsgId originId) { + _inner->showAtPosition( + position, + anim::type::normal, + _cornerButtons.doneJumpFrom(position.fullId, originId)); } void PinnedWidget::updateAdaptiveLayout() { @@ -387,15 +302,12 @@ void PinnedWidget::saveState(not_null memento) { void PinnedWidget::restoreState(not_null memento) { _inner->restoreState(memento->list()); if (const auto highlight = memento->getHighlightId()) { - const auto position = Data::MessagePosition{ + _inner->showAtPosition(Data::MessagePosition{ .fullId = ((highlight > 0 || !_migratedPeer) ? FullMsgId(_history->peer->id, highlight) : FullMsgId(_migratedPeer->id, -highlight)), .date = TimeId(0), - }; - _inner->showAroundPosition(position, [=] { - return showAtPositionNow(position, nullptr, anim::type::instant); - }); + }, anim::type::instant); } } @@ -463,7 +375,8 @@ void PinnedWidget::updateControlsGeometry() { } updateInnerVisibleArea(); } - updateScrollDownPosition(); + + _cornerButtons.updatePositions(); } void PinnedWidget::paintEvent(QPaintEvent *e) { @@ -490,7 +403,8 @@ void PinnedWidget::onScroll() { void PinnedWidget::updateInnerVisibleArea() { const auto scrollTop = _scroll->scrollTop(); _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); - updateScrollDownVisibility(); + _cornerButtons.updateJumpDownVisibility(); + _cornerButtons.updateUnreadThingsVisibility(); } void PinnedWidget::showAnimatedHook( diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.h b/Telegram/SourceFiles/history/view/history_view_pinned_section.h index a1008c735..d17267f33 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.h +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/section_widget.h" #include "window/section_memento.h" #include "history/view/history_view_list_widget.h" +#include "history/view/history_view_corner_buttons.h" #include "data/data_messages.h" #include "base/weak_ptr.h" #include "base/timer.h" @@ -35,7 +36,8 @@ class PinnedMemento; class PinnedWidget final : public Window::SectionWidget - , private ListDelegate { + , private ListDelegate + , private CornerButtonsDelegate { public: PinnedWidget( QWidget *parent, @@ -111,6 +113,16 @@ public: -> rpl::producer override; void listShowPremiumToast(not_null document) override; + // CornerButtonsDelegate delegate. + void cornerButtonsShowAtPosition( + Data::MessagePosition position) override; + Dialogs::Entry *cornerButtonsEntry() override; + FullMsgId cornerButtonsCurrentId() override; + bool cornerButtonsIgnoreVisibility() override; + std::optional cornerButtonsDownShown() override; + bool cornerButtonsUnreadMayBeShown() override; + bool cornerButtonsHas(CornerButtonType type) override; + protected: void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; @@ -127,22 +139,11 @@ private: void updateAdaptiveLayout(); void saveState(not_null memento); void restoreState(not_null memento); - void showAtStart(); - void showAtEnd(); void showAtPosition( Data::MessagePosition position, - HistoryItem *originItem = nullptr); - bool showAtPositionNow( - Data::MessagePosition position, - HistoryItem *originItem, - anim::type animated = anim::type::normal); + FullMsgId originId = {}); void setupClearButton(); - void setupScrollDownButton(); - void scrollDownClicked(); - void scrollDownAnimationFinish(); - void updateScrollDownVisibility(); - void updateScrollDownPosition(); void confirmDeleteSelected(); void confirmForwardSelected(); @@ -163,9 +164,7 @@ private: std::unique_ptr _scroll; std::unique_ptr _clearButton; - Ui::Animations::Simple _scrollDownShown; - bool _scrollDownIsShown = false; - object_ptr _scrollDown; + CornerButtons _cornerButtons; int _messagesCount = -1; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 66f3c3e7b..b163f5dd4 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -337,9 +337,6 @@ RepliesWidget::RepliesWidget( controller->showBackFromStack(); } } - while (update.item == _cornerButtons.replyReturn()) { - _cornerButtons.calculateNextReplyReturn(); - } }, lifetime()); _history->session().changes().historyUpdates( @@ -477,6 +474,8 @@ void RepliesWidget::setupTopicViewer() { } void RepliesWidget::subscribeToTopic() { + Expects(_topic != nullptr); + using TopicUpdateFlag = Data::TopicUpdate::Flag; session().changes().topicUpdates( _topic, @@ -485,6 +484,8 @@ void RepliesWidget::subscribeToTopic() { ) | rpl::start_with_next([=](const Data::TopicUpdate &update) { _cornerButtons.updateUnreadThingsVisibility(); }, _topicLifetime); + + _cornerButtons.updateUnreadThingsVisibility(); } void RepliesWidget::setTopic(Data::ForumTopic *topic) { @@ -917,7 +918,7 @@ bool RepliesWidget::showSlowmodeError() { Ui::FormatDurationWordsSlowmode(left)); } else if (_history->peer->slowmodeApplied()) { if (const auto item = _history->latestSendingMessage()) { - showAtPositionNow(item->position(), nullptr); + showAtPosition(item->position()); return tr::lng_slowmode_no_many(tr::now); } } @@ -1379,7 +1380,7 @@ void RepliesWidget::cornerButtonsShowAtPosition( } Dialogs::Entry *RepliesWidget::cornerButtonsEntry() { - return _topic; + return _topic ? static_cast(_topic) : _history; } FullMsgId RepliesWidget::cornerButtonsCurrentId() { @@ -1408,6 +1409,10 @@ bool RepliesWidget::cornerButtonsUnreadMayBeShown() { && !_composeControls->isLockPresent(); } +bool RepliesWidget::cornerButtonsHas(CornerButtonType type) { + return _topic || (type == CornerButtonType::Down); +} + void RepliesWidget::showAtStart() { showAtPosition(Data::MinMessagePosition); } @@ -1426,50 +1431,12 @@ void RepliesWidget::finishSending() { void RepliesWidget::showAtPosition( Data::MessagePosition position, - HistoryItem *originItem) { - if (!showAtPositionNow(position, originItem)) { - _inner->showAroundPosition(position, [=] { - return showAtPositionNow(position, originItem); - }); - } -} - -bool RepliesWidget::showAtPositionNow( - Data::MessagePosition position, - HistoryItem *originItem, - anim::type animated) { - using AnimatedScroll = HistoryView::ListWidget::AnimatedScroll; - const auto item = position.fullId - ? _history->owner().message(position.fullId) - : nullptr; - const auto use = item ? item->position() : position; - if (const auto scrollTop = _inner->scrollTopForPosition(use)) { - _cornerButtons.skipReplyReturn(use.fullId); - const auto currentScrollTop = _scroll->scrollTop(); - const auto wanted = std::clamp( - *scrollTop, - 0, - _scroll->scrollTopMax()); - const auto fullDelta = (wanted - currentScrollTop); - const auto limit = _scroll->height(); - const auto scrollDelta = std::clamp(fullDelta, -limit, limit); - const auto type = (animated == anim::type::instant) - ? AnimatedScroll::None - : (std::abs(fullDelta) > limit) - ? AnimatedScroll::Part - : AnimatedScroll::Full; - _inner->scrollTo(wanted, use, scrollDelta, type); - _lastShownAt = use.fullId; - if (use != Data::MaxMessagePosition - && use != Data::UnreadMessagePosition) { - _inner->highlightMessage(use.fullId); - } - if (originItem) { - pushReplyReturn(originItem); - } - return true; - } - return false; + FullMsgId originItemId) { + _lastShownAt = position.fullId; + _inner->showAtPosition( + position, + anim::type::normal, + _cornerButtons.doneJumpFrom(position.fullId, originItemId)); } void RepliesWidget::updateAdaptiveLayout() { @@ -1619,11 +1586,10 @@ bool RepliesWidget::showMessage( if (!originMessage) { return false; } - const auto originItem = (!originMessage - || _cornerButtons.replyReturn() == originMessage) - ? nullptr - : originMessage; - showAtPosition(message->position(), originItem); + const auto originItemId = (_cornerButtons.replyReturn() != originMessage) + ? originMessage->fullId() + : FullMsgId(); + showAtPosition(message->position(), originItemId); return true; } @@ -1653,7 +1619,7 @@ void RepliesWidget::refreshReplies() { ? _topic->replies() : std::make_shared(_history, _rootId)); if (old) { - _inner->showAroundPosition(Data::UnreadMessagePosition, nullptr); + _inner->refreshViewer(); } } @@ -1701,13 +1667,10 @@ void RepliesWidget::restoreState(not_null memento) { _cornerButtons.setReplyReturns(memento->replyReturns()); _inner->restoreState(memento->list()); if (const auto highlight = memento->getHighlightId()) { - const auto position = Data::MessagePosition{ + _inner->showAtPosition(Data::MessagePosition{ .fullId = FullMsgId(_history->peer->id, highlight), .date = TimeId(0), - }; - _inner->showAroundPosition(position, [=] { - return showAtPositionNow(position, nullptr); - }); + }, anim::type::instant); } } diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.h b/Telegram/SourceFiles/history/view/history_view_replies_section.h index 50020e753..d7f18260a 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.h +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.h @@ -159,6 +159,7 @@ public: bool cornerButtonsIgnoreVisibility() override; std::optional cornerButtonsDownShown() override; bool cornerButtonsUnreadMayBeShown() override; + bool cornerButtonsHas(CornerButtonType type) override; protected: void resizeEvent(QResizeEvent *e) override; @@ -182,11 +183,7 @@ private: void showAtEnd(); void showAtPosition( Data::MessagePosition position, - HistoryItem *originItem = nullptr); - bool showAtPositionNow( - Data::MessagePosition position, - HistoryItem *originItem, - anim::type animated = anim::type::normal); + FullMsgId originItemId = {}); void finishSending(); void setupComposeControls(); diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index c565be015..47f2985d4 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -112,9 +112,10 @@ ScheduledWidget::ScheduledWidget( [=](not_null emoji) { listShowPremiumToast(emoji); }, ComposeControls::Mode::Scheduled, SendMenu::Type::Disabled)) -, _scrollDown( - _scroll, - controller->chatStyle()->value(lifetime(), st::historyToDown)) { +, _cornerButtons( + _scroll.data(), + controller->chatStyle(), + static_cast(this)) { controller->chatStyle()->paletteChanged( ) | rpl::start_with_next([=] { _scroll->updateBars(); @@ -193,16 +194,6 @@ ScheduledWidget::ScheduledWidget( emptyInfo->setText(emptyText); _inner->setEmptyInfoWidget(std::move(emptyInfo)); } - - _history->session().changes().messageUpdates( - Data::MessageUpdate::Flag::Destroyed - ) | rpl::start_with_next([=](const Data::MessageUpdate &update) { - while (update.item == _replyReturn) { - calculateNextReplyReturn(); - } - }, lifetime()); - - setupScrollDownButton(); setupComposeControls(); } @@ -307,7 +298,8 @@ void ScheduledWidget::setupComposeControls() { _composeControls->lockShowStarts( ) | rpl::start_with_next([=] { - updateScrollDownVisibility(); + _cornerButtons.updateJumpDownVisibility(); + _cornerButtons.updateUnreadThingsVisibility(); }, lifetime()); _composeControls->viewportEvents( @@ -488,40 +480,21 @@ bool ScheduledWidget::confirmSendingFiles( void ScheduledWidget::pushReplyReturn(not_null item) { if (_inner->viewByPosition(item->position())) { - _replyReturns.push_back(item->id); - } else { - return; - } - _replyReturn = item; - updateScrollDownVisibility(); -} - -void ScheduledWidget::computeCurrentReplyReturn() { - _replyReturn = _replyReturns.empty() - ? nullptr - : _history->owner().message(_history->peer, _replyReturns.back()); -} - -void ScheduledWidget::calculateNextReplyReturn() { - _replyReturn = nullptr; - while (!_replyReturns.empty() && !_replyReturn) { - _replyReturns.pop_back(); - computeCurrentReplyReturn(); - } - if (!_replyReturn) { - updateScrollDownVisibility(); + _cornerButtons.pushReplyReturn(item); } } void ScheduledWidget::checkReplyReturns() { const auto currentTop = _scroll->scrollTop(); - for (; _replyReturn != nullptr; calculateNextReplyReturn()) { - const auto position = _replyReturn->position(); + while (const auto replyReturn = _cornerButtons.replyReturn()) { + const auto position = replyReturn->position(); const auto scrollTop = _inner->scrollTopForPosition(position); - const auto scrolledBelow = scrollTop + const auto below = scrollTop ? (currentTop >= std::min(*scrollTop, _scroll->scrollTopMax())) : _inner->isBelowPosition(position); - if (!scrolledBelow) { + if (below) { + _cornerButtons.calculateNextReplyReturn(); + } else { break; } } @@ -844,138 +817,52 @@ SendMenu::Type ScheduledWidget::sendMenuType() const { : SendMenu::Type::Scheduled; } -void ScheduledWidget::setupScrollDownButton() { - _scrollDown->setClickedCallback([=] { - scrollDownClicked(); - }); - base::install_event_filter(_scrollDown, [=](not_null event) { - if (event->type() != QEvent::Wheel) { - return base::EventFilterResult::Continue; - } - return _scroll->viewportEvent(event) - ? base::EventFilterResult::Cancel - : base::EventFilterResult::Continue; - }); - updateScrollDownVisibility(); +void ScheduledWidget::cornerButtonsShowAtPosition( + Data::MessagePosition position) { + showAtPosition(position); } -void ScheduledWidget::scrollDownClicked() { - if (base::IsCtrlPressed()) { - showAtEnd(); - } else if (_replyReturn) { - showAtPosition(_replyReturn->position()); - } else { - showAtEnd(); +Dialogs::Entry *ScheduledWidget::cornerButtonsEntry() { + return _history; +} + +FullMsgId ScheduledWidget::cornerButtonsCurrentId() { + return {}; +} + +bool ScheduledWidget::cornerButtonsIgnoreVisibility() { + return animatingShow(); +} + +std::optional ScheduledWidget::cornerButtonsDownShown() { + if (_composeControls->isLockPresent()) { + return false; } + const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; + if (top < _scroll->scrollTopMax() || _cornerButtons.replyReturn()) { + return true; + } else if (_inner->loadedAtBottomKnown()) { + return !_inner->loadedAtBottom(); + } + return std::nullopt; } -void ScheduledWidget::showAtEnd() { - showAtPosition(Data::MaxMessagePosition); +bool ScheduledWidget::cornerButtonsUnreadMayBeShown() { + return _inner->loadedAtBottomKnown() + && !_composeControls->isLockPresent(); +} + +bool ScheduledWidget::cornerButtonsHas(CornerButtonType type) { + return (type == CornerButtonType::Down); } void ScheduledWidget::showAtPosition( Data::MessagePosition position, - HistoryItem *originItem) { - if (showAtPositionNow(position, originItem)) { - if (const auto highlight = base::take(_highlightMessageId)) { - _inner->highlightMessage(highlight); - } - } else { - _nextAnimatedScrollPosition = position; - _nextAnimatedScrollDelta = _inner->isBelowPosition(position) - ? -_scroll->height() - : _inner->isAbovePosition(position) - ? _scroll->height() - : 0; - auto memento = HistoryView::ListMemento(position); - _inner->restoreState(&memento); - } -} - -bool ScheduledWidget::showAtPositionNow( - Data::MessagePosition position, - HistoryItem *originItem) { - if (const auto scrollTop = _inner->scrollTopForPosition(position)) { - while (_replyReturn && position.fullId.msg == _replyReturn->id) { - calculateNextReplyReturn(); - } - const auto currentScrollTop = _scroll->scrollTop(); - const auto wanted = std::clamp( - *scrollTop, - 0, - _scroll->scrollTopMax()); - const auto fullDelta = (wanted - currentScrollTop); - const auto limit = _scroll->height(); - const auto scrollDelta = std::clamp(fullDelta, -limit, limit); - _inner->scrollTo( - wanted, - position, - scrollDelta, - (std::abs(fullDelta) > limit - ? HistoryView::ListWidget::AnimatedScroll::Part - : HistoryView::ListWidget::AnimatedScroll::Full)); - if (position != Data::MaxMessagePosition - && position != Data::UnreadMessagePosition) { - _inner->highlightMessage(position.fullId); - } - if (originItem) { - pushReplyReturn(originItem); - } - return true; - } - return false; -} - -void ScheduledWidget::updateScrollDownVisibility() { - if (animatingShow()) { - return; - } - - const auto scrollDownIsVisible = [&]() -> std::optional { - if (_composeControls->isLockPresent()) { - return false; - } - const auto top = _scroll->scrollTop() + st::historyToDownShownAfter; - if (top < _scroll->scrollTopMax()) { - return true; - } - if (_inner->loadedAtBottomKnown()) { - return !_inner->loadedAtBottom(); - } - return std::nullopt; - }; - const auto scrollDownIsShown = scrollDownIsVisible(); - if (!scrollDownIsShown) { - return; - } - if (_scrollDownIsShown != *scrollDownIsShown) { - _scrollDownIsShown = *scrollDownIsShown; - _scrollDownShown.start( - [=] { updateScrollDownPosition(); }, - _scrollDownIsShown ? 0. : 1., - _scrollDownIsShown ? 1. : 0., - st::historyToDownDuration); - } -} - -void ScheduledWidget::updateScrollDownPosition() { - // _scrollDown is a child widget of _scroll, not me. - auto top = anim::interpolate( - 0, - _scrollDown->height() + st::historyToDownPosition.y(), - _scrollDownShown.value(_scrollDownIsShown ? 1. : 0.)); - _scrollDown->moveToRight( - st::historyToDownPosition.x(), - _scroll->height() - top); - auto shouldBeHidden = !_scrollDownIsShown && !_scrollDownShown.animating(); - if (shouldBeHidden != _scrollDown->isHidden()) { - _scrollDown->setVisible(!shouldBeHidden); - } -} - -void ScheduledWidget::scrollDownAnimationFinish() { - _scrollDownShown.stop(); - updateScrollDownPosition(); + FullMsgId originId) { + _inner->showAtPosition( + position, + anim::type::normal, + _cornerButtons.doneJumpFrom(position.fullId, originId)); } void ScheduledWidget::updateAdaptiveLayout() { @@ -1092,7 +979,7 @@ void ScheduledWidget::updateControlsGeometry() { _composeControls->move(0, bottom - controlsHeight); _composeControls->setAutocompleteBoundingRect(_scroll->geometry()); - updateScrollDownPosition(); + _cornerButtons.updatePositions(); } void ScheduledWidget::paintEvent(QPaintEvent *e) { @@ -1126,7 +1013,8 @@ void ScheduledWidget::updateInnerVisibleArea() { } const auto scrollTop = _scroll->scrollTop(); _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); - updateScrollDownVisibility(); + _cornerButtons.updateJumpDownVisibility(); + _cornerButtons.updateUnreadThingsVisibility(); } void ScheduledWidget::showAnimatedHook( @@ -1224,7 +1112,6 @@ void ScheduledWidget::highlightSingleNewMessage( } const auto newId = slice.ids[firstDifferent]; if (const auto item = session().data().message(newId)) { - // _highlightMessageId = newId; showAtPosition(item->position()); } } @@ -1267,7 +1154,7 @@ void ScheduledWidget::listMarkContentsRead( MessagesBarData ScheduledWidget::listMessagesBar( const std::vector> &elements) { - return MessagesBarData(); + return {}; } void ScheduledWidget::listContentRefreshed() { @@ -1308,14 +1195,16 @@ bool ScheduledWidget::showMessage( if (const auto origin = std::get_if(¶ms.origin)) { if (const auto returnTo = session().data().message(origin->id)) { if (_inner->viewByPosition(returnTo->position()) - && _replyReturn != returnTo) { + && _cornerButtons.replyReturn() != returnTo) { return returnTo; } } } return nullptr; }(); - showAtPosition(message->position(), originItem); + showAtPosition( + message->position(), + originItem ? originItem->fullId() : FullMsgId()); return true; } diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h index 6d09fb48e..5c5ee6c71 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "window/section_widget.h" #include "window/section_memento.h" #include "history/view/history_view_list_widget.h" +#include "history/view/history_view_corner_buttons.h" #include "data/data_messages.h" class History; @@ -52,7 +53,8 @@ class StickerToast; class ScheduledWidget final : public Window::SectionWidget - , private ListDelegate { + , private ListDelegate + , private CornerButtonsDelegate { public: ScheduledWidget( QWidget *parent, @@ -121,7 +123,8 @@ public: ClickHandlerPtr listDateLink(not_null view) override; bool listElementHideReply(not_null view) override; bool listElementShownUnread(not_null view) override; - bool listIsGoodForAroundPosition(not_null view) override; + bool listIsGoodForAroundPosition( + not_null view) override; void listSendBotCommand( const QString &command, const FullMsgId &context) override; @@ -133,6 +136,16 @@ public: -> rpl::producer override; void listShowPremiumToast(not_null document) override; + // CornerButtonsDelegate delegate. + void cornerButtonsShowAtPosition( + Data::MessagePosition position) override; + Dialogs::Entry *cornerButtonsEntry() override; + FullMsgId cornerButtonsCurrentId() override; + bool cornerButtonsIgnoreVisibility() override; + std::optional cornerButtonsDownShown() override; + bool cornerButtonsUnreadMayBeShown() override; + bool cornerButtonsHas(CornerButtonType type) override; + protected: void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; @@ -151,22 +164,12 @@ private: void restoreState(not_null memento); void showAtPosition( Data::MessagePosition position, - HistoryItem *originItem = nullptr); - bool showAtPositionNow( - Data::MessagePosition position, - HistoryItem *originItem); + FullMsgId originId = {}); void setupComposeControls(); void setupDragArea(); - void setupScrollDownButton(); - void scrollDownClicked(); - void scrollDownAnimationFinish(); - void updateScrollDownVisibility(); - void updateScrollDownPosition(); - void showAtEnd(); - void confirmSendNowSelected(); void confirmDeleteSelected(); void clearSelected(); @@ -190,8 +193,6 @@ private: [[nodiscard]] SendMenu::Type sendMenuType() const; void pushReplyReturn(not_null item); - void computeCurrentReplyReturn(); - void calculateNextReplyReturn(); void checkReplyReturns(); void uploadFile(const QByteArray &fileContent, SendMediaType type); @@ -242,16 +243,7 @@ private: std::unique_ptr _stickerToast; - std::vector _replyReturns; - HistoryItem *_replyReturn = nullptr; - - FullMsgId _highlightMessageId; - std::optional _nextAnimatedScrollPosition; - int _nextAnimatedScrollDelta = 0; - - Ui::Animations::Simple _scrollDownShown; - bool _scrollDownIsShown = false; - object_ptr _scrollDown; + CornerButtons _cornerButtons; Data::MessagesSlice _lastSlice; bool _choosingAttach = false;