Skip to content

Commit 258480d

Browse files
committed
feature: add Branch Compare command palette
Signed-off-by: leo <longshuang@msn.cn>
1 parent 6538efc commit 258480d

File tree

4 files changed

+289
-15
lines changed

4 files changed

+289
-15
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace SourceGit.ViewModels
5+
{
6+
public class BranchCompareCommandPalette : ICommandPalette
7+
{
8+
public List<Models.Branch> Branches
9+
{
10+
get => _branches;
11+
private set => SetProperty(ref _branches, value);
12+
}
13+
14+
public Models.Branch SelectedBranch
15+
{
16+
get => _selectedBranch;
17+
set => SetProperty(ref _selectedBranch, value);
18+
}
19+
20+
public string Filter
21+
{
22+
get => _filter;
23+
set
24+
{
25+
if (SetProperty(ref _filter, value))
26+
UpdateBranches();
27+
}
28+
}
29+
30+
public BranchCompareCommandPalette(Launcher launcher, Repository repo)
31+
{
32+
_launcher = launcher;
33+
_repo = repo;
34+
UpdateBranches();
35+
}
36+
37+
public override void Cleanup()
38+
{
39+
_launcher = null;
40+
_repo = null;
41+
_branches.Clear();
42+
_selectedBranch = null;
43+
_filter = null;
44+
}
45+
46+
public void ClearFilter()
47+
{
48+
Filter = string.Empty;
49+
}
50+
51+
public void Launch()
52+
{
53+
if (_selectedBranch != null)
54+
App.ShowWindow(new BranchCompare(_repo.FullPath, _selectedBranch, _repo.CurrentBranch));
55+
_launcher?.CancelCommandPalette();
56+
}
57+
58+
private void UpdateBranches()
59+
{
60+
var current = _repo.CurrentBranch;
61+
if (current == null)
62+
return;
63+
64+
var branches = new List<Models.Branch>();
65+
foreach (var b in _repo.Branches)
66+
{
67+
if (b == current)
68+
continue;
69+
70+
if (string.IsNullOrEmpty(_filter) || b.FriendlyName.Contains(_filter, StringComparison.OrdinalIgnoreCase))
71+
branches.Add(b);
72+
}
73+
74+
branches.Sort((l, r) =>
75+
{
76+
if (l.IsLocal == r.IsLocal)
77+
return l.Name.CompareTo(r.Name);
78+
79+
return l.IsLocal ? -1 : 1;
80+
});
81+
82+
Branches = branches;
83+
}
84+
85+
private Launcher _launcher;
86+
private Repository _repo;
87+
private List<Models.Branch> _branches = [];
88+
private Models.Branch _selectedBranch = null;
89+
private string _filter;
90+
}
91+
}

src/ViewModels/RepositoryCommandPalette.cs

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,18 @@
33

44
namespace SourceGit.ViewModels
55
{
6-
public record RepositoryCommandPaletteCmd(string Name, string Label, bool AutoCloseCommandPalette, Action Action);
6+
public class RepositoryCommandPaletteCmd
7+
{
8+
public string Key { get; set; }
9+
public Action Action { get; set; }
10+
public string Label => $"{App.Text(Key)}...";
11+
12+
public RepositoryCommandPaletteCmd(string key, Action action)
13+
{
14+
Key = key;
15+
Action = action;
16+
}
17+
}
718

819
public class RepositoryCommandPalette : ICommandPalette
920
{
@@ -34,24 +45,30 @@ public RepositoryCommandPalette(Launcher launcher, Repository repo)
3445
_launcher = launcher;
3546
_repo = repo;
3647

37-
_cmds.Add(new("File History", App.Text("FileHistory") + "...", false, () =>
48+
_cmds.Add(new("FileHistory", () =>
3849
{
3950
var sub = new FileHistoryCommandPalette(_launcher, _repo.FullPath);
4051
_launcher.OpenCommandPalette(sub);
4152
}));
4253

43-
_cmds.Add(new("Blame", App.Text("Blame") + "...", false, () =>
54+
_cmds.Add(new("Blame", () =>
4455
{
4556
var sub = new BlameCommandPalette(_launcher, _repo.FullPath);
4657
_launcher.OpenCommandPalette(sub);
4758
}));
4859

49-
_cmds.Add(new("Merge", App.Text("Merge") + "...", false, () =>
60+
_cmds.Add(new("Merge", () =>
5061
{
5162
var sub = new MergeCommandPalette(_launcher, _repo);
5263
_launcher.OpenCommandPalette(sub);
5364
}));
5465

66+
_cmds.Add(new("BranchCompare", () =>
67+
{
68+
var sub = new BranchCompareCommandPalette(_launcher, _repo);
69+
_launcher.OpenCommandPalette(sub);
70+
}));
71+
5572
_visibleCmds = _cmds;
5673
}
5774

@@ -72,16 +89,9 @@ public void ClearFilter()
7289

7390
public void Exec()
7491
{
75-
if (_selectedCmd == null)
76-
{
77-
_launcher?.CancelCommandPalette();
78-
return;
79-
}
80-
81-
var autoClose = _selectedCmd.AutoCloseCommandPalette;
82-
_selectedCmd.Action?.Invoke();
83-
84-
if (autoClose)
92+
if (_selectedCmd != null)
93+
_selectedCmd.Action?.Invoke();
94+
else
8595
_launcher?.CancelCommandPalette();
8696
}
8797

@@ -96,7 +106,7 @@ private void UpdateVisible()
96106
var visible = new List<RepositoryCommandPaletteCmd>();
97107
foreach (var cmd in VisibleCmds)
98108
{
99-
if (cmd.Name.Contains(_filter, StringComparison.OrdinalIgnoreCase) ||
109+
if (cmd.Key.Contains(_filter, StringComparison.OrdinalIgnoreCase) ||
100110
cmd.Label.Contains(_filter, StringComparison.OrdinalIgnoreCase))
101111
visible.Add(cmd);
102112
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<UserControl xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:m="using:SourceGit.Models"
6+
xmlns:vm="using:SourceGit.ViewModels"
7+
xmlns:v="using:SourceGit.Views"
8+
xmlns:c="using:SourceGit.Converters"
9+
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
10+
x:Class="SourceGit.Views.BranchCompareCommandPalette"
11+
x:DataType="vm:BranchCompareCommandPalette">
12+
<Grid RowDefinitions="Auto,Auto">
13+
<v:RepositoryCommandPaletteTextBox Grid.Row="0"
14+
x:Name="FilterTextBox"
15+
Height="24"
16+
Margin="4,8,4,0"
17+
BorderThickness="1"
18+
CornerRadius="12"
19+
Text="{Binding Filter, Mode=TwoWay}"
20+
BorderBrush="{DynamicResource Brush.Border2}"
21+
VerticalContentAlignment="Center">
22+
<TextBox.InnerLeftContent>
23+
<StackPanel Orientation="Horizontal">
24+
<Path Width="14" Height="14"
25+
Margin="6,0,0,0"
26+
Fill="{DynamicResource Brush.FG2}"
27+
Data="{StaticResource Icons.Search}"/>
28+
<Border BorderThickness="0"
29+
Background="{DynamicResource Brush.Badge}"
30+
Height="18"
31+
CornerRadius="4"
32+
Margin="4,0,0,0" Padding="4,0">
33+
<TextBlock Text="{DynamicResource Text.BranchCompare}"
34+
Foreground="Black"
35+
FontWeight="Bold"/>
36+
</Border>
37+
</StackPanel>
38+
</TextBox.InnerLeftContent>
39+
40+
<TextBox.InnerRightContent>
41+
<Button Classes="icon_button"
42+
Width="16"
43+
Margin="0,0,6,0"
44+
Command="{Binding ClearFilter}"
45+
IsVisible="{Binding Filter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
46+
HorizontalAlignment="Right">
47+
<Path Width="14" Height="14"
48+
Margin="0,1,0,0"
49+
Fill="{DynamicResource Brush.FG1}"
50+
Data="{StaticResource Icons.Clear}"/>
51+
</Button>
52+
</TextBox.InnerRightContent>
53+
</v:RepositoryCommandPaletteTextBox>
54+
55+
<ListBox Grid.Row="1"
56+
x:Name="BranchListBox"
57+
MaxHeight="250"
58+
Margin="4,8,4,0"
59+
BorderThickness="0"
60+
SelectionMode="Single"
61+
Background="Transparent"
62+
Focusable="True"
63+
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
64+
ScrollViewer.VerticalScrollBarVisibility="Auto"
65+
ItemsSource="{Binding Branches, Mode=OneWay}"
66+
SelectedItem="{Binding SelectedBranch, Mode=TwoWay}"
67+
IsVisible="{Binding Branches, Converter={x:Static c:ListConverters.IsNotNullOrEmpty}}">
68+
<ListBox.Styles>
69+
<Style Selector="ListBoxItem">
70+
<Setter Property="Padding" Value="8,0"/>
71+
<Setter Property="MinHeight" Value="26"/>
72+
<Setter Property="CornerRadius" Value="4"/>
73+
</Style>
74+
75+
<Style Selector="ListBox">
76+
<Setter Property="FocusAdorner">
77+
<FocusAdornerTemplate>
78+
<Grid/>
79+
</FocusAdornerTemplate>
80+
</Setter>
81+
</Style>
82+
</ListBox.Styles>
83+
84+
<ListBox.ItemsPanel>
85+
<ItemsPanelTemplate>
86+
<VirtualizingStackPanel Orientation="Vertical"/>
87+
</ItemsPanelTemplate>
88+
</ListBox.ItemsPanel>
89+
90+
<ListBox.ItemTemplate>
91+
<DataTemplate DataType="m:Branch">
92+
<Grid ColumnDefinitions="Auto,*" Background="Transparent" Tapped="OnItemTapped">
93+
<Path Grid.Column="0"
94+
Width="12" Height="12"
95+
Data="{StaticResource Icons.Branch}"
96+
IsHitTestVisible="False"/>
97+
<TextBlock Grid.Column="1"
98+
Margin="4,0,0,0"
99+
VerticalAlignment="Center"
100+
IsHitTestVisible="False"
101+
Text="{Binding FriendlyName, Mode=OneWay}"/>
102+
</Grid>
103+
</DataTemplate>
104+
</ListBox.ItemTemplate>
105+
</ListBox>
106+
</Grid>
107+
</UserControl>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using Avalonia.Controls;
2+
using Avalonia.Input;
3+
4+
namespace SourceGit.Views
5+
{
6+
public partial class BranchCompareCommandPalette : UserControl
7+
{
8+
public BranchCompareCommandPalette()
9+
{
10+
InitializeComponent();
11+
}
12+
13+
protected override void OnKeyDown(KeyEventArgs e)
14+
{
15+
base.OnKeyDown(e);
16+
17+
if (DataContext is not ViewModels.BranchCompareCommandPalette vm)
18+
return;
19+
20+
if (e.Key == Key.Enter)
21+
{
22+
vm.Launch();
23+
e.Handled = true;
24+
}
25+
else if (e.Key == Key.Up)
26+
{
27+
if (BranchListBox.IsKeyboardFocusWithin)
28+
{
29+
FilterTextBox.Focus(NavigationMethod.Directional);
30+
e.Handled = true;
31+
return;
32+
}
33+
}
34+
else if (e.Key == Key.Down || e.Key == Key.Tab)
35+
{
36+
if (FilterTextBox.IsKeyboardFocusWithin)
37+
{
38+
if (vm.Branches.Count > 0)
39+
{
40+
BranchListBox.Focus(NavigationMethod.Directional);
41+
vm.SelectedBranch = vm.Branches[0];
42+
}
43+
44+
e.Handled = true;
45+
return;
46+
}
47+
48+
if (BranchListBox.IsKeyboardFocusWithin && e.Key == Key.Tab)
49+
{
50+
FilterTextBox.Focus(NavigationMethod.Directional);
51+
e.Handled = true;
52+
return;
53+
}
54+
}
55+
}
56+
57+
private void OnItemTapped(object sender, TappedEventArgs e)
58+
{
59+
if (DataContext is ViewModels.BranchCompareCommandPalette vm)
60+
{
61+
vm.Launch();
62+
e.Handled = true;
63+
}
64+
}
65+
}
66+
}

0 commit comments

Comments
 (0)