From 4d9069b10a705321179a795bc416d5d3e27d2b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20W=C3=A5ngsell?= Date: Wed, 4 Jun 2025 09:54:11 +0200 Subject: [PATCH 1/2] Fixed feature to preserve the state (expansions and selection) in the 'Files' tab when switching between commits. --- src/Views/RevisionFileTreeView.axaml | 2 +- src/Views/RevisionFileTreeView.axaml.cs | 63 +++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/Views/RevisionFileTreeView.axaml b/src/Views/RevisionFileTreeView.axaml index 7266c4295..4cebde283 100644 --- a/src/Views/RevisionFileTreeView.axaml +++ b/src/Views/RevisionFileTreeView.axaml @@ -8,7 +8,7 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="SourceGit.Views.RevisionFileTreeView" x:Name="ThisControl"> - (); + foreach (var node in _rows) + { + if (node.IsExpanded) + { + expandedObjects.Add(node.Backend); + } + } + _tree.Clear(); _searchResult.Clear(); @@ -324,10 +337,51 @@ protected override async void OnPropertyChanged(AvaloniaPropertyChangedEventArgs Rows.Clear(); Rows.AddRange(topTree); + + _revisionFileRowsListBox ??= this.Find("RevisionFileRowsListBox"); + + if (_revisionFileRowsListBox is { IsArrangeValid: true }) + { + RestoreTreeState(expandedObjects, selectedNode); + } + GC.Collect(); } } + private void RestoreTreeState(List expandedObjects, RevisionFileTreeNode selectedNode) + { + for (int i = 0; i < _rows.Count; i++) + { + var revisionFileTreeNode = _rows[i]; + + if (!revisionFileTreeNode.IsFolder) + continue; + + if (expandedObjects.FirstOrDefault(o => o.SHA == revisionFileTreeNode.Backend.SHA || o.Path == revisionFileTreeNode.Backend.Path) != null) + { + ToggleNodeIsExpanded(revisionFileTreeNode); + } + } + + if (selectedNode != null) + { + foreach (var node in _rows) + { + if (node.Backend.SHA != selectedNode.Backend.SHA && node.Backend.Path != selectedNode.Backend.Path) + continue; + + selectedNode = node; + break; + } + } + + if (_revisionFileRowsListBox != null) + { + _revisionFileRowsListBox.SelectedItem = selectedNode; + } + } + private void OnTreeNodeContextRequested(object sender, ContextRequestedEventArgs e) { if (DataContext is ViewModels.CommitDetail { Repository: ViewModels.Repository repo, Commit: Models.Commit commit } vm && @@ -339,7 +393,7 @@ private void OnTreeNodeContextRequested(object sender, ContextRequestedEventArgs _ => CreateRevisionFileContextMenu(repo, vm, commit, obj), }; menu.Open(grid); - } + } e.Handled = true; } @@ -363,9 +417,9 @@ private async void OnRowsSelectionChanged(object sender, SelectionChangedEventAr if (sender is ListBox { SelectedItem: ViewModels.RevisionFileTreeNode { IsFolder: false } node }) await vm.ViewRevisionFileAsync(node.Backend); - else + else await vm.ViewRevisionFileAsync(null); - } + } private async Task> GetChildrenOfTreeNodeAsync(ViewModels.RevisionFileTreeNode node) { @@ -671,5 +725,6 @@ public ContextMenu CreateRevisionFileContextMenu(ViewModels.Repository repo, Vie private List _tree = []; private bool _disableSelectionChangingEvent = false; private List _searchResult = []; + private RevisionFileRowsListBox _revisionFileRowsListBox; } } From 876e2a3a6602f9f2a05fb3948073ff36c9e86f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20W?= Date: Mon, 4 Aug 2025 10:00:45 +0200 Subject: [PATCH 2/2] Rebase code, update it to use async handling, `Rows` instead of `_rows` --- src/Views/RevisionFileTreeView.axaml.cs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Views/RevisionFileTreeView.axaml.cs b/src/Views/RevisionFileTreeView.axaml.cs index f3b796182..539d2bea7 100644 --- a/src/Views/RevisionFileTreeView.axaml.cs +++ b/src/Views/RevisionFileTreeView.axaml.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; -using System.Linq; using System.IO; +using System.Linq; using System.Threading.Tasks; + using Avalonia; using Avalonia.Collections; using Avalonia.Controls; @@ -12,6 +13,7 @@ using Avalonia.Media; using Avalonia.Platform.Storage; using Avalonia.VisualTree; + using SourceGit.ViewModels; namespace SourceGit.Views @@ -134,7 +136,7 @@ protected override async void OnKeyDown(KeyEventArgs e) await App.CopyTextAsync(path); e.Handled = true; - } + } } else if (node.Backend is { Type: Models.ObjectType.Blob } file && e.Key == Key.S && @@ -300,7 +302,7 @@ protected override async void OnPropertyChanged(AvaloniaPropertyChangedEventArgs var selectedNode = _revisionFileRowsListBox?.SelectedItem as RevisionFileTreeNode; var expandedObjects = new List(); - foreach (var node in _rows) + foreach (var node in Rows) { if (node.IsExpanded) { @@ -349,24 +351,24 @@ protected override async void OnPropertyChanged(AvaloniaPropertyChangedEventArgs } } - private void RestoreTreeState(List expandedObjects, RevisionFileTreeNode selectedNode) + private async void RestoreTreeState(List expandedObjects, RevisionFileTreeNode selectedNode) { - for (int i = 0; i < _rows.Count; i++) + for (int i = 0; i < Rows.Count; i++) { - var revisionFileTreeNode = _rows[i]; + var revisionFileTreeNode = Rows[i]; if (!revisionFileTreeNode.IsFolder) continue; if (expandedObjects.FirstOrDefault(o => o.SHA == revisionFileTreeNode.Backend.SHA || o.Path == revisionFileTreeNode.Backend.Path) != null) { - ToggleNodeIsExpanded(revisionFileTreeNode); + await ToggleNodeIsExpandedAsync(revisionFileTreeNode); } } if (selectedNode != null) { - foreach (var node in _rows) + foreach (var node in Rows) { if (node.Backend.SHA != selectedNode.Backend.SHA && node.Backend.Path != selectedNode.Backend.Path) continue; @@ -393,7 +395,7 @@ private void OnTreeNodeContextRequested(object sender, ContextRequestedEventArgs _ => CreateRevisionFileContextMenu(repo, vm, commit, obj), }; menu.Open(grid); - } + } e.Handled = true; } @@ -417,9 +419,9 @@ private async void OnRowsSelectionChanged(object sender, SelectionChangedEventAr if (sender is ListBox { SelectedItem: ViewModels.RevisionFileTreeNode { IsFolder: false } node }) await vm.ViewRevisionFileAsync(node.Backend); - else + else await vm.ViewRevisionFileAsync(null); - } + } private async Task> GetChildrenOfTreeNodeAsync(ViewModels.RevisionFileTreeNode node) {