mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-23 20:47:25 -08:00
feature: auto focus the next
change after stage/unstage selected changes (#464)
This commit is contained in:
parent
dcddc5a2f2
commit
ea3a6a4755
4 changed files with 122 additions and 22 deletions
|
@ -325,23 +325,24 @@ namespace SourceGit.ViewModels
|
|||
PopupHost.ShowPopup(new StashChanges(_repo, _cached, true));
|
||||
}
|
||||
|
||||
public void StageSelected()
|
||||
public void StageSelected(Models.Change next)
|
||||
{
|
||||
StageChanges(_selectedUnstaged);
|
||||
SelectedUnstaged = [];
|
||||
StageChanges(_selectedUnstaged, next);
|
||||
}
|
||||
|
||||
public void StageAll()
|
||||
{
|
||||
StageChanges(_unstaged);
|
||||
SelectedUnstaged = [];
|
||||
StageChanges(_unstaged, null);
|
||||
}
|
||||
|
||||
public async void StageChanges(List<Models.Change> changes)
|
||||
public async void StageChanges(List<Models.Change> changes, Models.Change next)
|
||||
{
|
||||
if (_unstaged.Count == 0 || changes.Count == 0)
|
||||
return;
|
||||
|
||||
// Use `_selectedUnstaged` instead of `SelectedUnstaged` to avoid UI refresh.
|
||||
_selectedUnstaged = next != null ? [next] : [];
|
||||
|
||||
IsStaging = true;
|
||||
_repo.SetWatcherEnabled(false);
|
||||
if (changes.Count == _unstaged.Count)
|
||||
|
@ -362,23 +363,24 @@ namespace SourceGit.ViewModels
|
|||
IsStaging = false;
|
||||
}
|
||||
|
||||
public void UnstageSelected()
|
||||
public void UnstageSelected(Models.Change next)
|
||||
{
|
||||
UnstageChanges(_selectedStaged);
|
||||
SelectedStaged = [];
|
||||
UnstageChanges(_selectedStaged, next);
|
||||
}
|
||||
|
||||
public void UnstageAll()
|
||||
{
|
||||
UnstageChanges(_staged);
|
||||
SelectedStaged = [];
|
||||
UnstageChanges(_staged, null);
|
||||
}
|
||||
|
||||
public async void UnstageChanges(List<Models.Change> changes)
|
||||
public async void UnstageChanges(List<Models.Change> changes, Models.Change next)
|
||||
{
|
||||
if (_staged.Count == 0 || changes.Count == 0)
|
||||
return;
|
||||
|
||||
// Use `_selectedStaged` instead of `SelectedStaged` to avoid UI refresh.
|
||||
_selectedStaged = next != null ? [next] : [];
|
||||
|
||||
IsUnstaging = true;
|
||||
_repo.SetWatcherEnabled(false);
|
||||
if (_useAmend)
|
||||
|
@ -499,7 +501,7 @@ namespace SourceGit.ViewModels
|
|||
stage.Icon = App.CreateMenuIcon("Icons.File.Add");
|
||||
stage.Click += (_, e) =>
|
||||
{
|
||||
StageChanges(_selectedUnstaged);
|
||||
StageChanges(_selectedUnstaged, null);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
|
@ -823,7 +825,7 @@ namespace SourceGit.ViewModels
|
|||
stage.Icon = App.CreateMenuIcon("Icons.File.Add");
|
||||
stage.Click += (_, e) =>
|
||||
{
|
||||
StageChanges(_selectedUnstaged);
|
||||
StageChanges(_selectedUnstaged, null);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
|
@ -917,7 +919,7 @@ namespace SourceGit.ViewModels
|
|||
unstage.Icon = App.CreateMenuIcon("Icons.File.Remove");
|
||||
unstage.Click += (_, e) =>
|
||||
{
|
||||
UnstageChanges(_selectedStaged);
|
||||
UnstageChanges(_selectedStaged, null);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
|
@ -1086,7 +1088,7 @@ namespace SourceGit.ViewModels
|
|||
unstage.Icon = App.CreateMenuIcon("Icons.File.Remove");
|
||||
unstage.Click += (_, e) =>
|
||||
{
|
||||
UnstageChanges(_selectedStaged);
|
||||
UnstageChanges(_selectedStaged, null);
|
||||
e.Handled = true;
|
||||
};
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ namespace SourceGit.Views
|
|||
|
||||
public ChangeCollectionView()
|
||||
{
|
||||
Focusable = true;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
@ -132,6 +133,69 @@ namespace SourceGit.Views
|
|||
}
|
||||
}
|
||||
|
||||
public Models.Change GetNextChangeWithoutSelection()
|
||||
{
|
||||
var selected = SelectedChanges;
|
||||
var changes = Changes;
|
||||
if (selected == null || selected.Count == 0)
|
||||
return changes.Count > 0 ? changes[0] : null;
|
||||
if (selected.Count == changes.Count)
|
||||
return null;
|
||||
|
||||
var set = new HashSet<string>();
|
||||
foreach (var c in selected)
|
||||
set.Add(c.Path);
|
||||
|
||||
if (Content is ViewModels.ChangeCollectionAsTree tree)
|
||||
{
|
||||
var lastUnselected = -1;
|
||||
for (int i = tree.Rows.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var row = tree.Rows[i];
|
||||
if (!row.IsFolder)
|
||||
{
|
||||
if (set.Contains(row.FullPath))
|
||||
{
|
||||
if (lastUnselected == -1)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastUnselected = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lastUnselected != -1)
|
||||
return tree.Rows[lastUnselected].Change;
|
||||
}
|
||||
else
|
||||
{
|
||||
var lastUnselected = -1;
|
||||
for (int i = changes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (set.Contains(changes[i].Path))
|
||||
{
|
||||
if (lastUnselected == -1)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastUnselected = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastUnselected != -1)
|
||||
return changes[lastUnselected];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||
{
|
||||
base.OnPropertyChanged(change);
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
Classes="icon_button"
|
||||
Width="26" Height="14"
|
||||
Padding="0"
|
||||
Command="{Binding StageSelected}">
|
||||
Click="OnStageSelectedButtonClicked">
|
||||
<ToolTip.Tip>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="{DynamicResource Text.WorkingCopy.Unstaged.Stage}" VerticalAlignment="Center"/>
|
||||
|
@ -64,6 +64,7 @@
|
|||
|
||||
<!-- Unstaged Changes -->
|
||||
<v:ChangeCollectionView Grid.Row="1"
|
||||
x:Name="UnstagedChangesView"
|
||||
IsUnstagedChange="True"
|
||||
SelectionMode="Multiple"
|
||||
Background="{DynamicResource Brush.Contents}"
|
||||
|
@ -81,7 +82,7 @@
|
|||
<TextBlock Grid.Column="1" Text="{DynamicResource Text.WorkingCopy.Staged}" Foreground="{DynamicResource Brush.FG2}" FontWeight="Bold" Margin="8,0,0,0"/>
|
||||
<TextBlock Grid.Column="2" FontWeight="Bold" Foreground="{DynamicResource Brush.FG2}" Text="{Binding Staged, Converter={x:Static c:ListConverters.ToCount}}"/>
|
||||
<v:LoadingIcon Grid.Column="3" Width="14" Height="14" Margin="8,0,0,0" IsVisible="{Binding IsUnstaging}"/>
|
||||
<Button Grid.Column="5" Classes="icon_button" Width="26" Height="14" Padding="0" Command="{Binding UnstageSelected}">
|
||||
<Button Grid.Column="5" Classes="icon_button" Width="26" Height="14" Padding="0" Click="OnUnstageSelectedButtonClicked">
|
||||
<ToolTip.Tip>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="{DynamicResource Text.WorkingCopy.Staged.Unstage}" VerticalAlignment="Center"/>
|
||||
|
@ -98,6 +99,7 @@
|
|||
|
||||
<!-- Staged Changes -->
|
||||
<v:ChangeCollectionView Grid.Row="3"
|
||||
x:Name="StagedChangesView"
|
||||
SelectionMode="Multiple"
|
||||
Background="{DynamicResource Brush.Contents}"
|
||||
ViewMode="{Binding Source={x:Static vm:Preference.Instance}, Path=StagedChangeViewMode}"
|
||||
|
|
|
@ -46,7 +46,9 @@ namespace SourceGit.Views
|
|||
{
|
||||
if (DataContext is ViewModels.WorkingCopy vm)
|
||||
{
|
||||
vm.StageSelected();
|
||||
var next = UnstagedChangesView.GetNextChangeWithoutSelection();
|
||||
vm.StageSelected(next);
|
||||
UnstagedChangesView.Focus();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +57,9 @@ namespace SourceGit.Views
|
|||
{
|
||||
if (DataContext is ViewModels.WorkingCopy vm)
|
||||
{
|
||||
vm.UnstageSelected();
|
||||
var next = StagedChangesView.GetNextChangeWithoutSelection();
|
||||
vm.UnstageSelected(next);
|
||||
StagedChangesView.Focus();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +70,9 @@ namespace SourceGit.Views
|
|||
{
|
||||
if (e.Key is Key.Space or Key.Enter)
|
||||
{
|
||||
vm.StageSelected();
|
||||
var next = UnstagedChangesView.GetNextChangeWithoutSelection();
|
||||
vm.StageSelected(next);
|
||||
UnstagedChangesView.Focus();
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
@ -84,11 +90,37 @@ namespace SourceGit.Views
|
|||
{
|
||||
if (DataContext is ViewModels.WorkingCopy vm && e.Key is Key.Space or Key.Enter)
|
||||
{
|
||||
vm.UnstageSelected();
|
||||
var next = StagedChangesView.GetNextChangeWithoutSelection();
|
||||
vm.UnstageSelected(next);
|
||||
StagedChangesView.Focus();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStageSelectedButtonClicked(object _, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.WorkingCopy vm)
|
||||
{
|
||||
var next = UnstagedChangesView.GetNextChangeWithoutSelection();
|
||||
vm.StageSelected(next);
|
||||
UnstagedChangesView.Focus();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnUnstageSelectedButtonClicked(object _, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is ViewModels.WorkingCopy vm)
|
||||
{
|
||||
var next = StagedChangesView.GetNextChangeWithoutSelection();
|
||||
vm.UnstageSelected(next);
|
||||
StagedChangesView.Focus();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnOpenAIAssist(object _, RoutedEventArgs e)
|
||||
{
|
||||
if (!Models.OpenAI.IsValid)
|
||||
|
|
Loading…
Reference in a new issue