Skip to content

Commit fb2f4c2

Browse files
committed
feature: add hotkey Ctrl+Shift+F/⌘+⇧+F to open File History command palette
Signed-off-by: leo <longshuang@msn.cn>
1 parent ca544d9 commit fb2f4c2

11 files changed

+309
-7
lines changed

src/Resources/Locales/en_US.axaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@
477477
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">Stage all changes and commit</x:String>
478478
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">Fetch, starts directly</x:String>
479479
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">Dashboard mode (Default)</x:String>
480+
<x:String x:Key="Text.Hotkeys.Repo.OpenFileHistoryCommandPalette" xml:space="preserve">Open `File History` command palette</x:String>
480481
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">Commit search mode</x:String>
481482
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">Pull, starts directly</x:String>
482483
<x:String x:Key="Text.Hotkeys.Repo.Push" xml:space="preserve">Push, starts directly</x:String>

src/Resources/Locales/zh_CN.axaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@
481481
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">自动暂存全部变更并提交</x:String>
482482
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">拉取 (fetch) 远程变更</x:String>
483483
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">切换左边栏为分支/标签等显示模式(默认)</x:String>
484+
<x:String x:Key="Text.Hotkeys.Repo.OpenFileHistoryCommandPalette" xml:space="preserve">打开【文件历史】命令面板</x:String>
484485
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">切换左边栏为提交搜索模式</x:String>
485486
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">拉回 (pull) 远程变更</x:String>
486487
<x:String x:Key="Text.Hotkeys.Repo.Push" xml:space="preserve">推送本地变更到远程</x:String>

src/Resources/Locales/zh_TW.axaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,14 +473,15 @@
473473
<x:String x:Key="Text.Hotkeys.Global.GotoNextTab" xml:space="preserve">切換到下一個頁面</x:String>
474474
<x:String x:Key="Text.Hotkeys.Global.GotoPrevTab" xml:space="preserve">切換到上一個頁面</x:String>
475475
<x:String x:Key="Text.Hotkeys.Global.NewTab" xml:space="preserve">新增頁面</x:String>
476-
<x:String x:Key="Text.Hotkeys.Global.OpenPreferences" xml:space="preserve">開啟偏好設定面板</x:String>
476+
<x:String x:Key="Text.Hotkeys.Global.OpenPreferences" xml:space="preserve">開啟 [偏好設定] 面板</x:String>
477477
<x:String x:Key="Text.Hotkeys.Global.SwitchTab" xml:space="preserve">切換目前頁面</x:String>
478478
<x:String x:Key="Text.Hotkeys.Repo" xml:space="preserve">存放庫頁面快速鍵</x:String>
479479
<x:String x:Key="Text.Hotkeys.Repo.Commit" xml:space="preserve">提交暫存區變更</x:String>
480480
<x:String x:Key="Text.Hotkeys.Repo.CommitAndPush" xml:space="preserve">提交暫存區變更並推送</x:String>
481481
<x:String x:Key="Text.Hotkeys.Repo.CommitWithAutoStage" xml:space="preserve">自動暫存全部變更並提交</x:String>
482482
<x:String x:Key="Text.Hotkeys.Repo.Fetch" xml:space="preserve">提取 (fetch) 遠端的變更</x:String>
483483
<x:String x:Key="Text.Hotkeys.Repo.GoHome" xml:space="preserve">切換左邊欄為分支/標籤等顯示模式 (預設)</x:String>
484+
<x:String x:Key="Text.Hotkeys.Repo.OpenFileHistoryCommandPalette" xml:space="preserve">開啟「檔案歷史記錄」命令面板</x:String>
484485
<x:String x:Key="Text.Hotkeys.Repo.OpenSearchCommits" xml:space="preserve">切換左邊欄為歷史搜尋模式</x:String>
485486
<x:String x:Key="Text.Hotkeys.Repo.Pull" xml:space="preserve">拉取 (pull) 遠端的變更</x:String>
486487
<x:String x:Key="Text.Hotkeys.Repo.Push" xml:space="preserve">推送 (push) 本機變更到遠端存放庫</x:String>
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading.Tasks;
4+
using Avalonia.Threading;
5+
using CommunityToolkit.Mvvm.ComponentModel;
6+
7+
namespace SourceGit.ViewModels
8+
{
9+
public class FileHistoryCommandPalette : ObservableObject, IDisposable
10+
{
11+
public bool IsLoading
12+
{
13+
get => _isLoading;
14+
private set => SetProperty(ref _isLoading, value);
15+
}
16+
17+
public List<string> VisibleFiles
18+
{
19+
get => _visibleFiles;
20+
private set => SetProperty(ref _visibleFiles, value);
21+
}
22+
23+
public string Filter
24+
{
25+
get => _filter;
26+
set
27+
{
28+
if (SetProperty(ref _filter, value))
29+
UpdateVisible();
30+
}
31+
}
32+
33+
public string SelectedFile
34+
{
35+
get => _selectedFile;
36+
set => SetProperty(ref _selectedFile, value);
37+
}
38+
39+
public FileHistoryCommandPalette(Launcher launcher, string repo)
40+
{
41+
_launcher = launcher;
42+
_repo = repo;
43+
_isLoading = true;
44+
45+
Task.Run(async () =>
46+
{
47+
var files = await new Commands.QueryRevisionFileNames(_repo, "HEAD")
48+
.GetResultAsync()
49+
.ConfigureAwait(false);
50+
51+
Dispatcher.UIThread.Post(() =>
52+
{
53+
IsLoading = false;
54+
_repoFiles = files;
55+
UpdateVisible();
56+
});
57+
});
58+
}
59+
60+
public void Dispose()
61+
{
62+
_launcher = null;
63+
_repo = null;
64+
_repoFiles.Clear();
65+
_filter = null;
66+
_visibleFiles.Clear();
67+
_selectedFile = null;
68+
}
69+
70+
public void ClearFilter()
71+
{
72+
Filter = string.Empty;
73+
}
74+
75+
public void Launch()
76+
{
77+
if (!string.IsNullOrEmpty(_selectedFile))
78+
App.ShowWindow(new FileHistories(_repo, _selectedFile));
79+
_launcher.CancelCommandPalette();
80+
}
81+
82+
private void UpdateVisible()
83+
{
84+
if (_repoFiles is { Count: > 0 })
85+
{
86+
if (string.IsNullOrEmpty(_filter))
87+
{
88+
VisibleFiles = _repoFiles;
89+
}
90+
else
91+
{
92+
var visible = new List<string>();
93+
foreach (var f in _repoFiles)
94+
{
95+
if (f.Contains(_filter, StringComparison.OrdinalIgnoreCase))
96+
visible.Add(f);
97+
}
98+
VisibleFiles = visible;
99+
}
100+
}
101+
}
102+
103+
private Launcher _launcher = null;
104+
private string _repo = null;
105+
private bool _isLoading = false;
106+
private List<string> _repoFiles = null;
107+
private string _filter = string.Empty;
108+
private List<string> _visibleFiles = [];
109+
private string _selectedFile = null;
110+
}
111+
}

src/ViewModels/LauncherPagesCommandPalette.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public void OpenOrSwitchTo()
8484
else if (_selectedRepo != null)
8585
_launcher.OpenRepositoryInTab(_selectedRepo, null);
8686

87-
_launcher.CancelCommandPalette();
87+
_launcher?.CancelCommandPalette();
8888
}
8989

9090
private void UpdateVisible()
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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:vm="using:SourceGit.ViewModels"
6+
xmlns:v="using:SourceGit.Views"
7+
xmlns:c="using:SourceGit.Converters"
8+
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
9+
x:Class="SourceGit.Views.FileHistoryCommandPalette"
10+
x:DataType="vm:FileHistoryCommandPalette">
11+
<Grid RowDefinitions="Auto,Auto,Auto">
12+
<TextBox Grid.Row="0"
13+
x:Name="FilterTextBox"
14+
Height="24"
15+
Margin="4,8,4,0"
16+
BorderThickness="1"
17+
CornerRadius="12"
18+
Text="{Binding Filter, Mode=TwoWay}"
19+
BorderBrush="{DynamicResource Brush.Border2}"
20+
VerticalContentAlignment="Center"
21+
v:AutoFocusBehaviour.IsEnabled="True">
22+
<TextBox.InnerLeftContent>
23+
<Path Width="14" Height="14"
24+
Margin="6,0,0,0"
25+
Fill="{DynamicResource Brush.FG2}"
26+
Data="{StaticResource Icons.Search}"/>
27+
</TextBox.InnerLeftContent>
28+
29+
<TextBox.InnerRightContent>
30+
<Button Classes="icon_button"
31+
Width="16"
32+
Margin="0,0,6,0"
33+
Command="{Binding ClearFilter}"
34+
IsVisible="{Binding Filter, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
35+
HorizontalAlignment="Right">
36+
<Path Width="14" Height="14"
37+
Margin="0,1,0,0"
38+
Fill="{DynamicResource Brush.FG1}"
39+
Data="{StaticResource Icons.Clear}"/>
40+
</Button>
41+
</TextBox.InnerRightContent>
42+
</TextBox>
43+
44+
<TextBlock Grid.Row="1"
45+
Margin="6,8,0,8"
46+
Text="{DynamicResource Text.FileHistory}"
47+
FontWeight="Bold"
48+
Foreground="{DynamicResource Brush.FG2}"
49+
IsVisible="{Binding VisibleFiles, Converter={x:Static c:ListConverters.IsNotNullOrEmpty}}"/>
50+
51+
<ListBox Grid.Row="2"
52+
x:Name="FileListBox"
53+
MaxHeight="250"
54+
Margin="4,0"
55+
BorderThickness="0"
56+
SelectionMode="Single"
57+
Background="Transparent"
58+
Focusable="True"
59+
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
60+
ScrollViewer.VerticalScrollBarVisibility="Auto"
61+
ItemsSource="{Binding VisibleFiles, Mode=OneWay}"
62+
SelectedItem="{Binding SelectedFile, Mode=TwoWay}"
63+
IsVisible="{Binding VisibleFiles, Converter={x:Static c:ListConverters.IsNotNullOrEmpty}}">
64+
<ListBox.Styles>
65+
<Style Selector="ListBoxItem">
66+
<Setter Property="Padding" Value="8,0"/>
67+
<Setter Property="MinHeight" Value="26"/>
68+
<Setter Property="CornerRadius" Value="4"/>
69+
</Style>
70+
71+
<Style Selector="ListBox">
72+
<Setter Property="FocusAdorner">
73+
<FocusAdornerTemplate>
74+
<Grid/>
75+
</FocusAdornerTemplate>
76+
</Setter>
77+
</Style>
78+
</ListBox.Styles>
79+
80+
<ListBox.ItemsPanel>
81+
<ItemsPanelTemplate>
82+
<VirtualizingStackPanel Orientation="Vertical"/>
83+
</ItemsPanelTemplate>
84+
</ListBox.ItemsPanel>
85+
86+
<ListBox.ItemTemplate>
87+
<DataTemplate DataType="x:String">
88+
<Grid ColumnDefinitions="Auto,*" Background="Transparent" Tapped="OnItemTapped">
89+
<Path Grid.Column="0"
90+
Width="12" Height="12"
91+
Data="{StaticResource Icons.File}"
92+
IsHitTestVisible="False"/>
93+
<TextBlock Grid.Column="1"
94+
Margin="4,0,0,0"
95+
VerticalAlignment="Center"
96+
IsHitTestVisible="False">
97+
<Run Text="{Binding Converter={x:Static c:PathConverters.PureFileName}, Mode=OneWay}"/>
98+
<Run Text=" "/>
99+
<Run Text="{Binding Converter={x:Static c:PathConverters.PureDirectoryName}, Mode=OneWay}" Foreground="{DynamicResource Brush.FG2}"/>
100+
</TextBlock>
101+
</Grid>
102+
</DataTemplate>
103+
</ListBox.ItemTemplate>
104+
</ListBox>
105+
106+
<v:LoadingIcon Grid.Row="2"
107+
Width="48" Height="48"
108+
Margin="0,12,0,8"
109+
HorizontalAlignment="Center" VerticalAlignment="Center"
110+
IsVisible="{Binding IsLoading}"/>
111+
</Grid>
112+
</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 FileHistoryCommandPalette : UserControl
7+
{
8+
public FileHistoryCommandPalette()
9+
{
10+
InitializeComponent();
11+
}
12+
13+
protected override void OnKeyDown(KeyEventArgs e)
14+
{
15+
base.OnKeyDown(e);
16+
17+
if (DataContext is not ViewModels.FileHistoryCommandPalette 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 (FileListBox.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.VisibleFiles.Count > 0)
39+
{
40+
FileListBox.Focus(NavigationMethod.Directional);
41+
vm.SelectedFile = vm.VisibleFiles[0];
42+
}
43+
44+
e.Handled = true;
45+
return;
46+
}
47+
48+
if (FileListBox.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.FileHistoryCommandPalette vm)
60+
{
61+
vm.Launch();
62+
e.Handled = true;
63+
}
64+
}
65+
}
66+
}

src/Views/Hotkeys.axaml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Increase}}"
7878
Margin="0,8"/>
7979

80-
<Grid RowDefinitions="20,20,20,20,20,20,20,20,20,20,20,20" ColumnDefinitions="150,*">
80+
<Grid RowDefinitions="20,20,20,20,20,20,20,20,20,20,20,20,20" ColumnDefinitions="150,*">
8181
<TextBlock Grid.Row="0" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Shift+H, macOS=⌘+⇧+H}"/>
8282
<TextBlock Grid.Row="0" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.GoHome}" />
8383

@@ -111,8 +111,11 @@
111111
<TextBlock Grid.Row="10" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Shift+Up, macOS=⌘+⇧+Up}"/>
112112
<TextBlock Grid.Row="10" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.Push}" />
113113

114-
<TextBlock Grid.Row="11" Grid.Column="0" Classes="bold" Text="F5"/>
115-
<TextBlock Grid.Row="11" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.Refresh}" />
114+
<TextBlock Grid.Row="11" Grid.Column="0" Classes="bold" Text="{OnPlatform Ctrl+Shift+F, macOS=⌘+⇧+F}"/>
115+
<TextBlock Grid.Row="11" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.OpenFileHistoryCommandPalette}" />
116+
117+
<TextBlock Grid.Row="12" Grid.Column="0" Classes="bold" Text="F5"/>
118+
<TextBlock Grid.Row="12" Grid.Column="1" Margin="16,0,0,0" Text="{DynamicResource Text.Hotkeys.Repo.Refresh}" />
116119
</Grid>
117120

118121
<TextBlock Text="{DynamicResource Text.Hotkeys.TextEditor}"

src/Views/Launcher.axaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@
135135
<DataTemplate DataType="vm:LauncherPagesCommandPalette">
136136
<v:LauncherPagesCommandPalette/>
137137
</DataTemplate>
138+
<DataTemplate DataType="vm:FileHistoryCommandPalette">
139+
<v:FileHistoryCommandPalette/>
140+
</DataTemplate>
138141
</ContentControl.DataTemplates>
139142
</ContentControl>
140143
</Border>

src/Views/Launcher.axaml.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ protected override async void OnKeyDown(KeyEventArgs e)
224224
repo.SelectedViewIndex = 2;
225225
e.Handled = true;
226226
return;
227+
case Key.F when e.KeyModifiers.HasFlag(KeyModifiers.Shift):
228+
vm.OpenCommandPalette(new ViewModels.FileHistoryCommandPalette(vm, repo.FullPath));
229+
e.Handled = true;
230+
return;
227231
case Key.F:
228232
repo.IsSearching = true;
229233
e.Handled = true;

0 commit comments

Comments
 (0)