diff --git a/src/eepp/ui/tools/uidiffview.cpp b/src/eepp/ui/tools/uidiffview.cpp index 07fb6758d..c9457994a 100644 --- a/src/eepp/ui/tools/uidiffview.cpp +++ b/src/eepp/ui/tools/uidiffview.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -80,13 +81,17 @@ static Sprite* setImageViewerImage( UIImageViewer* viewer, Image* image ) { UIScrollView* UIDiffView::NewMultiFileDiffViewer( const std::string& patchText, const std::string& repoPath, ViewMode viewMode ) { + auto diffs = UIDiffView::splitDiff( patchText ); + auto* uiSceneNode = SceneManager::instance()->getUISceneNode(); + const bool wasLoading = uiSceneNode && uiSceneNode->isLoading(); + if ( uiSceneNode ) + uiSceneNode->setIsLoading( true ); + auto scrollView = UIScrollView::New(); auto vbox = UILinearLayout::NewVertical(); vbox->setParent( scrollView ); vbox->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent ); - auto diffs = UIDiffView::splitDiff( patchText ); - for ( const auto& diff : diffs ) { auto* diffView = UIDiffView::New(); diffView->setViewMode( viewMode ); @@ -98,6 +103,18 @@ UIScrollView* UIDiffView::NewMultiFileDiffViewer( const std::string& patchText, diffView->loadFromPatch( diff, "", "", repoPath ); } + if ( uiSceneNode ) { + uiSceneNode->setIsLoading( wasLoading ); + if ( !wasLoading ) { + // A diff view owns several editors, scroll bars, toggles and image viewers. Queueing + // each intermediate widget separately makes style invalidation scan an ever-growing + // dirty set. One recursive invalidation of the completed tree provides the same final + // styling. + uiSceneNode->invalidateStyle( scrollView, true ); + uiSceneNode->invalidateStyleState( scrollView, true, true ); + } + } + return scrollView; } diff --git a/src/tests/unit_tests/uidiffview_tests.cpp b/src/tests/unit_tests/uidiffview_tests.cpp index 006f095c4..ff4a1ad64 100644 --- a/src/tests/unit_tests/uidiffview_tests.cpp +++ b/src/tests/unit_tests/uidiffview_tests.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include using namespace EE; @@ -143,6 +144,25 @@ diff --git a/second.txt b/second.txt eeDelete( viewer ); } +UTEST( UIDiffView, MultiFileViewerHandlesLargePatches ) { + UIApplication app( WindowSettings{ 800, 600, "eepp - unit tests" } ); + app.getUI()->flushDirtyStyleAndLayout(); + constexpr size_t fileCount = 128; + std::string patchText; + patchText.reserve( fileCount * 160 ); + for ( size_t i = 0; i < fileCount; ++i ) { + const std::string fileName( "file" + std::to_string( i ) + ".txt" ); + patchText += "diff --git a/" + fileName + " b/" + fileName + "\n--- a/" + fileName + + "\n+++ b/" + fileName + "\n@@ -1 +1 @@\n-old\n+new\n"; + } + + auto* viewer = UIDiffView::NewMultiFileDiffViewer( patchText ); + EXPECT_EQ( fileCount, viewer->findAllByType( UI_TYPE_DIFF_VIEW ).size() ); + EXPECT_FALSE( viewer->getUISceneNode()->isLoading() ); + + eeDelete( viewer ); +} + UTEST( UIDiffView, LoadFromFileImageDiffUsesImageViewers ) { UIApplication app( WindowSettings{ 800, 600, "eepp - unit tests" } );