diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index 5e71fcad07..79828f7fc2 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -618,7 +618,8 @@ void Controller::rebuildFromContext( storyId.peer, &StoriesSourceInfo::id); if (i != end(sources)) { - showSiblings(&user->session(), sources, (i - begin(sources))); + rebuildCachedSourcesList(sources, (i - begin(sources))); + showSiblings(&user->session()); if (int(sources.end() - i) < kPreloadUsersCount) { stories.loadMore(list); } @@ -780,18 +781,19 @@ void Controller::setPlayingAllowed(bool allowed) { } } -void Controller::showSiblings( - not_null session, - const std::vector &sources, - int index) { +void Controller::showSiblings(not_null session) { showSibling( _siblingLeft, session, - (index > 0) ? sources[index - 1].id : PeerId()); + (_cachedSourceIndex > 0 + ? _cachedSourcesList[_cachedSourceIndex - 1] + : PeerId())); showSibling( _siblingRight, session, - (index + 1 < sources.size()) ? sources[index + 1].id : PeerId()); + (_cachedSourceIndex + 1 < _cachedSourcesList.size() + ? _cachedSourcesList[_cachedSourceIndex + 1] + : PeerId())); } void Controller::hideSiblings() { @@ -1116,6 +1118,68 @@ void Controller::loadMoreToList() { }); } +void Controller::rebuildCachedSourcesList( + const std::vector &lists, + int index) { + Expects(index >= 0 && index < lists.size()); + + // Remove removed. + _cachedSourcesList.erase(ranges::remove_if(_cachedSourcesList, [&]( + PeerId id) { + return !ranges::contains(lists, id, &Data::StoriesSourceInfo::id); + }), end(_cachedSourcesList)); + + // Find current, full rebuild if can't find. + const auto i = ranges::find(_cachedSourcesList, lists[index].id); + if (i == end(_cachedSourcesList)) { + _cachedSourcesList.clear(); + } else { + _cachedSourceIndex = int(i - begin(_cachedSourcesList)); + } + + if (_cachedSourcesList.empty()) { + // Full rebuild. + _cachedSourcesList = lists + | ranges::views::transform(&Data::StoriesSourceInfo::id) + | ranges::to_vector; + _cachedSourceIndex = index; + } else if (ranges::equal( + lists, + _cachedSourcesList, + ranges::equal_to(), + &Data::StoriesSourceInfo::id)) { + // No rebuild needed. + _cachedSourceIndex = index; + } else { + // All that go before the current push to front. + for (auto before = index; before > 0;) { + --before; + const auto peerId = lists[--before].id; + if (!ranges::contains(_cachedSourcesList, peerId)) { + _cachedSourcesList.insert( + begin(_cachedSourcesList), + peerId); + ++_cachedSourceIndex; + } + } + // All that go after the current push to back. + for (auto after = index + 1, count = int(lists.size()); after != count; ++after) { + const auto peerId = lists[after].id; + if (!ranges::contains(_cachedSourcesList, peerId)) { + _cachedSourcesList.push_back(peerId); + } + } + } + + Ensures(_cachedSourcesList.size() == lists.size()); + Ensures(ranges::equal( + lists, + _cachedSourcesList, + ranges::equal_to(), + &Data::StoriesSourceInfo::id)); + Ensures(_cachedSourceIndex >= 0 && _cachedSourceIndex < _cachedSourcesList.size()); +} + void Controller::refreshViewsFromData() { Expects(shown()); diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.h b/Telegram/SourceFiles/media/stories/media_stories_controller.h index 96d1020736..405960f39e 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.h +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.h @@ -162,10 +162,7 @@ private: void setPlayingAllowed(bool allowed); void hideSiblings(); - void showSiblings( - not_null session, - const std::vector &lists, - int index); + void showSiblings(not_null session); void showSibling( std::unique_ptr &sibling, not_null session, @@ -186,6 +183,9 @@ private: void rebuildFromContext(not_null user, FullStoryId storyId); void checkMoveByDelta(); void loadMoreToList(); + void rebuildCachedSourcesList( + const std::vector &lists, + int index); void startReactionAnimation( Data::ReactionId id, @@ -227,6 +227,9 @@ private: bool _started = false; bool _viewed = false; + std::vector _cachedSourcesList; + int _cachedSourceIndex = -1; + ViewsSlice _viewsSlice; rpl::event_stream<> _moreViewsLoaded; base::has_weak_ptr _viewsLoadGuard;