From c563df7d9d847feff2540f39cb5214de4f97817c Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 31 Aug 2020 16:14:32 +0400 Subject: [PATCH] Fix navigation in a message replies section. --- .../SourceFiles/data/data_replies_list.cpp | 47 +++++++++++++++---- .../history/view/history_view_list_widget.cpp | 13 ++++- .../history/view/history_view_list_widget.h | 4 ++ .../view/history_view_replies_section.cpp | 20 +++----- .../view/history_view_replies_section.h | 2 - 5 files changed, 61 insertions(+), 25 deletions(-) diff --git a/Telegram/SourceFiles/data/data_replies_list.cpp b/Telegram/SourceFiles/data/data_replies_list.cpp index 744c29523..5105d3295 100644 --- a/Telegram/SourceFiles/data/data_replies_list.cpp +++ b/Telegram/SourceFiles/data/data_replies_list.cpp @@ -20,7 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Data { namespace { -constexpr auto kMessagesPerPage = 4; // #TODO replies +constexpr auto kMessagesPerPage = 16; } // namespace @@ -94,8 +94,8 @@ bool RepliesList::buildFromData(not_null viewer) { const auto around = viewer->around; if (_list.empty() || (!around && _skippedAfter != 0) - || (around > 0 && around < _list.back()) - || (around > _list.front())) { + || (around > _list.front() && _skippedAfter != 0) + || (around > 0 && around < _list.back() && _skippedBefore != 0)) { loadAround(around); return false; } @@ -207,6 +207,13 @@ void RepliesList::loadAround(MsgId id) { _list.clear(); if (processMessagesIsEmpty(result)) { _fullCount = _skippedBefore = _skippedAfter = 0; + } else if (id > 0) { + Assert(!_list.empty()); + if (_list.front() <= id) { + _skippedAfter = 0; + } else if (_list.back() >= id) { + _skippedBefore = 0; + } } }).fail([=](const RPCError &error) { _beforeId = 0; @@ -312,7 +319,8 @@ void RepliesList::loadAfter() { bool RepliesList::processMessagesIsEmpty(const MTPmessages_Messages &result) { const auto guard = gsl::finally([&] { _partLoaded.fire({}); }); - _fullCount = result.match([&](const MTPDmessages_messagesNotModified &) { + const auto fullCount = result.match([&]( + const MTPDmessages_messagesNotModified &) { LOG(("API Error: received messages.messagesNotModified! " "(HistoryWidget::messagesReceived)")); return 0; @@ -346,7 +354,8 @@ bool RepliesList::processMessagesIsEmpty(const MTPmessages_Messages &result) { } const auto id = IdFromMessage(list.front()); - const auto toFront = !_list.empty() && (id > _list.front()); + const auto wasSize = int(_list.size()); + const auto toFront = (wasSize > 0) && (id > _list.front()); const auto clientFlags = MTPDmessage_ClientFlags(); const auto type = NewMessageType::Existing; auto refreshed = std::vector(); @@ -368,11 +377,31 @@ bool RepliesList::processMessagesIsEmpty(const MTPmessages_Messages &result) { refreshed.insert(refreshed.end(), _list.begin(), _list.end()); _list = std::move(refreshed); } - if (_fullCount.current() && _skippedBefore && !_skippedAfter) { - _skippedAfter = *_fullCount.current() - *_skippedBefore - _list.size(); - } else if (_fullCount.current() && _skippedAfter && !_skippedBefore) { - _skippedBefore = *_fullCount.current() - *_skippedAfter - _list.size(); + + const auto nowSize = int(_list.size()); + auto &decrementFrom = toFront ? _skippedAfter : _skippedBefore; + if (decrementFrom.has_value()) { + *decrementFrom = std::max( + *decrementFrom - (nowSize - wasSize), + 0); } + + const auto checkedCount = std::max(fullCount, nowSize); + if (_skippedBefore && _skippedAfter) { + auto &correct = toFront ? _skippedBefore : _skippedAfter; + *correct = std::max( + checkedCount - *decrementFrom - nowSize, + 0); + *decrementFrom = *_fullCount.current() - *correct - nowSize; + Assert(*decrementFrom >= 0); + } else if (_skippedBefore) { + *_skippedBefore = std::min(*_skippedBefore, checkedCount - nowSize); + _skippedAfter = checkedCount - *_skippedBefore - nowSize; + } else if (_skippedAfter) { + *_skippedAfter = std::min(*_skippedAfter, checkedCount - nowSize); + _skippedBefore = checkedCount - *_skippedAfter - nowSize; + } + _fullCount = checkedCount; return false; } diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 3211bcfe8..c47d8e719 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -455,6 +455,15 @@ void ListWidget::highlightMessage(FullMsgId itemId) { } } +void ListWidget::showAroundPosition( + Data::MessagePosition position, + Fn overrideInitialScroll) { + _aroundPosition = position; + _aroundIndex = -1; + _overrideInitialScroll = std::move(overrideInitialScroll); + refreshViewer(); +} + void ListWidget::updateHighlightedMessage() { if (const auto item = session().data().message(_highlightedMessageId)) { if (const auto view = viewForItem(item)) { @@ -486,7 +495,9 @@ void ListWidget::saveScrollState() { } void ListWidget::restoreScrollState() { - if (_items.empty()) { + if (_items.empty() + || (_overrideInitialScroll + && base::take(_overrideInitialScroll)())) { return; } if (!_scrollTopState.item) { diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index d2b1f498f..44322a516 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -164,6 +164,9 @@ public: bool isAbovePosition(Data::MessagePosition position) const; bool isBelowPosition(Data::MessagePosition position) const; void highlightMessage(FullMsgId itemId); + void showAroundPosition( + Data::MessagePosition position, + Fn overrideInitialScroll); TextForMimeData getSelectedText() const; MessageIdsList getSelectedItems() const; @@ -472,6 +475,7 @@ private: int _visibleTopFromItem = 0; ScrollTopState _scrollTopState; Ui::Animations::Simple _scrollToAnimation; + Fn _overrideInitialScroll; bool _scrollDateShown = false; Ui::Animations::Simple _scrollDateOpacity; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index bb473a5c3..cf4984c9d 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -780,19 +780,10 @@ void RepliesWidget::scrollDownClicked() { } void RepliesWidget::showAtPosition(Data::MessagePosition position) { - if (showAtPositionNow(position)) { - 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); + if (!showAtPositionNow(position)) { + _inner->showAroundPosition(position, [=] { + return showAtPositionNow(position); + }); } } @@ -810,6 +801,9 @@ bool RepliesWidget::showAtPositionNow(Data::MessagePosition position) { (std::abs(fullDelta) > limit ? HistoryView::ListWidget::AnimatedScroll::Part : HistoryView::ListWidget::AnimatedScroll::Full)); + if (const auto highlight = base::take(_highlightMessageId)) { + _inner->highlightMessage(highlight); + } return true; } return false; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.h b/Telegram/SourceFiles/history/view/history_view_replies_section.h index de3c1146f..7a9969be6 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.h +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.h @@ -213,8 +213,6 @@ private: bool _skipScrollEvent = false; FullMsgId _highlightMessageId; - std::optional _nextAnimatedScrollPosition; - int _nextAnimatedScrollDelta = 0; Ui::Animations::Simple _scrollDownShown; bool _scrollDownIsShown = false;