diff --git a/bin/assets/i18n/de.xml b/bin/assets/i18n/de.xml index 02ddbf361..d5861e19e 100644 --- a/bin/assets/i18n/de.xml +++ b/bin/assets/i18n/de.xml @@ -1292,6 +1292,7 @@ Für sichtbare Änderung ecode neu starten. Keine weiteren Commits Im Git-Verlauf anzeigen Git-Commit-Verlauf – %s + Geänderte Dateien (%zu) +%zu -%zu Commit-SHA Commit-SHA kopieren %s Zur geteilten Diff-Ansicht wechseln diff --git a/bin/assets/i18n/en.xml b/bin/assets/i18n/en.xml index 586295b0e..a2b7d6e32 100644 --- a/bin/assets/i18n/en.xml +++ b/bin/assets/i18n/en.xml @@ -1277,6 +1277,7 @@ Restart ecode to see the changes. No additional commits Show in Git History Git Commit History - %s + Changed files (%zu) +%zu -%zu Commit SHA Copy Commit SHA %s Switch to split diff view diff --git a/bin/assets/i18n/fr.xml b/bin/assets/i18n/fr.xml index de1ce5a2d..e68a81114 100644 --- a/bin/assets/i18n/fr.xml +++ b/bin/assets/i18n/fr.xml @@ -1276,6 +1276,7 @@ Redémarrer ecode pour voir les changements. Aucun commit supplémentaire Afficher dans l’historique Git Historique des commits Git – %s + Fichiers modifiés (%zu) +%zu -%zu SHA du commit Copier le SHA du commit %s Passer à la vue des différences séparée diff --git a/bin/assets/i18n/zh.xml b/bin/assets/i18n/zh.xml index de3b2502c..684bd63bb 100644 --- a/bin/assets/i18n/zh.xml +++ b/bin/assets/i18n/zh.xml @@ -1081,6 +1081,7 @@ file in the directory tree. 没有其他提交 在 Git 历史记录中显示 Git 提交历史记录 - %s + 已更改文件(%zu) +%zu -%zu 提交 SHA 复制提交 SHA %s 切换到拆分差异视图 diff --git a/include/eepp/ui/tools/uidiffview.hpp b/include/eepp/ui/tools/uidiffview.hpp index a00b917ec..c9185c0ee 100644 --- a/include/eepp/ui/tools/uidiffview.hpp +++ b/include/eepp/ui/tools/uidiffview.hpp @@ -17,11 +17,14 @@ class Sprite; namespace UI { class UIScrollView; +class UIPushButton; +class UITextView; namespace Tools { class UIImageViewer; class UIDiffEditorPlugin; +class UIMultiDiffView; class EE_API UIDiffView : public UIWidget, public WidgetCommandExecuter { public: @@ -182,6 +185,8 @@ class EE_API UIDiffView : public UIWidget, public WidgetCommandExecuter { std::string mImageDiffOldPath; std::string mImageDiffNewPath; + friend class UIMultiDiffView; + UIDiffView(); virtual void onSizePolicyChange() override; @@ -231,6 +236,67 @@ class EE_API UIDiffView : public UIWidget, public WidgetCommandExecuter { void updateFileHeaderInfo(); }; +class EE_API UIMultiDiffView : public UILinearLayout { + public: + static UIMultiDiffView* New( const std::string& patchText, const std::string& repoPath = "", + UIDiffView::ViewMode viewMode = UIDiffView::ViewMode::Unified, + bool interactiveFileHeaders = false ); + + static UIMultiDiffView* New( std::shared_ptr preparedDiff, + const std::string& repoPath = "", + UIDiffView::ViewMode viewMode = UIDiffView::ViewMode::Unified, + bool interactiveFileHeaders = false ); + + const std::vector& getDiffViews() const { return mDiffViews; } + + UIScrollView* getScrollView() const { return mScrollView; } + + void setViewMode( UIDiffView::ViewMode mode ); + + UIDiffView::ViewMode getViewMode() const { return mViewMode; } + + void setCollapsed( bool collapsed ); + + bool isCollapsed() const { return mCollapsed; } + + void setToolbarVisible( bool visible ); + + bool isToolbarVisible() const; + + size_t getFileCount() const { return mFileCount; } + + size_t getAddedLines() const { return mAddedLines; } + + size_t getRemovedLines() const { return mRemovedLines; } + + protected: + UILinearLayout* mToolbar{ nullptr }; + UIPushButton* mFilesToggle{ nullptr }; + UIPushButton* mModeToggle{ nullptr }; + UITextView* mFilesStatus{ nullptr }; + UIScrollView* mScrollView{ nullptr }; + std::vector mDiffViews; + UIDiffView::ViewMode mViewMode{ UIDiffView::ViewMode::Unified }; + size_t mFileCount{ 0 }; + size_t mAddedLines{ 0 }; + size_t mRemovedLines{ 0 }; + bool mCollapsed{ false }; + + UIMultiDiffView(); + + void load( std::shared_ptr preparedDiff, + const std::string& repoPath, UIDiffView::ViewMode viewMode, + bool interactiveFileHeaders ); + + void updateFilesToggle(); + + void updateModeToggle(); + + void updateStatus(); + + virtual void onThemeLoaded() override; +}; + } // namespace Tools } // namespace UI } // namespace EE diff --git a/src/eepp/ui/tools/uidiffview.cpp b/src/eepp/ui/tools/uidiffview.cpp index b7b69e6cc..4e12b4577 100644 --- a/src/eepp/ui/tools/uidiffview.cpp +++ b/src/eepp/ui/tools/uidiffview.cpp @@ -14,10 +14,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -38,6 +40,8 @@ struct UIDiffView::PreparedPatch { class UIDiffView::PreparedMultiFileDiff { public: std::vector patches; + size_t addedLines{ 0 }; + size_t removedLines{ 0 }; }; static bool imagesHaveSameDimensions( const std::string& oldFilePath, @@ -160,6 +164,201 @@ void UIDiffView::setMultiFileCollapsed( UIScrollView* multiDiff, bool collapsed diff->setCollapsed( collapsed ); } +UIMultiDiffView* UIMultiDiffView::New( const std::string& patchText, const std::string& repoPath, + UIDiffView::ViewMode viewMode, + bool interactiveFileHeaders ) { + return New( UIDiffView::prepareMultiFileDiff( patchText ), repoPath, viewMode, + interactiveFileHeaders ); +} + +UIMultiDiffView* +UIMultiDiffView::New( std::shared_ptr preparedDiff, + const std::string& repoPath, UIDiffView::ViewMode viewMode, + bool interactiveFileHeaders ) { + if ( !preparedDiff ) + return nullptr; + auto* view = eeNew( UIMultiDiffView, () ); + view->load( std::move( preparedDiff ), repoPath, viewMode, interactiveFileHeaders ); + return view; +} + +UIMultiDiffView::UIMultiDiffView() : UILinearLayout( "multidiffview", UIOrientation::Vertical ) { + beginAttributesTransaction(); + + setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent ); + + mToolbar = UILinearLayout::NewHorizontal(); + mToolbar->setParent( this ); + mToolbar->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent ); + mToolbar->setPadding( Rectf( 8, 4, 8, 4 ) ); + + mFilesToggle = UIPushButton::New(); + mFilesToggle->setParent( mToolbar ); + mFilesToggle->addClass( "git_commit_btn" ); + mFilesToggle->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::WrapContent ); + mFilesToggle->onClick( [this]( const Event* ) { setCollapsed( !mCollapsed ); } ); + + mModeToggle = UIPushButton::New(); + mModeToggle->setParent( mToolbar ); + mModeToggle->addClass( "git_commit_btn" ); + mModeToggle->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::WrapContent ); + mModeToggle->setLayoutMarginLeft( 4 ); + mModeToggle->setTextAsFallback( true ); + mModeToggle->onClick( [this]( const Event* ) { + setViewMode( mViewMode == UIDiffView::ViewMode::Unified ? UIDiffView::ViewMode::SideBySide + : UIDiffView::ViewMode::Unified ); + } ); + + mFilesStatus = UITextView::New(); + mFilesStatus->setParent( mToolbar ); + mFilesStatus->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::WrapContent ); + mFilesStatus->setLayoutWeight( 1 ); + mFilesStatus->setLayoutMarginLeft( 8 ); + mFilesStatus->setGravity( UI_VALIGN_CENTER ); + mFilesStatus->setLayoutGravity( UI_VALIGN_CENTER ); + mFilesStatus->setUsingCustomStyling( true ); + + mScrollView = UIScrollView::New(); + mScrollView->setParent( this ); + mScrollView->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::Fixed ); + mScrollView->setLayoutWeight( 1 ); + + endAttributesTransaction(); +} + +void UIMultiDiffView::load( std::shared_ptr preparedDiff, + const std::string& repoPath, UIDiffView::ViewMode viewMode, + bool interactiveFileHeaders ) { + auto* uiSceneNode = SceneManager::instance()->getUISceneNode(); + const bool wasLoading = uiSceneNode && uiSceneNode->isLoading(); + if ( uiSceneNode ) + uiSceneNode->setIsLoading( true ); + + mViewMode = viewMode; + mFileCount = preparedDiff->patches.size(); + mAddedLines = preparedDiff->addedLines; + mRemovedLines = preparedDiff->removedLines; + auto* content = UILinearLayout::NewVertical(); + content->setParent( mScrollView ); + content->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent ); + mDiffViews.reserve( preparedDiff->patches.size() ); + for ( auto& patch : preparedDiff->patches ) { + auto* diffView = UIDiffView::New(); + diffView->setViewMode( viewMode ); + diffView->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent ); + diffView->setParent( content ); + diffView->setHeadersVisible( true ); + diffView->setViewModeToggleVisible( false ); + diffView->setCompleteViewToggleVisible( false ); + diffView->setInteractiveFileHeader( interactiveFileHeaders ); + diffView->loadPreparedPatch( std::move( patch ), "", "", repoPath ); + mDiffViews.emplace_back( diffView ); + } + + updateFilesToggle(); + updateModeToggle(); + updateStatus(); + if ( uiSceneNode ) { + uiSceneNode->setIsLoading( wasLoading ); + if ( !wasLoading ) { + uiSceneNode->invalidateStyle( this, true ); + uiSceneNode->invalidateStyleState( this, true, true ); + } + } +} + +void UIMultiDiffView::setViewMode( UIDiffView::ViewMode mode ) { + if ( mViewMode == mode ) + return; + mViewMode = mode; + for ( auto* diff : mDiffViews ) + diff->setViewMode( mode ); + updateModeToggle(); +} + +void UIMultiDiffView::setCollapsed( bool collapsed ) { + if ( mCollapsed == collapsed ) + return; + mCollapsed = collapsed; + for ( auto* diff : mDiffViews ) + diff->setCollapsed( collapsed ); + updateFilesToggle(); +} + +void UIMultiDiffView::setToolbarVisible( bool visible ) { + mToolbar->setVisible( visible ); +} + +bool UIMultiDiffView::isToolbarVisible() const { + return mToolbar->isVisible(); +} + +void UIMultiDiffView::updateFilesToggle() { + const String text = mCollapsed ? i18n( "git_expand_all_files", "Expand All Files" ) + : i18n( "git_collapse_all_files", "Collapse All Files" ); + mFilesToggle->setTooltipText( text ); + if ( auto* scene = getUISceneNode() ) { + if ( auto* icon = scene->findIcon( mCollapsed ? "expand-all" : "collapse-all" ) ) + mFilesToggle->setIcon( icon->createDrawable( PixelDensity::dpToPxI( 12 ) ) ); + } + mFilesToggle->setText( mFilesToggle->hasIcon() ? String{} : text ); +} + +void UIMultiDiffView::updateModeToggle() { + const bool unified = mViewMode == UIDiffView::ViewMode::Unified; + mModeToggle->setText( unified ? i18n( "git_split_diff", "Split" ) + : i18n( "git_unified_diff", "Unified" ) ); + mModeToggle->setTooltipText( + unified ? i18n( "git_switch_to_split_diff", "Switch to split diff view" ) + : i18n( "git_switch_to_unified_diff", "Switch to unified diff view" ) ); + if ( auto* scene = getUISceneNode() ) { + if ( auto* icon = scene->findIcon( unified ? "split-horizontal" : "layout" ) ) + mModeToggle->setIcon( icon->createDrawable( PixelDensity::dpToPxI( 12 ) ) ); + } +} + +void UIMultiDiffView::updateStatus() { + mFilesStatus->setText( String::format( + i18n( "git_changed_files_summary", "Changed files (%zu) +%zu -%zu" ).toUtf8(), mFileCount, + mAddedLines, mRemovedLines ) ); + if ( auto* scene = getUISceneNode(); + scene && scene->getRoot() && scene->getRoot()->getUIStyle() ) { + auto* root = scene->getRoot(); + auto font = root->getUIStyle()->getVariable( "--font" ); + auto warning = root->getUIStyle()->getVariable( "--theme-warning" ); + auto success = root->getUIStyle()->getVariable( "--theme-success" ); + auto error = root->getUIStyle()->getVariable( "--theme-error" ); + std::vector patterns; + patterns.emplace_back( SyntaxPattern( { ".*%((%d+)%)%s+(%+%d+)%s+(%-%d+)" }, + { "normal", "warning", "keyword", "type" } ) ); + SyntaxDefinition definition( "multi_diff_files_status", {}, std::move( patterns ) ); + SyntaxColorScheme scheme( + "multi_diff_files_status", + { { "normal"_sst, + { font.isEmpty() ? mFilesStatus->getFontColor() + : Color::fromString( font.getValue() ) } }, + { "warning"_sst, + { warning.isEmpty() ? Color( 220, 170, 0 ) + : Color::fromString( warning.getValue() ) } }, + { "keyword"_sst, + { success.isEmpty() ? Color( 0, 180, 60 ) + : Color::fromString( success.getValue() ) } }, + { "type"_sst, + { error.isEmpty() ? Color( 220, 50, 70 ) + : Color::fromString( error.getValue() ) } } }, + {} ); + SyntaxTokenizer::tokenizeText( definition, scheme, mFilesStatus->getTextCache() ); + mFilesStatus->invalidateDraw(); + } +} + +void UIMultiDiffView::onThemeLoaded() { + UILinearLayout::onThemeLoaded(); + updateFilesToggle(); + updateModeToggle(); + updateStatus(); +} + class UIDiffEditorPlugin : public UICodeEditorPlugin { public: UIDiffEditorPlugin( UIDiffView* view ) : mView( view ) {} @@ -1410,8 +1609,12 @@ UIDiffView::prepareMultiFileDiff( const std::string& patchText, for ( const auto& diff : diffs ) { if ( cancelled && cancelled->load( std::memory_order_relaxed ) ) return {}; - prepared->patches.emplace_back( - preparePatch( diff, "", SubLineDiffAlgorithm::LCS, cancelled ) ); + auto patch = preparePatch( diff, "", SubLineDiffAlgorithm::LCS, cancelled ); + for ( const auto& line : patch.lines ) { + prepared->addedLines += line.type == DiffLineType::Added; + prepared->removedLines += line.type == DiffLineType::Removed; + } + prepared->patches.emplace_back( std::move( patch ) ); } if ( cancelled && cancelled->load( std::memory_order_relaxed ) ) diff --git a/src/tests/unit_tests/uidiffview_tests.cpp b/src/tests/unit_tests/uidiffview_tests.cpp index e500b9022..4d4781efb 100644 --- a/src/tests/unit_tests/uidiffview_tests.cpp +++ b/src/tests/unit_tests/uidiffview_tests.cpp @@ -125,10 +125,13 @@ diff --git a/second.txt b/second.txt +after )patch"; - auto* viewer = - UIDiffView::NewMultiFileDiffViewer( patchText, "", UIDiffView::ViewMode::SideBySide, true ); - auto diffViews = viewer->findAllByType( UI_TYPE_DIFF_VIEW ); + auto* viewer = UIMultiDiffView::New( patchText, "", UIDiffView::ViewMode::SideBySide, true ); + const auto& diffViews = viewer->getDiffViews(); ASSERT_EQ( size_t{ 2 }, diffViews.size() ); + EXPECT_EQ( size_t{ 2 }, viewer->getFileCount() ); + EXPECT_EQ( size_t{ 2 }, viewer->getAddedLines() ); + EXPECT_EQ( size_t{ 2 }, viewer->getRemovedLines() ); + EXPECT_TRUE( viewer->isToolbarVisible() ); for ( const auto* diffView : diffViews ) { EXPECT_EQ( UIDiffView::ViewMode::SideBySide, diffView->getViewMode() ); EXPECT_FALSE( diffView->isViewModeToggleVisible() ); @@ -136,14 +139,16 @@ diff --git a/second.txt b/second.txt EXPECT_TRUE( diffView->isInteractiveFileHeader() ); } - UIDiffView::setMultiFileViewMode( viewer, UIDiffView::ViewMode::Unified ); - UIDiffView::setMultiFileCollapsed( viewer, true ); + viewer->setViewMode( UIDiffView::ViewMode::Unified ); + viewer->setCollapsed( true ); + EXPECT_EQ( UIDiffView::ViewMode::Unified, viewer->getViewMode() ); + EXPECT_TRUE( viewer->isCollapsed() ); for ( const auto* diffView : diffViews ) { EXPECT_EQ( UIDiffView::ViewMode::Unified, diffView->getViewMode() ); EXPECT_TRUE( diffView->isCollapsed() ); EXPECT_TRUE( diffView->getViewLines().empty() ); } - UIDiffView::setMultiFileCollapsed( viewer, false ); + viewer->setCollapsed( false ); for ( const auto* diffView : diffViews ) { EXPECT_FALSE( diffView->isCollapsed() ); EXPECT_FALSE( diffView->getViewLines().empty() ); @@ -202,8 +207,8 @@ UTEST( UIDiffView, MultiFileViewerHandlesLargePatches ) { "\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() ); + auto* viewer = UIMultiDiffView::New( patchText ); + EXPECT_EQ( fileCount, viewer->getDiffViews().size() ); EXPECT_TRUE( viewer->findAllByType( UI_TYPE_IMAGE_VIEWER ).empty() ); EXPECT_FALSE( viewer->getUISceneNode()->isLoading() ); diff --git a/src/tests/unit_tests/uiscenenode_tests.cpp b/src/tests/unit_tests/uiscenenode_tests.cpp index 26b9ebfdc..b5d28f40a 100644 --- a/src/tests/unit_tests/uiscenenode_tests.cpp +++ b/src/tests/unit_tests/uiscenenode_tests.cpp @@ -140,7 +140,7 @@ UTEST( UIApplication, CreatesSecondaryWindowWithoutChangingAmbientScene ) { secondaryUI->getWindow()->getInput()->beginInputFrame(); primaryWindow->getInput()->processEventForWindow( &textEvent ); secondaryUI->getWindow()->getInput()->endInputFrame(); - EXPECT_STREQ( textInput->getText().toUtf8().c_str(), "x" ); + EXPECT_STDSTREQ( textInput->getText().toUtf8(), "x" ); } EXPECT_EQ( SceneManager::instance()->getUISceneNode(), app.getUI() ); diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 8a79ddb2e..393851c28 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -2663,21 +2663,16 @@ void App::loadDiffFromMemory( const std::string& content, const std::string& ori if ( !icon ) icon = getUISceneNode()->findIcon( "file" ); - auto scrollView = UIDiffView::NewMultiFileDiffViewer( - content, repoPath, mConfig.editor.diffViewMode, interactiveFileHeaders ); - auto [tab, iv] = getSplitter()->createWidget( scrollView, diffViewTitle ); + auto multiDiff = UIMultiDiffView::New( content, repoPath, mConfig.editor.diffViewMode, + interactiveFileHeaders ); + auto [tab, iv] = getSplitter()->createWidget( multiDiff, diffViewTitle ); if ( icon ) tab->setIcon( icon->createDrawable( getMenuIconSize() ) ); tab->setText( diffViewTitle ); - auto diffView = scrollView->getFirstChild()->asType()->getFirstChild(); - - while ( diffView ) { - if ( diffView->isType( UI_TYPE_DIFF_VIEW ) ) { - configureDiffView( diffView->asType() ); - diffView->asType()->setSyntaxColorScheme( *getCurrentColorScheme() ); - } - diffView = diffView->getNextNode(); + for ( auto* diffView : multiDiff->getDiffViews() ) { + configureDiffView( diffView ); + diffView->setSyntaxColorScheme( *getCurrentColorScheme() ); } return; } @@ -2719,21 +2714,15 @@ void App::loadDiffFromPath( const std::string& path ) { if ( !icon ) icon = getUISceneNode()->findIcon( "file" ); - auto scrollView = - UIDiffView::NewMultiFileDiffViewer( content, "", mConfig.editor.diffViewMode ); - auto [tab, iv] = getSplitter()->createWidget( scrollView, diffViewTitle ); + auto multiDiff = UIMultiDiffView::New( content, "", mConfig.editor.diffViewMode ); + auto [tab, iv] = getSplitter()->createWidget( multiDiff, diffViewTitle ); if ( icon ) tab->setIcon( icon->createDrawable( getMenuIconSize() ) ); tab->setText( diffViewTitle ); - auto diffView = scrollView->getFirstChild()->asType()->getFirstChild(); - - while ( diffView ) { - if ( diffView->isType( UI_TYPE_DIFF_VIEW ) ) { - configureDiffView( diffView->asType() ); - diffView->asType()->setSyntaxColorScheme( *getCurrentColorScheme() ); - } - diffView = diffView->getNextNode(); + for ( auto* diffView : multiDiff->getDiffViews() ) { + configureDiffView( diffView ); + diffView->setSyntaxColorScheme( *getCurrentColorScheme() ); } return; } diff --git a/src/tools/ecode/plugins/git/gitplugin.cpp b/src/tools/ecode/plugins/git/gitplugin.cpp index 6bfb22c98..8e72b9b52 100644 --- a/src/tools/ecode/plugins/git/gitplugin.cpp +++ b/src/tools/ecode/plugins/git/gitplugin.cpp @@ -646,28 +646,6 @@ void GitPlugin::updateStatusBarSync() { mStatusButton->invalidateDraw(); } -void GitPlugin::styleCommitFilesStatus( UITextView* status ) { - if ( !status ) - return; - status->setUsingCustomStyling( true ); - if ( !mCommitStatusCustomTokenizer.has_value() ) { - std::vector patterns; - patterns.emplace_back( SyntaxPattern( { ".*%((%d+)%)%s+(%+%d+)%s+(%-%d+)" }, - { "normal", "warning", "keyword", "type" } ) ); - SyntaxDefinition syntaxDef( "git_commit_files_status", {}, std::move( patterns ) ); - SyntaxColorScheme scheme( "git_commit_files_status", - { { "normal"_sst, { getVarColor( "--font" ) } }, - { "warning"_sst, { getVarColor( "--theme-warning" ) } }, - { "keyword"_sst, { getVarColor( "--theme-success" ) } }, - { "type"_sst, { getVarColor( "--theme-error" ) } } }, - {} ); - mCommitStatusCustomTokenizer = { std::move( syntaxDef ), std::move( scheme ) }; - } - SyntaxTokenizer::tokenizeText( mCommitStatusCustomTokenizer->def, - mCommitStatusCustomTokenizer->scheme, status->getTextCache() ); - status->invalidateDraw(); -} - void GitPlugin::updateStatus( bool force ) { if ( !mGit || !mGitFound ) return; @@ -843,9 +821,6 @@ PluginRequestHandle GitPlugin::processMessage( const PluginMessage& msg ) { } case ecode::PluginMessageType::UIThemeReloaded: { mStatusCustomTokenizer.reset(); - mCommitStatusCustomTokenizer.reset(); - styleCommitFilesStatus( mCommitDetails.status ); - styleCommitFilesStatus( mDetachedHistory.details.status ); updateUINow( true ); break; } @@ -3060,19 +3035,8 @@ void GitPlugin::CommitDetailsState::openCommitDetails( GitPlugin& plugin, const - - - - - + )xml" ); @@ -3086,8 +3050,6 @@ void GitPlugin::CommitDetailsState::openCommitDetails( GitPlugin& plugin, const view->bind( "git_commit_message", message ); view->bind( "git_commit_files_status", status ); view->bind( "git_commit_message_toggle", messageToggle ); - view->bind( "git_commit_files_toggle", filesToggle ); - view->bind( "git_commit_mode_toggle", modeToggle ); view->bind( "git_commit_github", gitHub ); view->bind( "git_commit_diff", diffContainer ); messageToggle->onClick( [owner, state]( const Event* ) { @@ -3099,34 +3061,6 @@ void GitPlugin::CommitDetailsState::openCommitDetails( GitPlugin& plugin, const "Collapse Commit Description" ) : owner->i18n( "git_expand_commit_description", "Expand Commit Description" ) ); } ); - filesToggle->onClick( [owner, state]( const Event* ) { - state->filesCollapsed = !state->filesCollapsed; - UIDiffView::setMultiFileCollapsed( state->diff, state->filesCollapsed ); - state->filesToggle->setTooltipText( - state->filesCollapsed - ? owner->i18n( "git_expand_all_files", "Expand All Files" ) - : owner->i18n( "git_collapse_all_files", "Collapse All Files" ) ); - if ( auto* icon = - owner->findIcon( state->filesCollapsed ? "expand-all" : "collapse-all" ) ) - state->filesToggle->setIcon( icon->createDrawable( PixelDensity::dpToPxI( 12 ) ) ); - } ); - modeToggle->onClick( [owner, state]( const Event* ) { - state->viewMode = state->viewMode == UIDiffView::ViewMode::Unified - ? UIDiffView::ViewMode::SideBySide - : UIDiffView::ViewMode::Unified; - UIDiffView::setMultiFileViewMode( state->diff, state->viewMode ); - state->modeToggle->setText( state->viewMode == UIDiffView::ViewMode::Unified - ? owner->i18n( "git_split_diff", "Split" ) - : owner->i18n( "git_unified_diff", "Unified" ) ); - state->modeToggle->setTooltipText( - state->viewMode == UIDiffView::ViewMode::Unified - ? owner->i18n( "git_switch_to_split_diff", "Switch to split diff view" ) - : owner->i18n( "git_switch_to_unified_diff", "Switch to unified diff view" ) ); - if ( auto* icon = owner->findIcon( state->viewMode == UIDiffView::ViewMode::Unified - ? "split-horizontal" - : "layout" ) ) - state->modeToggle->setIcon( icon->createDrawable( PixelDensity::dpToPxI( 12 ) ) ); - } ); gitHub->onClick( [state]( const Event* ) { if ( !state->url.empty() ) Engine::instance()->openURI( state->url ); @@ -3158,11 +3092,7 @@ void GitPlugin::CommitDetailsState::openCommitDetails( GitPlugin& plugin, const message->setVisible( false ); messageToggle->setVisible( false ); status->setText( plugin.i18n( "git_loading_changed_files", "Loading changed files..." ) ); - plugin.styleCommitFilesStatus( status ); - filesCollapsed = false; - filesToggle->setTooltipText( plugin.i18n( "git_collapse_all_files", "Collapse All Files" ) ); - if ( auto* icon = plugin.findIcon( "collapse-all" ) ) - filesToggle->setIcon( icon->createDrawable( PixelDensity::dpToPxI( 12 ) ) ); + status->setVisible( true ); url.clear(); gitHub->setVisible( false ); view->find( "git_commit_sha" )->setVisible( !isWorkingTree ); @@ -3233,7 +3163,6 @@ void GitPlugin::CommitDetailsState::loadCommitFiles( GitPlugin& plugin, bool det details.status->setText( plugin->i18n( "git_changed_files_error", "Could not load changed files" ) + ( result.result.empty() ? "" : ": " + result.result ) ); - plugin->styleCommitFilesStatus( details.status ); return; } std::string message = std::move( result.message ); @@ -3258,42 +3187,28 @@ void GitPlugin::CommitDetailsState::loadCommitFiles( GitPlugin& plugin, bool det details.messageToggle->setText( plugin->i18n( "git_expand_commit_description", "Expand Commit Description" ) ); - int totalInserts = 0; - int totalDeletes = 0; - for ( const auto& file : result.files ) { - totalInserts += file.inserts; - totalDeletes += file.deletes; - } if ( result.files.empty() ) { details.status->setText( plugin->i18n( "git_no_changed_files", "No changed files" ) ); } else { - details.status->setText( String::format( - plugin->i18n( "git_changed_files_summary", "Changed files (%zu) +%d -%d" ) - .toUtf8(), - result.files.size(), totalInserts, totalDeletes ) ); + details.status->setVisible( false ); } - plugin->styleCommitFilesStatus( details.status ); details.url = std::move( result.commitURL ); details.gitHub->setVisible( !details.url.empty() ); details.diffContainer->closeAllChildren(); details.diff = nullptr; if ( preparedDiff ) { - details.diff = UIDiffView::NewMultiFileDiffViewer( std::move( preparedDiff ), repo, - details.viewMode ); + details.diff = UIMultiDiffView::New( std::move( preparedDiff ), repo, + UIDiffView::ViewMode::Unified, true ); details.diff->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent ); details.diff->setParent( details.diffContainer ); - for ( auto* diff : UIDiffView::multiFileDiffViews( details.diff ) ) { - diff->setInteractiveFileHeader( true ); + for ( auto* diff : details.diff->getDiffViews() ) { if ( const auto* scheme = plugin->getPluginContext()->getCurrentColorScheme() ) diff->setSyntaxColorScheme( *scheme ); } } - const bool hasDiff = details.diff != nullptr; - details.filesToggle->setVisible( hasDiff ); - details.modeToggle->setVisible( hasDiff ); } ); } ); } @@ -3496,6 +3411,16 @@ void GitPlugin::buildSidePanelTab() { #git_commit_details .git_commit_btn:hover { border-color: var(--primary); } + multidiffview .git_commit_btn { + lw: 20dp; + lh: 20dp; + padding: 0; + background-color: var(--list-back); + border-color: transparent; + } + multidiffview .git_commit_btn:hover { + border-color: var(--primary); + } #git_commit_details #git_commit_author { font-size: 11dp; text-stroke-width: 1dp; diff --git a/src/tools/ecode/plugins/git/gitplugin.hpp b/src/tools/ecode/plugins/git/gitplugin.hpp index 078880554..69a8c22cb 100644 --- a/src/tools/ecode/plugins/git/gitplugin.hpp +++ b/src/tools/ecode/plugins/git/gitplugin.hpp @@ -178,11 +178,9 @@ class GitPlugin : public PluginBase { UITextView* message{ nullptr }; UITextView* status{ nullptr }; UIPushButton* messageToggle{ nullptr }; - UIPushButton* filesToggle{ nullptr }; - UIPushButton* modeToggle{ nullptr }; UIPushButton* gitHub{ nullptr }; UIWidget* diffContainer{ nullptr }; - UIScrollView* diff{ nullptr }; + Tools::UIMultiDiffView* diff{ nullptr }; std::string messageBody; std::string url; Git::Commit commit; @@ -190,9 +188,7 @@ class GitPlugin : public PluginBase { std::atomic generation{ 0 }; std::shared_ptr diffPreparationCancelled; EventConnection closeConnection; - Tools::UIDiffView::ViewMode viewMode{ Tools::UIDiffView::ViewMode::Unified }; bool messageExpanded{ false }; - bool filesCollapsed{ false }; bool workingTree{ false }; void openCommitDetails( GitPlugin& plugin, const Git::Commit& commit, bool detached, @@ -216,8 +212,6 @@ class GitPlugin : public PluginBase { message = nullptr; status = nullptr; messageToggle = nullptr; - filesToggle = nullptr; - modeToggle = nullptr; gitHub = nullptr; diffContainer = nullptr; diff = nullptr; @@ -225,9 +219,7 @@ class GitPlugin : public PluginBase { url.clear(); commit = {}; repo.clear(); - viewMode = Tools::UIDiffView::ViewMode::Unified; messageExpanded = false; - filesCollapsed = false; workingTree = false; } }; @@ -278,7 +270,6 @@ class GitPlugin : public PluginBase { SyntaxColorScheme scheme; }; std::optional mStatusCustomTokenizer; - std::optional mCommitStatusCustomTokenizer; std::optional mTooltipCustomSyntaxDef; Uint32 mModelChangedId{ 0 }; Uint32 mModelStylerId{ 0 }; @@ -365,8 +356,6 @@ class GitPlugin : public PluginBase { void updateStatusBarSync(); - void styleCommitFilesStatus( UITextView* status ); - void updateUI(); void updateUINow( bool force = false );