mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-22 20:37:19 -08:00
ux: improve change list selection
This commit is contained in:
parent
2f5f98770f
commit
ef0c904e91
5 changed files with 132 additions and 88 deletions
|
@ -164,7 +164,7 @@ namespace SourceGit.Models
|
||||||
|
|
||||||
private void OnRepositoryChanged(object o, FileSystemEventArgs e)
|
private void OnRepositoryChanged(object o, FileSystemEventArgs e)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(e.Name))
|
if (string.IsNullOrEmpty(e.Name) || e.Name.EndsWith(".lock", StringComparison.Ordinal))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var name = e.Name.Replace("\\", "/");
|
var name = e.Name.Replace("\\", "/");
|
||||||
|
|
|
@ -8,15 +8,18 @@ namespace SourceGit.ViewModels
|
||||||
{
|
{
|
||||||
public List<ChangeTreeNode> Tree { get; set; } = new List<ChangeTreeNode>();
|
public List<ChangeTreeNode> Tree { get; set; } = new List<ChangeTreeNode>();
|
||||||
public AvaloniaList<ChangeTreeNode> Rows { get; set; } = new AvaloniaList<ChangeTreeNode>();
|
public AvaloniaList<ChangeTreeNode> Rows { get; set; } = new AvaloniaList<ChangeTreeNode>();
|
||||||
|
public AvaloniaList<ChangeTreeNode> SelectedRows { get; set; } = new AvaloniaList<ChangeTreeNode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ChangeCollectionAsGrid
|
public class ChangeCollectionAsGrid
|
||||||
{
|
{
|
||||||
public AvaloniaList<Models.Change> Changes { get; set; } = new AvaloniaList<Models.Change>();
|
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 class ChangeCollectionAsList
|
||||||
{
|
{
|
||||||
public AvaloniaList<Models.Change> Changes { get; set; } = new AvaloniaList<Models.Change>();
|
public AvaloniaList<Models.Change> Changes { get; set; } = new AvaloniaList<Models.Change>();
|
||||||
|
public AvaloniaList<Models.Change> SelectedChanges { get; set; } = new AvaloniaList<Models.Change>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -301,11 +301,13 @@ namespace SourceGit.ViewModels
|
||||||
public void StageSelected()
|
public void StageSelected()
|
||||||
{
|
{
|
||||||
StageChanges(_selectedUnstaged);
|
StageChanges(_selectedUnstaged);
|
||||||
|
SelectedUnstaged = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StageAll()
|
public void StageAll()
|
||||||
{
|
{
|
||||||
StageChanges(_unstaged);
|
StageChanges(_unstaged);
|
||||||
|
SelectedUnstaged = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void StageChanges(List<Models.Change> changes)
|
public async void StageChanges(List<Models.Change> changes)
|
||||||
|
@ -337,11 +339,13 @@ namespace SourceGit.ViewModels
|
||||||
public void UnstageSelected()
|
public void UnstageSelected()
|
||||||
{
|
{
|
||||||
UnstageChanges(_selectedStaged);
|
UnstageChanges(_selectedStaged);
|
||||||
|
SelectedStaged = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UnstageAll()
|
public void UnstageAll()
|
||||||
{
|
{
|
||||||
UnstageChanges(_staged);
|
UnstageChanges(_staged);
|
||||||
|
SelectedStaged = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void UnstageChanges(List<Models.Change> changes)
|
public async void UnstageChanges(List<Models.Change> changes)
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
<UserControl.DataTemplates>
|
<UserControl.DataTemplates>
|
||||||
<DataTemplate DataType="vm:ChangeCollectionAsTree">
|
<DataTemplate DataType="vm:ChangeCollectionAsTree">
|
||||||
<v:ChangeCollectionContainer ItemsSource="{Binding Rows}"
|
<v:ChangeCollectionContainer ItemsSource="{Binding Rows}"
|
||||||
|
SelectedItems="{Binding SelectedRows, Mode=TwoWay}"
|
||||||
SelectionMode="{Binding #ThisControl.SelectionMode}"
|
SelectionMode="{Binding #ThisControl.SelectionMode}"
|
||||||
SelectionChanged="OnRowSelectionChanged">
|
SelectionChanged="OnRowSelectionChanged">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
|
@ -65,6 +66,7 @@
|
||||||
|
|
||||||
<DataTemplate DataType="vm:ChangeCollectionAsGrid">
|
<DataTemplate DataType="vm:ChangeCollectionAsGrid">
|
||||||
<v:ChangeCollectionContainer ItemsSource="{Binding Changes}"
|
<v:ChangeCollectionContainer ItemsSource="{Binding Changes}"
|
||||||
|
SelectedItems="{Binding SelectedChanges, Mode=TwoWay}"
|
||||||
SelectionMode="{Binding #ThisControl.SelectionMode}"
|
SelectionMode="{Binding #ThisControl.SelectionMode}"
|
||||||
SelectionChanged="OnRowSelectionChanged">
|
SelectionChanged="OnRowSelectionChanged">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
|
@ -93,6 +95,7 @@
|
||||||
|
|
||||||
<DataTemplate DataType="vm:ChangeCollectionAsList">
|
<DataTemplate DataType="vm:ChangeCollectionAsList">
|
||||||
<v:ChangeCollectionContainer ItemsSource="{Binding Changes}"
|
<v:ChangeCollectionContainer ItemsSource="{Binding Changes}"
|
||||||
|
SelectedItems="{Binding SelectedChanges, Mode=TwoWay}"
|
||||||
SelectionMode="{Binding #ThisControl.SelectionMode}"
|
SelectionMode="{Binding #ThisControl.SelectionMode}"
|
||||||
SelectionChanged="OnRowSelectionChanged">
|
SelectionChanged="OnRowSelectionChanged">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
|
|
|
@ -6,6 +6,7 @@ using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Threading;
|
||||||
using Avalonia.VisualTree;
|
using Avalonia.VisualTree;
|
||||||
|
|
||||||
namespace SourceGit.Views
|
namespace SourceGit.Views
|
||||||
|
@ -101,7 +102,7 @@ namespace SourceGit.Views
|
||||||
|
|
||||||
public void ToggleNodeIsExpanded(ViewModels.ChangeTreeNode node)
|
public void ToggleNodeIsExpanded(ViewModels.ChangeTreeNode node)
|
||||||
{
|
{
|
||||||
if (_displayContext is ViewModels.ChangeCollectionAsTree tree)
|
if (Content is ViewModels.ChangeCollectionAsTree tree)
|
||||||
{
|
{
|
||||||
node.IsExpanded = !node.IsExpanded;
|
node.IsExpanded = !node.IsExpanded;
|
||||||
|
|
||||||
|
@ -136,92 +137,12 @@ namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
base.OnPropertyChanged(change);
|
base.OnPropertyChanged(change);
|
||||||
|
|
||||||
if (change.Property == ViewModeProperty || change.Property == ChangesProperty)
|
if (change.Property == ViewModeProperty)
|
||||||
{
|
UpdateDataSource(false);
|
||||||
_disableSelectionChangingEvent = change.Property == ChangesProperty;
|
else if (change.Property == ChangesProperty)
|
||||||
var changes = Changes;
|
UpdateDataSource(true);
|
||||||
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;
|
|
||||||
}
|
|
||||||
else if (change.Property == SelectedChangesProperty)
|
else if (change.Property == SelectedChangesProperty)
|
||||||
{
|
UpdateSelection();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRowDoubleTapped(object sender, TappedEventArgs e)
|
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)
|
private void CollectChangesInNode(List<Models.Change> outs, ViewModels.ChangeTreeNode node)
|
||||||
{
|
{
|
||||||
if (node.IsFolder)
|
if (node.IsFolder)
|
||||||
|
@ -324,6 +359,5 @@ namespace SourceGit.Views
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _disableSelectionChangingEvent = false;
|
private bool _disableSelectionChangingEvent = false;
|
||||||
private object _displayContext = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue