From e25ab04c491b1d603fc8035b8bf358e1d4cd142e Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 16 Mar 2026 19:41:47 +0800 Subject: [PATCH] feature: only create a new `FileHistoriesSingleRevision` instance if it is necessary after selecting a single item in `File History` (#2192) Signed-off-by: leo --- src/ViewModels/FileHistories.cs | 88 +++++++++++++++++++++----------- src/Views/FileHistories.axaml | 5 +- src/Views/FileHistories.axaml.cs | 30 +++++++++++ 3 files changed, 92 insertions(+), 31 deletions(-) diff --git a/src/ViewModels/FileHistories.cs b/src/ViewModels/FileHistories.cs index 722e450f..17d1fc05 100644 --- a/src/ViewModels/FileHistories.cs +++ b/src/ViewModels/FileHistories.cs @@ -2,10 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; - -using Avalonia.Collections; using Avalonia.Threading; - using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.ViewModels @@ -17,15 +14,27 @@ namespace SourceGit.ViewModels public bool CanOpenWithDefaultEditor { get; set; } = canOpenWithDefaultEditor; } + public class FileHistoriesSingleRevisionViewMode + { + public bool IsDiff + { + get; + set; + } = true; + } + public class FileHistoriesSingleRevision : ObservableObject { public bool IsDiffMode { - get => _isDiffMode; + get => _viewMode.IsDiff; set { - if (SetProperty(ref _isDiffMode, value)) + if (_viewMode.IsDiff != value) + { + _viewMode.IsDiff = value; RefreshViewContent(); + } } } @@ -35,17 +44,24 @@ namespace SourceGit.ViewModels set => SetProperty(ref _viewContent, value); } - public FileHistoriesSingleRevision(string repo, Models.FileVersion revision, bool prevIsDiffMode) + public FileHistoriesSingleRevision(string repo, Models.FileVersion revision, FileHistoriesSingleRevisionViewMode viewMode) { _repo = repo; _file = revision.Path; _revision = revision; - _isDiffMode = prevIsDiffMode; + _viewMode = viewMode; _viewContent = null; RefreshViewContent(); } + public void SetRevision(Models.FileVersion revision) + { + _file = revision.Path; + _revision = revision; + RefreshViewContent(); + } + public async Task ResetToSelectedRevisionAsync() { return await new Commands.Checkout(_repo) @@ -72,7 +88,7 @@ namespace SourceGit.ViewModels private void RefreshViewContent() { - if (_isDiffMode) + if (_viewMode.IsDiff) { ViewContent = new DiffContext(_repo, new(_revision), _viewContent as DiffContext); return; @@ -155,7 +171,7 @@ namespace SourceGit.ViewModels private string _repo = null; private string _file = null; private Models.FileVersion _revision = null; - private bool _isDiffMode = false; + private FileHistoriesSingleRevisionViewMode _viewMode = null; private object _viewContent = null; } @@ -226,11 +242,15 @@ namespace SourceGit.ViewModels set => SetProperty(ref _revisions, value); } - public AvaloniaList SelectedRevisions + public List SelectedRevisions { - get; - set; - } = []; + get => _selectedRevisions; + set + { + if (SetProperty(ref _selectedRevisions, value)) + RefreshViewContent(); + } + } public object ViewContent { @@ -257,23 +277,8 @@ namespace SourceGit.ViewModels { IsLoading = false; Revisions = revisions; - if (revisions.Count > 0) - SelectedRevisions.Add(revisions[0]); }); }); - - SelectedRevisions.CollectionChanged += (_, _) => - { - if (_viewContent is FileHistoriesSingleRevision singleRevision) - _prevIsDiffMode = singleRevision.IsDiffMode; - - ViewContent = SelectedRevisions.Count switch - { - 1 => new FileHistoriesSingleRevision(_repo, SelectedRevisions[0], _prevIsDiffMode), - 2 => new FileHistoriesCompareRevisions(_repo, SelectedRevisions[0], SelectedRevisions[1]), - _ => SelectedRevisions.Count, - }; - }; } public void NavigateToCommit(Models.FileVersion revision) @@ -303,10 +308,35 @@ namespace SourceGit.ViewModels return msg; } + private void RefreshViewContent() + { + var count = _selectedRevisions?.Count ?? 0; + if (count == 0) + { + ViewContent = null; + } + else if (count == 1) + { + if (_viewContent is FileHistoriesSingleRevision single) + single.SetRevision(_selectedRevisions[0]); + else + ViewContent = new FileHistoriesSingleRevision(_repo, _selectedRevisions[0], _viewMode); + } + else if (count == 2) + { + ViewContent = new FileHistoriesCompareRevisions(_repo, _selectedRevisions[0], _selectedRevisions[1]); + } + else + { + ViewContent = _selectedRevisions.Count; + } + } + private readonly string _repo = null; private bool _isLoading = true; - private bool _prevIsDiffMode = true; + private FileHistoriesSingleRevisionViewMode _viewMode = new(); private List _revisions = null; + private List _selectedRevisions = []; private Dictionary _fullCommitMessages = new(); private object _viewContent = null; } diff --git a/src/Views/FileHistories.axaml b/src/Views/FileHistories.axaml index f929b0a6..8b21e197 100644 --- a/src/Views/FileHistories.axaml +++ b/src/Views/FileHistories.axaml @@ -59,9 +59,10 @@ BorderThickness="1" Margin="8,4,4,8" BorderBrush="{DynamicResource Brush.Border2}" - ItemsSource="{Binding Revisions}" - SelectedItems="{Binding SelectedRevisions, Mode=TwoWay}" + ItemsSource="{Binding Revisions, Mode=OneWay}" SelectionMode="Multiple" + SelectionChanged="OnRevisionsSelectionChanged" + PropertyChanged="OnRevisionsPropertyChanged" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto"> diff --git a/src/Views/FileHistories.axaml.cs b/src/Views/FileHistories.axaml.cs index 749b4862..25254327 100644 --- a/src/Views/FileHistories.axaml.cs +++ b/src/Views/FileHistories.axaml.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; +using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Interactivity; @@ -14,6 +16,34 @@ namespace SourceGit.Views InitializeComponent(); } + private void OnRevisionsPropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) + { + if (e.Property == ListBox.ItemsSourceProperty && + sender is ListBox { Items: { Count: > 0 } } listBox) + listBox.SelectedIndex = 0; + } + + private void OnRevisionsSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (sender is ListBox listBox && DataContext is ViewModels.FileHistories vm) + { + if (listBox.SelectedItems is { } selected) + { + var revs = new List(); + foreach (var item in listBox.SelectedItems) + { + if (item is Models.FileVersion ver) + revs.Add(ver); + } + vm.SelectedRevisions = revs; + } + else + { + vm.SelectedRevisions = []; + } + } + } + private void OnPressCommitSHA(object sender, PointerPressedEventArgs e) { if (sender is TextBlock { DataContext: Models.FileVersion ver } &&