ux: improve change list selection

This commit is contained in:
leo 2024-07-16 17:00:08 +08:00
parent 2f5f98770f
commit ef0c904e91
No known key found for this signature in database
5 changed files with 132 additions and 88 deletions

View file

@ -164,7 +164,7 @@ namespace SourceGit.Models
private void OnRepositoryChanged(object o, FileSystemEventArgs e)
{
if (string.IsNullOrEmpty(e.Name))
if (string.IsNullOrEmpty(e.Name) || e.Name.EndsWith(".lock", StringComparison.Ordinal))
return;
var name = e.Name.Replace("\\", "/");

View file

@ -8,15 +8,18 @@ namespace SourceGit.ViewModels
{
public List<ChangeTreeNode> Tree { get; set; } = new List<ChangeTreeNode>();
public AvaloniaList<ChangeTreeNode> Rows { get; set; } = new AvaloniaList<ChangeTreeNode>();
public AvaloniaList<ChangeTreeNode> SelectedRows { get; set; } = new AvaloniaList<ChangeTreeNode>();
}
public class ChangeCollectionAsGrid
{
public AvaloniaList<Models.Change> Changes { get; set; } = new AvaloniaList<Models.Change>();
public AvaloniaList<Models.Change> SelectedChanges { get; set; } = new AvaloniaList<Models.Change>();
}
public class ChangeCollectionAsList
{
public AvaloniaList<Models.Change> Changes { get; set; } = new AvaloniaList<Models.Change>();
public AvaloniaList<Models.Change> SelectedChanges { get; set; } = new AvaloniaList<Models.Change>();
}
}

View file

@ -301,11 +301,13 @@ namespace SourceGit.ViewModels
public void StageSelected()
{
StageChanges(_selectedUnstaged);
SelectedUnstaged = [];
}
public void StageAll()
{
StageChanges(_unstaged);
SelectedUnstaged = [];
}
public async void StageChanges(List<Models.Change> changes)
@ -337,11 +339,13 @@ namespace SourceGit.ViewModels
public void UnstageSelected()
{
UnstageChanges(_selectedStaged);
SelectedStaged = [];
}
public void UnstageAll()
{
UnstageChanges(_staged);
SelectedStaged = [];
}
public async void UnstageChanges(List<Models.Change> changes)

View file

@ -31,6 +31,7 @@
<UserControl.DataTemplates>
<DataTemplate DataType="vm:ChangeCollectionAsTree">
<v:ChangeCollectionContainer ItemsSource="{Binding Rows}"
SelectedItems="{Binding SelectedRows, Mode=TwoWay}"
SelectionMode="{Binding #ThisControl.SelectionMode}"
SelectionChanged="OnRowSelectionChanged">
<ListBox.ItemTemplate>
@ -65,6 +66,7 @@
<DataTemplate DataType="vm:ChangeCollectionAsGrid">
<v:ChangeCollectionContainer ItemsSource="{Binding Changes}"
SelectedItems="{Binding SelectedChanges, Mode=TwoWay}"
SelectionMode="{Binding #ThisControl.SelectionMode}"
SelectionChanged="OnRowSelectionChanged">
<ListBox.ItemTemplate>
@ -93,6 +95,7 @@
<DataTemplate DataType="vm:ChangeCollectionAsList">
<v:ChangeCollectionContainer ItemsSource="{Binding Changes}"
SelectedItems="{Binding SelectedChanges, Mode=TwoWay}"
SelectionMode="{Binding #ThisControl.SelectionMode}"
SelectionChanged="OnRowSelectionChanged">
<ListBox.ItemTemplate>

View file

@ -6,6 +6,7 @@ using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Avalonia.VisualTree;
namespace SourceGit.Views
@ -101,7 +102,7 @@ namespace SourceGit.Views
public void ToggleNodeIsExpanded(ViewModels.ChangeTreeNode node)
{
if (_displayContext is ViewModels.ChangeCollectionAsTree tree)
if (Content is ViewModels.ChangeCollectionAsTree tree)
{
node.IsExpanded = !node.IsExpanded;
@ -136,92 +137,12 @@ namespace SourceGit.Views
{
base.OnPropertyChanged(change);
if (change.Property == ViewModeProperty || change.Property == ChangesProperty)
{
_disableSelectionChangingEvent = change.Property == ChangesProperty;
var changes = Changes;
if (changes == null || changes.Count == 0)
{
Content = null;
_displayContext = null;
_disableSelectionChangingEvent = false;
return;
}
if (ViewMode == Models.ChangeViewMode.Tree)
{
HashSet<string> oldFolded = new HashSet<string>();
if (_displayContext is ViewModels.ChangeCollectionAsTree oldTree)
{
foreach (var row in oldTree.Rows)
{
if (row.IsFolder && !row.IsExpanded)
oldFolded.Add(row.FullPath);
}
}
var tree = new ViewModels.ChangeCollectionAsTree();
tree.Tree = ViewModels.ChangeTreeNode.Build(changes, oldFolded);
var rows = new List<ViewModels.ChangeTreeNode>();
MakeTreeRows(rows, tree.Tree);
tree.Rows.AddRange(rows);
_displayContext = tree;
}
else if (ViewMode == Models.ChangeViewMode.Grid)
{
var grid = new ViewModels.ChangeCollectionAsGrid();
grid.Changes.AddRange(changes);
_displayContext = grid;
}
else
{
var list = new ViewModels.ChangeCollectionAsList();
list.Changes.AddRange(changes);
_displayContext = list;
}
Content = _displayContext;
_disableSelectionChangingEvent = false;
}
if (change.Property == ViewModeProperty)
UpdateDataSource(false);
else if (change.Property == ChangesProperty)
UpdateDataSource(true);
else if (change.Property == SelectedChangesProperty)
{
if (_disableSelectionChangingEvent)
return;
var list = this.FindDescendantOfType<ChangeCollectionContainer>();
if (list == null)
return;
_disableSelectionChangingEvent = true;
var selected = SelectedChanges;
if (selected == null || selected.Count == 0)
{
list.SelectedItem = null;
}
else if (_displayContext is ViewModels.ChangeCollectionAsTree tree)
{
var sets = new HashSet<Models.Change>();
foreach (var c in selected)
sets.Add(c);
var nodes = new List<ViewModels.ChangeTreeNode>();
foreach (var row in tree.Rows)
{
if (row.Change != null && sets.Contains(row.Change))
nodes.Add(row);
}
list.SelectedItems = nodes;
}
else
{
list.SelectedItems = selected;
}
_disableSelectionChangingEvent = false;
}
UpdateSelection();
}
private void OnRowDoubleTapped(object sender, TappedEventArgs e)
@ -283,6 +204,120 @@ namespace SourceGit.Views
}
}
private void UpdateDataSource(bool disableEvents)
{
_disableSelectionChangingEvent = disableEvents;
var changes = Changes;
if (changes == null || changes.Count == 0)
{
Content = null;
_disableSelectionChangingEvent = false;
return;
}
var selected = SelectedChanges ?? [];
if (ViewMode == Models.ChangeViewMode.Tree)
{
HashSet<string> oldFolded = new HashSet<string>();
if (Content is ViewModels.ChangeCollectionAsTree oldTree)
{
foreach (var row in oldTree.Rows)
{
if (row.IsFolder && !row.IsExpanded)
oldFolded.Add(row.FullPath);
}
}
var tree = new ViewModels.ChangeCollectionAsTree();
tree.Tree = ViewModels.ChangeTreeNode.Build(changes, oldFolded);
var rows = new List<ViewModels.ChangeTreeNode>();
MakeTreeRows(rows, tree.Tree);
tree.Rows.AddRange(rows);
if (selected.Count > 0)
{
var sets = new HashSet<Models.Change>();
foreach (var c in selected)
sets.Add(c);
var nodes = new List<ViewModels.ChangeTreeNode>();
foreach (var row in tree.Rows)
{
if (row.Change != null && sets.Contains(row.Change))
nodes.Add(row);
}
tree.SelectedRows.AddRange(nodes);
}
Content = tree;
}
else if (ViewMode == Models.ChangeViewMode.Grid)
{
var grid = new ViewModels.ChangeCollectionAsGrid();
grid.Changes.AddRange(changes);
if (selected.Count > 0)
grid.SelectedChanges.AddRange(selected);
Content = grid;
}
else
{
var list = new ViewModels.ChangeCollectionAsList();
list.Changes.AddRange(changes);
if (selected.Count > 0)
list.SelectedChanges.AddRange(selected);
Content = list;
}
_disableSelectionChangingEvent = false;
}
private void UpdateSelection()
{
if (_disableSelectionChangingEvent)
return;
_disableSelectionChangingEvent = true;
var selected = SelectedChanges ?? [];
if (Content is ViewModels.ChangeCollectionAsTree tree)
{
tree.SelectedRows.Clear();
if (selected.Count > 0)
{
var sets = new HashSet<Models.Change>();
foreach (var c in selected)
sets.Add(c);
var nodes = new List<ViewModels.ChangeTreeNode>();
foreach (var row in tree.Rows)
{
if (row.Change != null && sets.Contains(row.Change))
nodes.Add(row);
}
tree.SelectedRows.AddRange(nodes);
}
}
else if (Content is ViewModels.ChangeCollectionAsGrid grid)
{
grid.SelectedChanges.Clear();
if (selected.Count > 0)
grid.SelectedChanges.AddRange(selected);
}
else if (Content is ViewModels.ChangeCollectionAsList list)
{
list.SelectedChanges.Clear();
if (selected.Count > 0)
list.SelectedChanges.AddRange(selected);
}
_disableSelectionChangingEvent = false;
}
private void CollectChangesInNode(List<Models.Change> outs, ViewModels.ChangeTreeNode node)
{
if (node.IsFolder)
@ -324,6 +359,5 @@ namespace SourceGit.Views
}
private bool _disableSelectionChangingEvent = false;
private object _displayContext = null;
}
}