refactor: workspace/page switcher (#1330)

- add `Switch Tab` popup
- change hotkey to open `Preferences` to `Ctrl+,/⌘+,`
- change hotkey to open `Switch Workspace` to `Ctrl+Shift+P/⌘+⇧+P`
- change hotkey to open `Switch Tab` to `Ctrl+P/⌘+P`

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo 2025-05-18 19:36:17 +08:00
parent 36c2e083cc
commit 9614b995d8
No known key found for this signature in database
17 changed files with 418 additions and 180 deletions

View file

@ -1,6 +1,7 @@
using System;
using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
@ -18,6 +19,20 @@ namespace SourceGit.Views
get => GetValue(IsScrollerVisibleProperty);
set => SetValue(IsScrollerVisibleProperty, value);
}
public static readonly StyledProperty<string> SearchFilterProperty =
AvaloniaProperty.Register<LauncherTabBar, string>(nameof(SearchFilter));
public string SearchFilter
{
get => GetValue(SearchFilterProperty);
set => SetValue(SearchFilterProperty, value);
}
public AvaloniaList<ViewModels.LauncherPage> SelectablePages
{
get;
} = [];
public LauncherTabBar()
{
@ -125,7 +140,15 @@ namespace SourceGit.Views
var stroke = new Pen(this.FindResource("Brush.Border0") as IBrush);
context.DrawGeometry(fill, stroke, geo);
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == SearchFilterProperty)
UpdateSelectablePages();
}
private void ScrollTabs(object _, PointerWheelEventArgs e)
{
if (!e.KeyModifiers.HasFlag(KeyModifiers.Shift))
@ -247,16 +270,92 @@ namespace SourceGit.Views
e.Handled = true;
}
private void OnGotoSelectedPage(object sender, LauncherTabSelectedEventArgs e)
private void OnTabsDropdownOpened(object sender, EventArgs e)
{
if (DataContext is ViewModels.Launcher vm)
vm.ActivePage = e.Page;
UpdateSelectablePages();
}
private void OnTabsDropdownKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
PageSelector.Flyout?.Hide();
e.Handled = true;
}
else if (e.Key == Key.Enter)
{
if (TabsDropdownList.SelectedItem is ViewModels.LauncherPage page &&
DataContext is ViewModels.Launcher vm)
{
vm.ActivePage = page;
PageSelector.Flyout?.Hide();
e.Handled = true;
}
}
}
private void OnTabsDropdownSearchBoxKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Down && TabsDropdownList.ItemCount > 0)
{
TabsDropdownList.Focus(NavigationMethod.Directional);
PageSelector.Flyout?.Hide();
e.Handled = true;
if (TabsDropdownList.SelectedIndex < 0)
TabsDropdownList.SelectedIndex = 0;
else if (TabsDropdownList.SelectedIndex < TabsDropdownList.ItemCount)
TabsDropdownList.SelectedIndex++;
e.Handled = true;
}
}
private void OnTabsDropdownLostFocus(object sender, RoutedEventArgs e)
{
if (sender is Control { IsFocused: false, IsKeyboardFocusWithin: false })
PageSelector.Flyout?.Hide();
}
private void OnClearSearchFilter(object sender, RoutedEventArgs e)
{
SearchFilter = string.Empty;
}
private void OnTabsDropdownItemDoubleTapped(object sender, TappedEventArgs e)
{
if (sender is Control { DataContext: ViewModels.LauncherPage page } &&
DataContext is ViewModels.Launcher vm)
{
vm.ActivePage = page;
PageSelector.Flyout?.Hide();
e.Handled = true;
}
}
private void UpdateSelectablePages()
{
if (DataContext is not ViewModels.Launcher vm)
return;
SelectablePages.Clear();
var pages = vm.Pages;
var filter = SearchFilter?.Trim() ?? "";
if (string.IsNullOrEmpty(filter))
{
SelectablePages.AddRange(pages);
return;
}
foreach (var page in pages)
{
var node = page.Node;
if (node.Name.Contains(filter, StringComparison.OrdinalIgnoreCase) ||
(node.IsRepository && node.Id.Contains(filter, StringComparison.OrdinalIgnoreCase)))
SelectablePages.Add(page);
}
}
private bool _pressedTab = false;
private Point _pressedTabPosition = new Point();
private bool _startDragTab = false;