From 641098ffb23d45312da4d7edf538584623a96a98 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 12 May 2025 16:27:54 +0800 Subject: [PATCH 01/60] ux: better content padding for maximized window on Windows Signed-off-by: leo --- src/Resources/Styles.axaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml index 093ae4e0..882a14f4 100644 --- a/src/Resources/Styles.axaml +++ b/src/Resources/Styles.axaml @@ -40,7 +40,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -461,7 +375,7 @@ SelectionMode="Single" ContextRequested="OnWorktreeContextRequested" DoubleTapped="OnDoubleTappedWorktree" - PropertyChanged="OnLeftSidebarListBoxPropertyChanged" + PropertyChanged="OnWorktreeListPropertyChanged" IsVisible="{Binding IsWorktreeGroupExpanded, Mode=OneWay}"> + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Views/SubmodulesView.axaml.cs b/src/Views/SubmodulesView.axaml.cs new file mode 100644 index 00000000..116cbe9f --- /dev/null +++ b/src/Views/SubmodulesView.axaml.cs @@ -0,0 +1,174 @@ +using System; + +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.Layout; +using Avalonia.Media; +using Avalonia.VisualTree; + +namespace SourceGit.Views +{ + public class SubmoduleTreeNodeToggleButton : ToggleButton + { + protected override Type StyleKeyOverride => typeof(ToggleButton); + + protected override void OnPointerPressed(PointerPressedEventArgs e) + { + if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed && + DataContext is ViewModels.SubmoduleTreeNode { IsFolder: true } node) + { + var view = this.FindAncestorOfType(); + view?.ToggleNodeIsExpanded(node); + } + + e.Handled = true; + } + } + + public class SubmoduleTreeNodeIcon : UserControl + { + public static readonly StyledProperty IsExpandedProperty = + AvaloniaProperty.Register(nameof(IsExpanded)); + + public bool IsExpanded + { + get => GetValue(IsExpandedProperty); + set => SetValue(IsExpandedProperty, value); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == IsExpandedProperty) + UpdateContent(); + } + + protected override void OnDataContextChanged(EventArgs e) + { + base.OnDataContextChanged(e); + UpdateContent(); + } + + private void UpdateContent() + { + if (DataContext is not ViewModels.SubmoduleTreeNode node) + { + Content = null; + return; + } + + if (node.Module != null) + CreateContent(new Thickness(0, 0, 0, 0), "Icons.Submodule"); + else if (node.IsExpanded) + CreateContent(new Thickness(0, 2, 0, 0), "Icons.Folder.Open"); + else + CreateContent(new Thickness(0, 2, 0, 0), "Icons.Folder"); + } + + private void CreateContent(Thickness margin, string iconKey) + { + var geo = this.FindResource(iconKey) as StreamGeometry; + if (geo == null) + return; + + Content = new Avalonia.Controls.Shapes.Path() + { + Width = 12, + Height = 12, + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Center, + Margin = margin, + Data = geo, + }; + } + } + + public partial class SubmodulesView : UserControl + { + public static readonly StyledProperty SubmodulesProperty = + AvaloniaProperty.Register(nameof(Submodules)); + + public ViewModels.SubmoduleCollection Submodules + { + get => GetValue(SubmodulesProperty); + set => SetValue(SubmodulesProperty, value); + } + + public static readonly RoutedEvent RowsChangedEvent = + RoutedEvent.Register(nameof(RowsChanged), RoutingStrategies.Tunnel | RoutingStrategies.Bubble); + + public event EventHandler RowsChanged + { + add { AddHandler(RowsChangedEvent, value); } + remove { RemoveHandler(RowsChangedEvent, value); } + } + + public int Rows + { + get; + private set; + } + + public SubmodulesView() + { + InitializeComponent(); + } + + public void ToggleNodeIsExpanded(ViewModels.SubmoduleTreeNode node) + { + var submodules = Submodules; + if (submodules != null) + { + submodules.ToggleExpand(node); + Rows = submodules.Rows.Count; + RaiseEvent(new RoutedEventArgs(RowsChangedEvent)); + } + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == SubmodulesProperty) + { + Rows = Submodules?.Rows.Count ?? 0; + RaiseEvent(new RoutedEventArgs(RowsChangedEvent)); + } + else if (change.Property == IsVisibleProperty) + { + RaiseEvent(new RoutedEventArgs(RowsChangedEvent)); + } + } + + private void OnDoubleTappedNode(object sender, TappedEventArgs e) + { + if (sender is Control { DataContext: ViewModels.SubmoduleTreeNode node } && + DataContext is ViewModels.Repository repo) + { + if (node.IsFolder) + ToggleNodeIsExpanded(node); + else if (node.Module.Status != Models.SubmoduleStatus.NotInited) + repo.OpenSubmodule(node.Module.Path); + } + + e.Handled = true; + } + + private void OnRowContextRequested(object sender, ContextRequestedEventArgs e) + { + if (sender is Control { DataContext: ViewModels.SubmoduleTreeNode node } control && + node.Module != null && + DataContext is ViewModels.Repository repo) + { + var menu = repo.CreateContextMenuForSubmodule(node.Module); + menu?.Open(control); + } + + e.Handled = true; + } + } +} From 85e08f5eea483818f4756a177b5be534c5b665c3 Mon Sep 17 00:00:00 2001 From: AquariusStar <48148723+AquariusStar@users.noreply.github.com> Date: Fri, 16 May 2025 04:20:31 +0300 Subject: [PATCH 29/60] localization: update russian localization (#1319) --- src/Resources/Locales/ru_RU.axaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index 1c45f22f..ca5cc384 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -410,6 +410,7 @@ Закрыть панель поиска Найти следующее совпадение Найти предыдущее совпадение + Открыть с внешним инструментом сравнения/слияние Открыть панель поиска Отклонить Сформировать @@ -708,6 +709,12 @@ Каталог: Относительный путь для хранения подмодуля. Удалить подмодуль + СОСТОЯНИЕ + изменён + не создан + ревизия изменена + не слита + URL-адрес ОК Копировать имя метки Копировать сообщение с метки From 6c62789c4cf13fd668c8e0d18066a850c3ccfbbd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 16 May 2025 01:20:43 +0000 Subject: [PATCH 30/60] doc: Update translation status and sort locale files --- TRANSLATION.md | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 16649d1f..2e1e8d64 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -309,20 +309,7 @@ This document shows the translation status of each locale file in the repository -### ![ru__RU](https://img.shields.io/badge/ru__RU-99.11%25-yellow) - -
-Missing keys in ru_RU.axaml - -- Text.Hotkeys.TextEditor.OpenExternalMergeTool -- Text.Submodule.Status -- Text.Submodule.Status.Modified -- Text.Submodule.Status.NotInited -- Text.Submodule.Status.RevisionChanged -- Text.Submodule.Status.Unmerged -- Text.Submodule.URL - -
+### ![ru__RU](https://img.shields.io/badge/ru__RU-%E2%88%9A-brightgreen) ### ![ta__IN](https://img.shields.io/badge/ta__IN-94.65%25-yellow) From 85b223a3d058d84a868e96963a56fecd8c1f20ac Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Fri, 16 May 2025 02:27:42 +0100 Subject: [PATCH 31/60] Task/UI usability tweaks (#1314) * Allow About to center in parent * About closes on Escape * ConfirmEmptyCommit dialog closes on Escape * Ignore Dev file * Missed condition --------- Co-authored-by: Martin Smith --- .gitignore | 1 + src/App.axaml.cs | 9 +++++++-- src/Views/About.axaml | 7 ++++++- src/Views/ConfirmEmptyCommit.axaml | 2 ++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 498c7e32..e686a534 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ build/*.rpm build/*.AppImage SourceGit.app/ build.command +src/Properties/launchSettings.json diff --git a/src/App.axaml.cs b/src/App.axaml.cs index 6e45164d..ec0f79c9 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -109,8 +109,13 @@ namespace SourceGit { if (data is Views.ChromelessWindow window) { - if (showAsDialog && Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner }) - window.ShowDialog(owner); + if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner }) + { + if (showAsDialog) + window.ShowDialog(owner); + else + window.Show(owner); + } else window.Show(); diff --git a/src/Views/About.axaml b/src/Views/About.axaml index d0dd7b82..bcc133e4 100644 --- a/src/Views/About.axaml +++ b/src/Views/About.axaml @@ -10,7 +10,7 @@ Title="{DynamicResource Text.About}" Width="520" Height="230" CanResize="False" - WindowStartupLocation="CenterScreen"> + WindowStartupLocation="CenterOwner"> @@ -67,4 +67,9 @@ + + + + + diff --git a/src/Views/ConfirmEmptyCommit.axaml b/src/Views/ConfirmEmptyCommit.axaml index 32a1f2cd..bfa42ef0 100644 --- a/src/Views/ConfirmEmptyCommit.axaml +++ b/src/Views/ConfirmEmptyCommit.axaml @@ -12,6 +12,7 @@ Title="{DynamicResource Text.Warn}" SizeToContent="WidthAndHeight" CanResize="False" + ShowInTaskbar="False" WindowStartupLocation="CenterOwner"> @@ -64,6 +65,7 @@ Height="30" Margin="4,0" Click="CloseWindow" + IsCancel="True" Content="{DynamicResource Text.Cancel}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/> From e4490d87dc6c1974fd3b8c0d72325a253a0089d0 Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 16 May 2025 09:44:36 +0800 Subject: [PATCH 32/60] code_review: PR #1314 Signed-off-by: leo --- src/App.axaml.cs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/App.axaml.cs b/src/App.axaml.cs index ec0f79c9..45ab0b8c 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -107,18 +107,24 @@ namespace SourceGit #region Utility Functions public static void ShowWindow(object data, bool showAsDialog) { - if (data is Views.ChromelessWindow window) + var impl = (Views.ChromelessWindow target, bool isDialog) => { if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner }) { - if (showAsDialog) - window.ShowDialog(owner); + if (isDialog) + target.ShowDialog(owner); else - window.Show(owner); + target.Show(owner); } else - window.Show(); + { + target.Show(); + } + }; + if (data is Views.ChromelessWindow window) + { + impl(window, showAsDialog); return; } @@ -135,10 +141,7 @@ namespace SourceGit if (window != null) { window.DataContext = data; - if (showAsDialog && Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner }) - window.ShowDialog(owner); - else - window.Show(); + impl(window, showAsDialog); } } From d2994696130613e49331c5f9f352bf6b6523dddf Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 16 May 2025 10:47:38 +0800 Subject: [PATCH 33/60] ux: show tooltip at right of hovered item in repository's left side bar (#1317) Signed-off-by: leo --- src/Views/BranchTree.axaml | 8 +++++--- src/Views/SubmodulesView.axaml | 7 ++++++- src/Views/TagsView.axaml | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/Views/BranchTree.axaml b/src/Views/BranchTree.axaml index 61a08613..a90b327e 100644 --- a/src/Views/BranchTree.axaml +++ b/src/Views/BranchTree.axaml @@ -32,11 +32,13 @@ - + + ColumnDefinitions="16,*"> - + diff --git a/src/Views/TagsView.axaml b/src/Views/TagsView.axaml index 9bf1e653..2795c403 100644 --- a/src/Views/TagsView.axaml +++ b/src/Views/TagsView.axaml @@ -26,7 +26,13 @@ SelectionChanged="OnRowSelectionChanged"> - + @@ -86,7 +92,11 @@ SelectionChanged="OnRowSelectionChanged"> - + From ed1351b1f789e7550be3b8b7857953edf2a84fec Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 16 May 2025 11:31:53 +0800 Subject: [PATCH 34/60] feature: supports to show submodules as tree or list (#1307) Signed-off-by: leo --- src/Resources/Locales/en_US.axaml | 1 + src/Resources/Locales/zh_CN.axaml | 1 + src/Resources/Locales/zh_TW.axaml | 1 + src/Resources/Styles.axaml | 2 +- src/ViewModels/Preferences.cs | 6 + src/ViewModels/Repository.cs | 27 +- ...duleTreeNode.cs => SubmoduleCollection.cs} | 24 +- src/Views/Repository.axaml | 16 +- src/Views/SubmodulesView.axaml | 312 ++++++++++++------ src/Views/SubmodulesView.axaml.cs | 64 ++-- 10 files changed, 302 insertions(+), 152 deletions(-) rename src/ViewModels/{SubmoduleTreeNode.cs => SubmoduleCollection.cs} (90%) diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index cee9ad2c..2f7c5c43 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -617,6 +617,7 @@ Message SHA Current Branch + Show Submodules as Tree Show Tags as Tree SKIP Statistics diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 3b0237da..56227607 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -621,6 +621,7 @@ 提交信息 提交指纹 仅在当前分支中查找 + 以树型结构展示 以树型结构展示 跳过此提交 提交统计 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 6b3ce423..204e1cf7 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -621,6 +621,7 @@ 提交訊息 提交編號 僅搜尋目前分支 + 以樹型結構展示 以樹型結構展示 跳過此提交 提交統計 diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml index 882a14f4..923ef22b 100644 --- a/src/Resources/Styles.axaml +++ b/src/Resources/Styles.axaml @@ -1235,7 +1235,7 @@ - + - - - - + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Views/SubmodulesView.axaml.cs b/src/Views/SubmodulesView.axaml.cs index 116cbe9f..81ccdc5d 100644 --- a/src/Views/SubmodulesView.axaml.cs +++ b/src/Views/SubmodulesView.axaml.cs @@ -89,15 +89,6 @@ namespace SourceGit.Views public partial class SubmodulesView : UserControl { - public static readonly StyledProperty SubmodulesProperty = - AvaloniaProperty.Register(nameof(Submodules)); - - public ViewModels.SubmoduleCollection Submodules - { - get => GetValue(SubmodulesProperty); - set => SetValue(SubmodulesProperty, value); - } - public static readonly RoutedEvent RowsChangedEvent = RoutedEvent.Register(nameof(RowsChanged), RoutingStrategies.Tunnel | RoutingStrategies.Bubble); @@ -120,11 +111,10 @@ namespace SourceGit.Views public void ToggleNodeIsExpanded(ViewModels.SubmoduleTreeNode node) { - var submodules = Submodules; - if (submodules != null) + if (Content is ViewModels.SubmoduleCollectionAsTree tree) { - submodules.ToggleExpand(node); - Rows = submodules.Rows.Count; + tree.ToggleExpand(node); + Rows = tree.Rows.Count; RaiseEvent(new RoutedEventArgs(RowsChangedEvent)); } } @@ -133,9 +123,15 @@ namespace SourceGit.Views { base.OnPropertyChanged(change); - if (change.Property == SubmodulesProperty) + if (change.Property == ContentProperty) { - Rows = Submodules?.Rows.Count ?? 0; + if (Content is ViewModels.SubmoduleCollectionAsTree tree) + Rows = tree.Rows.Count; + else if (Content is ViewModels.SubmoduleCollectionAsList list) + Rows = list.Submodules.Count; + else + Rows = 0; + RaiseEvent(new RoutedEventArgs(RowsChangedEvent)); } else if (change.Property == IsVisibleProperty) @@ -144,28 +140,40 @@ namespace SourceGit.Views } } - private void OnDoubleTappedNode(object sender, TappedEventArgs e) + private void OnItemDoubleTapped(object sender, TappedEventArgs e) { - if (sender is Control { DataContext: ViewModels.SubmoduleTreeNode node } && - DataContext is ViewModels.Repository repo) + if (sender is Control control && DataContext is ViewModels.Repository repo) { - if (node.IsFolder) - ToggleNodeIsExpanded(node); - else if (node.Module.Status != Models.SubmoduleStatus.NotInited) - repo.OpenSubmodule(node.Module.Path); + if (control.DataContext is ViewModels.SubmoduleTreeNode node) + { + if (node.IsFolder) + ToggleNodeIsExpanded(node); + else if (node.Module.Status != Models.SubmoduleStatus.NotInited) + repo.OpenSubmodule(node.Module.Path); + } + else if (control.DataContext is Models.Submodule m && m.Status != Models.SubmoduleStatus.NotInited) + { + repo.OpenSubmodule(m.Path); + } } e.Handled = true; } - private void OnRowContextRequested(object sender, ContextRequestedEventArgs e) + private void OnItemContextRequested(object sender, ContextRequestedEventArgs e) { - if (sender is Control { DataContext: ViewModels.SubmoduleTreeNode node } control && - node.Module != null && - DataContext is ViewModels.Repository repo) + if (sender is Control control && DataContext is ViewModels.Repository repo) { - var menu = repo.CreateContextMenuForSubmodule(node.Module); - menu?.Open(control); + if (control.DataContext is ViewModels.SubmoduleTreeNode node && node.Module != null) + { + var menu = repo.CreateContextMenuForSubmodule(node.Module); + menu?.Open(control); + } + else if (control.DataContext is Models.Submodule m) + { + var menu = repo.CreateContextMenuForSubmodule(m); + menu?.Open(control); + } } e.Handled = true; From f46bbd01cdf1489a8978b655bef8f4de06d6ecbc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 16 May 2025 03:32:09 +0000 Subject: [PATCH 35/60] doc: Update translation status and sort locale files --- TRANSLATION.md | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 2e1e8d64..7bad5859 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -6,7 +6,7 @@ This document shows the translation status of each locale file in the repository ### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen) -### ![de__DE](https://img.shields.io/badge/de__DE-98.85%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-98.73%25-yellow)
Missing keys in de_DE.axaml @@ -14,6 +14,7 @@ This document shows the translation status of each locale file in the repository - Text.GitFlow.FinishWithPush - Text.GitFlow.FinishWithSquash - Text.Hotkeys.TextEditor.OpenExternalMergeTool +- Text.Repository.ShowSubmodulesAsTree - Text.Submodule.Status - Text.Submodule.Status.Modified - Text.Submodule.Status.NotInited @@ -23,12 +24,13 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-99.11%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-98.98%25-yellow)
Missing keys in es_ES.axaml - Text.Hotkeys.TextEditor.OpenExternalMergeTool +- Text.Repository.ShowSubmodulesAsTree - Text.Submodule.Status - Text.Submodule.Status.Modified - Text.Submodule.Status.NotInited @@ -38,7 +40,7 @@ This document shows the translation status of each locale file in the repository
-### ![fr__FR](https://img.shields.io/badge/fr__FR-94.65%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-94.53%25-yellow)
Missing keys in fr_FR.axaml @@ -68,6 +70,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.BranchSort.ByCommitterDate - Text.Repository.BranchSort.ByName - Text.Repository.Search.ByContent +- Text.Repository.ShowSubmodulesAsTree - Text.Repository.ViewLogs - Text.Repository.Visit - Text.Submodule.Status @@ -88,7 +91,7 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-94.39%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-94.27%25-yellow)
Missing keys in it_IT.axaml @@ -120,6 +123,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.BranchSort.ByCommitterDate - Text.Repository.BranchSort.ByName - Text.Repository.Search.ByContent +- Text.Repository.ShowSubmodulesAsTree - Text.Repository.ViewLogs - Text.Repository.Visit - Text.Submodule.Status @@ -140,7 +144,7 @@ This document shows the translation status of each locale file in the repository
-### ![ja__JP](https://img.shields.io/badge/ja__JP-94.39%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-94.27%25-yellow)
Missing keys in ja_JP.axaml @@ -171,6 +175,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.BranchSort.ByName - Text.Repository.FilterCommits - Text.Repository.Search.ByContent +- Text.Repository.ShowSubmodulesAsTree - Text.Repository.Tags.OrderByNameDes - Text.Repository.ViewLogs - Text.Repository.Visit @@ -192,7 +197,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-86.11%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-86.01%25-yellow)
Missing keys in pt_BR.axaml @@ -273,6 +278,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.Notifications.Clear - Text.Repository.OnlyHighlightCurrentBranchInHistories - Text.Repository.Search.ByContent +- Text.Repository.ShowSubmodulesAsTree - Text.Repository.Skip - Text.Repository.Tags.OrderByCreatorDate - Text.Repository.Tags.OrderByNameAsc @@ -309,9 +315,16 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-%E2%88%9A-brightgreen) +### ![ru__RU](https://img.shields.io/badge/ru__RU-99.87%25-yellow) -### ![ta__IN](https://img.shields.io/badge/ta__IN-94.65%25-yellow) +
+Missing keys in ru_RU.axaml + +- Text.Repository.ShowSubmodulesAsTree + +
+ +### ![ta__IN](https://img.shields.io/badge/ta__IN-94.53%25-yellow)
Missing keys in ta_IN.axaml @@ -341,6 +354,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.BranchSort.ByCommitterDate - Text.Repository.BranchSort.ByName - Text.Repository.Search.ByContent +- Text.Repository.ShowSubmodulesAsTree - Text.Repository.ViewLogs - Text.Repository.Visit - Text.Submodule.Status @@ -361,7 +375,7 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-95.80%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-95.67%25-yellow)
Missing keys in uk_UA.axaml @@ -387,6 +401,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.BranchSort.ByCommitterDate - Text.Repository.BranchSort.ByName - Text.Repository.Search.ByContent +- Text.Repository.ShowSubmodulesAsTree - Text.Repository.ViewLogs - Text.Repository.Visit - Text.Submodule.Status From fd935259aafa01e584801cbf84903f8767349eb3 Mon Sep 17 00:00:00 2001 From: leo Date: Fri, 16 May 2025 12:22:37 +0800 Subject: [PATCH 36/60] refactor: build tags view data in viewmodels instead of views Signed-off-by: leo --- src/ViewModels/Preferences.cs | 7 +- src/ViewModels/Repository.cs | 28 ++++- src/ViewModels/SubmoduleCollection.cs | 10 +- src/ViewModels/TagCollection.cs | 72 ++++++++++++- src/Views/Repository.axaml | 5 +- src/Views/TagsView.axaml | 53 +++++---- src/Views/TagsView.axaml.cs | 148 +++++--------------------- 7 files changed, 151 insertions(+), 172 deletions(-) diff --git a/src/ViewModels/Preferences.cs b/src/ViewModels/Preferences.cs index 5ce6f769..2698067e 100644 --- a/src/ViewModels/Preferences.cs +++ b/src/ViewModels/Preferences.cs @@ -178,9 +178,9 @@ namespace SourceGit.ViewModels public bool ShowTagsAsTree { - get => _showTagsAsTree; - set => SetProperty(ref _showTagsAsTree, value); - } + get; + set; + } = false; public bool ShowTagsInGraph { @@ -677,7 +677,6 @@ namespace SourceGit.ViewModels private double _lastCheckUpdateTime = 0; private string _ignoreUpdateTag = string.Empty; - private bool _showTagsAsTree = false; private bool _showTagsInGraph = true; private bool _useTwoColumnsLayoutInHistories = false; private bool _displayTimeAsPeriodInHistories = false; diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index c3e7c478..d24f6fbf 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -198,7 +198,21 @@ namespace SourceGit.ViewModels private set => SetProperty(ref _tags, value); } - public List VisibleTags + public bool ShowTagsAsTree + { + get => Preferences.Instance.ShowTagsAsTree; + set + { + if (value != Preferences.Instance.ShowTagsAsTree) + { + Preferences.Instance.ShowTagsAsTree = value; + VisibleTags = BuildVisibleTags(); + OnPropertyChanged(); + } + } + } + + public object VisibleTags { get => _visibleTags; private set => SetProperty(ref _visibleTags, value); @@ -548,7 +562,7 @@ namespace SourceGit.ViewModels _localBranchTrees.Clear(); _remoteBranchTrees.Clear(); _tags.Clear(); - _visibleTags.Clear(); + _visibleTags = null; _submodules.Clear(); _visibleSubmodules = null; _searchedCommits.Clear(); @@ -2492,7 +2506,7 @@ namespace SourceGit.ViewModels return builder; } - private List BuildVisibleTags() + private object BuildVisibleTags() { switch (_settings.TagSortMode) { @@ -2523,7 +2537,11 @@ namespace SourceGit.ViewModels var historiesFilters = _settings.CollectHistoriesFilters(); UpdateTagFilterMode(historiesFilters); - return visible; + + if (Preferences.Instance.ShowTagsAsTree) + return TagCollectionAsTree.Build(visible, _visibleTags as TagCollectionAsTree); + else + return new TagCollectionAsList() { Tags = visible }; } private object BuildVisibleSubmodules() @@ -2775,7 +2793,7 @@ namespace SourceGit.ViewModels private List _remoteBranchTrees = new List(); private List _worktrees = new List(); private List _tags = new List(); - private List _visibleTags = new List(); + private object _visibleTags = null; private List _submodules = new List(); private object _visibleSubmodules = null; diff --git a/src/ViewModels/SubmoduleCollection.cs b/src/ViewModels/SubmoduleCollection.cs index e2ebf634..4600496e 100644 --- a/src/ViewModels/SubmoduleCollection.cs +++ b/src/ViewModels/SubmoduleCollection.cs @@ -150,18 +150,12 @@ namespace SourceGit.ViewModels collection.Tree = SubmoduleTreeNode.Build(submodules, oldExpanded); var rows = new List(); - collection.MakeTreeRows(rows, collection.Tree); + MakeTreeRows(rows, collection.Tree); collection.Rows.AddRange(rows); return collection; } - public void Clear() - { - Tree.Clear(); - Rows.Clear(); - } - public void ToggleExpand(SubmoduleTreeNode node) { node.IsExpanded = !node.IsExpanded; @@ -193,7 +187,7 @@ namespace SourceGit.ViewModels } } - private void MakeTreeRows(List rows, List nodes) + private static void MakeTreeRows(List rows, List nodes) { foreach (var node in nodes) { diff --git a/src/ViewModels/TagCollection.cs b/src/ViewModels/TagCollection.cs index f05a727e..ce9c9508 100644 --- a/src/ViewModels/TagCollection.cs +++ b/src/ViewModels/TagCollection.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; + using Avalonia.Collections; + using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.ViewModels @@ -61,7 +63,7 @@ namespace SourceGit.ViewModels Counter = 1; } - public static List Build(IList tags, HashSet expaneded) + public static List Build(List tags, HashSet expaneded) { var nodes = new List(); var folders = new Dictionary(); @@ -131,7 +133,7 @@ namespace SourceGit.ViewModels public class TagCollectionAsList { - public AvaloniaList Tags + public List Tags { get; set; @@ -151,5 +153,71 @@ namespace SourceGit.ViewModels get; set; } = []; + + public static TagCollectionAsTree Build(List tags, TagCollectionAsTree old) + { + var oldExpanded = new HashSet(); + if (old != null) + { + foreach (var row in old.Rows) + { + if (row.IsFolder && row.IsExpanded) + oldExpanded.Add(row.FullPath); + } + } + + var collection = new TagCollectionAsTree(); + collection.Tree = TagTreeNode.Build(tags, oldExpanded); + + var rows = new List(); + MakeTreeRows(rows, collection.Tree); + collection.Rows.AddRange(rows); + + return collection; + } + + public void ToggleExpand(TagTreeNode node) + { + node.IsExpanded = !node.IsExpanded; + + var rows = Rows; + var depth = node.Depth; + var idx = rows.IndexOf(node); + if (idx == -1) + return; + + if (node.IsExpanded) + { + var subrows = new List(); + MakeTreeRows(subrows, node.Children); + rows.InsertRange(idx + 1, subrows); + } + else + { + var removeCount = 0; + for (int i = idx + 1; i < rows.Count; i++) + { + var row = rows[i]; + if (row.Depth <= depth) + break; + + removeCount++; + } + rows.RemoveRange(idx + 1, removeCount); + } + } + + private static void MakeTreeRows(List rows, List nodes) + { + foreach (var node in nodes) + { + rows.Add(node); + + if (!node.IsExpanded || !node.IsFolder) + continue; + + MakeTreeRows(rows, node.Children); + } + } } } diff --git a/src/Views/Repository.axaml b/src/Views/Repository.axaml index 99bdd6ab..4eb303fe 100644 --- a/src/Views/Repository.axaml +++ b/src/Views/Repository.axaml @@ -271,7 +271,7 @@
-### ![it__IT](https://img.shields.io/badge/it__IT-94.27%25-yellow) - -
-Missing keys in it_IT.axaml - -- Text.Bisect -- Text.Bisect.Abort -- Text.Bisect.Bad -- Text.Bisect.Detecting -- Text.Bisect.Good -- Text.Bisect.Skip -- Text.Bisect.WaitingForRange -- Text.Checkout.RecurseSubmodules -- Text.CommitCM.CopyAuthor -- Text.CommitCM.CopyCommitter -- Text.CommitCM.CopySubject -- Text.CommitMessageTextBox.SubjectCount -- Text.Configure.Git.PreferredMergeMode -- Text.ConfirmEmptyCommit.Continue -- Text.ConfirmEmptyCommit.NoLocalChanges -- Text.ConfirmEmptyCommit.StageAllThenCommit -- Text.ConfirmEmptyCommit.WithLocalChanges -- Text.CopyFullPath -- Text.GitFlow.FinishWithPush -- Text.GitFlow.FinishWithSquash -- Text.Hotkeys.TextEditor.OpenExternalMergeTool -- Text.Preferences.General.ShowTagsInGraph -- Text.Preferences.Git.IgnoreCRAtEOLInDiff -- Text.Repository.BranchSort -- Text.Repository.BranchSort.ByCommitterDate -- Text.Repository.BranchSort.ByName -- Text.Repository.Search.ByContent -- Text.Repository.ShowSubmodulesAsTree -- Text.Repository.ViewLogs -- Text.Repository.Visit -- Text.Submodule.Status -- Text.Submodule.Status.Modified -- Text.Submodule.Status.NotInited -- Text.Submodule.Status.RevisionChanged -- Text.Submodule.Status.Unmerged -- Text.Submodule.URL -- Text.ViewLogs -- Text.ViewLogs.Clear -- Text.ViewLogs.CopyLog -- Text.ViewLogs.Delete -- Text.WorkingCopy.ConfirmCommitWithFilter -- Text.WorkingCopy.Conflicts.OpenExternalMergeTool -- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts -- Text.WorkingCopy.Conflicts.UseMine -- Text.WorkingCopy.Conflicts.UseTheirs - -
+### ![it__IT](https://img.shields.io/badge/it__IT-%E2%88%9A-brightgreen) ### ![ja__JP](https://img.shields.io/badge/ja__JP-94.27%25-yellow) From 879b84ac2040a68eeb437844800e9db2023572f7 Mon Sep 17 00:00:00 2001 From: Gadfly Date: Sat, 17 May 2025 07:58:47 +0800 Subject: [PATCH 41/60] enhance: Show the stderr content from `QueryLocalChanges` (#1327) --- src/Commands/QueryLocalChanges.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Commands/QueryLocalChanges.cs b/src/Commands/QueryLocalChanges.cs index 4e626a79..404f5be6 100644 --- a/src/Commands/QueryLocalChanges.cs +++ b/src/Commands/QueryLocalChanges.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using Avalonia.Threading; namespace SourceGit.Commands { @@ -22,7 +23,10 @@ namespace SourceGit.Commands var outs = new List(); var rs = ReadToEnd(); if (!rs.IsSuccess) + { + Dispatcher.UIThread.Post(() => App.RaiseException(Context, rs.StdErr)); return outs; + } var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) From d3d0e7b15c4b80ec11d9743dbe03e9e1572cf5fd Mon Sep 17 00:00:00 2001 From: leo Date: Sat, 17 May 2025 08:13:19 +0800 Subject: [PATCH 42/60] ux: thinner border for default avatar Signed-off-by: leo --- src/Views/Avatar.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Views/Avatar.cs b/src/Views/Avatar.cs index 9a61c99a..87bc7ce3 100644 --- a/src/Views/Avatar.cs +++ b/src/Views/Avatar.cs @@ -54,8 +54,8 @@ namespace SourceGit.Views { context.DrawRectangle(Brushes.White, new Pen(new SolidColorBrush(Colors.Black, 0.3f), 0.65f), rect, corner, corner); - var offsetX = Bounds.Width / 8.0; - var offsetY = Bounds.Height / 8.0; + var offsetX = Bounds.Width / 10.0; + var offsetY = Bounds.Height / 10.0; var stepX = (Bounds.Width - offsetX * 2) / 5.0; var stepY = (Bounds.Height - offsetY * 2) / 5.0; From d3a740fb95702e0bf05701a86896ebc1e8cfe938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20J=2E=20Mart=C3=ADnez=20M=2E?= <56406225+jjesus-dev@users.noreply.github.com> Date: Fri, 16 May 2025 23:12:01 -0600 Subject: [PATCH 43/60] localization: update spanish translations (#1329) add missing translations --- src/Resources/Locales/es_ES.axaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml index b11d0e98..e2b16329 100644 --- a/src/Resources/Locales/es_ES.axaml +++ b/src/Resources/Locales/es_ES.axaml @@ -410,6 +410,7 @@ Cerrar panel de búsqueda Buscar siguiente coincidencia Buscar coincidencia anterior + Abrir con herramienta diff/merge externa Abrir panel de búsqueda Descartar Stage @@ -620,6 +621,7 @@ Mensaje SHA Rama Actual + Mostrar Submódulos como Árbol Mostrar Etiquetas como Árbol OMITIR Estadísticas @@ -708,6 +710,12 @@ Ruta Relativa: Carpeta relativa para almacenar este módulo. Eliminar Submódulo + ESTADO + modificado + no inicializado + revisión cambiada + unmerged + URL OK Copiar Nombre de la Etiqueta Copiar Mensaje de la Etiqueta From 506dbc218c13b5f560a57e843b326f17ee01cb1a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 17 May 2025 05:12:20 +0000 Subject: [PATCH 44/60] doc: Update translation status and sort locale files --- TRANSLATION.md | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index b604acca..08d3bb06 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -24,21 +24,7 @@ This document shows the translation status of each locale file in the repository -### ![es__ES](https://img.shields.io/badge/es__ES-98.98%25-yellow) - -
-Missing keys in es_ES.axaml - -- Text.Hotkeys.TextEditor.OpenExternalMergeTool -- Text.Repository.ShowSubmodulesAsTree -- Text.Submodule.Status -- Text.Submodule.Status.Modified -- Text.Submodule.Status.NotInited -- Text.Submodule.Status.RevisionChanged -- Text.Submodule.Status.Unmerged -- Text.Submodule.URL - -
+### ![es__ES](https://img.shields.io/badge/es__ES-%E2%88%9A-brightgreen) ### ![fr__FR](https://img.shields.io/badge/fr__FR-94.53%25-yellow) From 01945f231ed8f98e49cdd3de848c922c157c1053 Mon Sep 17 00:00:00 2001 From: popara <31167073+popara96@users.noreply.github.com> Date: Sat, 17 May 2025 07:17:10 +0200 Subject: [PATCH 45/60] Added workspaces shortcuts (#1328) - added Alt+Space for opening Workspaces context menu (which can then be navigated normally with arrows) - added Alt+1 through Alt+9 for switching to corresponding workspace --- src/Resources/Locales/en_US.axaml | 2 ++ src/ViewModels/Launcher.cs | 10 ++++++- src/Views/Hotkeys.axaml | 8 +++++- src/Views/Launcher.axaml | 2 +- src/Views/Launcher.axaml.cs | 44 +++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 2f7c5c43..63c9815d 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -386,6 +386,8 @@ Go to previous page Create new page Open Preferences dialog + Open Workspaces dialog + Switch to corresponding workspace REPOSITORY Commit staged changes Commit and push staged changes diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs index d9425059..5eaca763 100644 --- a/src/ViewModels/Launcher.cs +++ b/src/ViewModels/Launcher.cs @@ -463,6 +463,14 @@ namespace SourceGit.ViewModels return menu; } + public void SwitchWorkspace(int idx) + { + var pref = Preferences.Instance; + if (idx >= pref.Workspaces.Count || pref.Workspaces[idx].IsActive) return; + + SwitchWorkspace(pref.Workspaces[idx]); + } + private string GetRepositoryGitDir(string repo) { var fullpath = Path.Combine(repo, ".git"); @@ -493,7 +501,7 @@ namespace SourceGit.ViewModels return new Commands.QueryGitDir(repo).Result(); } - + private void SwitchWorkspace(Workspace to) { foreach (var one in Pages) diff --git a/src/Views/Hotkeys.axaml b/src/Views/Hotkeys.axaml index 87242793..b1d436a4 100644 --- a/src/Views/Hotkeys.axaml +++ b/src/Views/Hotkeys.axaml @@ -45,7 +45,7 @@ FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Increase}}" Margin="0,0,0,8"/> - + @@ -69,6 +69,12 @@ + + + + + + - - + - + - + @@ -102,5 +102,22 @@
+ + + + + + + + + + + + + + +
diff --git a/src/Views/Launcher.axaml.cs b/src/Views/Launcher.axaml.cs index 24fd6dcc..02cc4f08 100644 --- a/src/Views/Launcher.axaml.cs +++ b/src/Views/Launcher.axaml.cs @@ -157,6 +157,12 @@ namespace SourceGit.Views if (e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control)) { + if (e.Key == Key.P) + { + vm.OpenWorkspaceSwitcher(); + e.Handled = true; + } + if (e.Key == Key.W) { vm.CloseTab(null); @@ -248,17 +254,10 @@ namespace SourceGit.Views } } } - else if (e.KeyModifiers.HasFlag(KeyModifiers.Alt)) - { - if (SwitchWorkspace(e.Key)) - { - e.Handled = true; - return; - } - } else if (e.Key == Key.Escape) { vm.ActivePage.CancelPopup(); + vm.CancelWorkspaceSwitcher(); e.Handled = true; return; } @@ -314,44 +313,6 @@ namespace SourceGit.Views e.Handled = true; } - - private bool SwitchWorkspace(Key eKey) - { - var exec = (ViewModels.Launcher l, int idx) => - { - var pref = ViewModels.Preferences.Instance; - if (idx < pref.Workspaces.Count) - l.SwitchWorkspace(pref.Workspaces[idx]); - return true; // Alt+1..9 (or Option+1..9) always mark handled - }; - - if (DataContext is ViewModels.Launcher launcher) - { - switch (eKey) - { - case Key.D1 or Key.NumPad1: - return exec(launcher, 0); - case Key.D2 or Key.NumPad2: - return exec(launcher, 1); - case Key.D3 or Key.NumPad3: - return exec(launcher, 2); - case Key.D4 or Key.NumPad4: - return exec(launcher, 3); - case Key.D5 or Key.NumPad5: - return exec(launcher, 4); - case Key.D6 or Key.NumPad6: - return exec(launcher, 5); - case Key.D7 or Key.NumPad7: - return exec(launcher, 6); - case Key.D8 or Key.NumPad8: - return exec(launcher, 7); - case Key.D9 or Key.NumPad9: - return exec(launcher, 8); - } - } - - return false; - } private KeyModifiers _unhandledModifiers = KeyModifiers.None; private WindowState _lastWindowState = WindowState.Normal; diff --git a/src/Views/WorkspaceSwitcher.axaml b/src/Views/WorkspaceSwitcher.axaml new file mode 100644 index 00000000..49fed451 --- /dev/null +++ b/src/Views/WorkspaceSwitcher.axaml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Views/WorkspaceSwitcher.axaml.cs b/src/Views/WorkspaceSwitcher.axaml.cs new file mode 100644 index 00000000..04bdae1a --- /dev/null +++ b/src/Views/WorkspaceSwitcher.axaml.cs @@ -0,0 +1,49 @@ +using Avalonia.Controls; +using Avalonia.Input; + +namespace SourceGit.Views +{ + public partial class WorkspaceSwitcher : UserControl + { + public WorkspaceSwitcher() + { + InitializeComponent(); + } + + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + + if (e.Key == Key.Enter && DataContext is ViewModels.WorkspaceSwitcher switcher) + { + switcher.Switch(); + e.Handled = true; + } + } + + private void OnItemDoubleTapped(object sender, TappedEventArgs e) + { + if (DataContext is ViewModels.WorkspaceSwitcher switcher) + { + switcher.Switch(); + e.Handled = true; + } + } + + private void OnSearchBoxKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Down && WorkspaceListBox.ItemCount > 0) + { + WorkspaceListBox.Focus(NavigationMethod.Directional); + + if (WorkspaceListBox.SelectedIndex < 0) + WorkspaceListBox.SelectedIndex = 0; + else if (WorkspaceListBox.SelectedIndex < WorkspaceListBox.ItemCount) + WorkspaceListBox.SelectedIndex++; + + e.Handled = true; + } + } + } +} + From d429a6426a99d441869d9727929b879dd4037717 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 17 May 2025 12:14:32 +0000 Subject: [PATCH 50/60] doc: Update translation status and sort locale files --- TRANSLATION.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 2795c890..aee0e2a0 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -6,7 +6,7 @@ This document shows the translation status of each locale file in the repository ### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen) -### ![de__DE](https://img.shields.io/badge/de__DE-98.60%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-98.48%25-yellow)
Missing keys in de_DE.axaml @@ -16,6 +16,7 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.Global.SwitchWorkspace - Text.Hotkeys.TextEditor.OpenExternalMergeTool - Text.Repository.ShowSubmodulesAsTree +- Text.Repository.WorkspaceSwitcher - Text.Submodule.Status - Text.Submodule.Status.Modified - Text.Submodule.Status.NotInited @@ -25,16 +26,17 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-99.87%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-99.75%25-yellow)
Missing keys in es_ES.axaml - Text.Hotkeys.Global.SwitchWorkspace +- Text.Repository.WorkspaceSwitcher
-### ![fr__FR](https://img.shields.io/badge/fr__FR-94.41%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-94.29%25-yellow)
Missing keys in fr_FR.axaml @@ -68,6 +70,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.ShowSubmodulesAsTree - Text.Repository.ViewLogs - Text.Repository.Visit +- Text.Repository.WorkspaceSwitcher - Text.Submodule.Status - Text.Submodule.Status.Modified - Text.Submodule.Status.NotInited @@ -86,16 +89,17 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-99.87%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-99.75%25-yellow)
Missing keys in it_IT.axaml - Text.Hotkeys.Global.SwitchWorkspace +- Text.Repository.WorkspaceSwitcher
-### ![ja__JP](https://img.shields.io/badge/ja__JP-94.16%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-94.04%25-yellow)
Missing keys in ja_JP.axaml @@ -131,6 +135,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.Tags.OrderByNameDes - Text.Repository.ViewLogs - Text.Repository.Visit +- Text.Repository.WorkspaceSwitcher - Text.Submodule.Status - Text.Submodule.Status.Modified - Text.Submodule.Status.NotInited @@ -149,7 +154,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-85.90%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-85.79%25-yellow)
Missing keys in pt_BR.axaml @@ -240,6 +245,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.UseRelativeTimeInHistories - Text.Repository.ViewLogs - Text.Repository.Visit +- Text.Repository.WorkspaceSwitcher - Text.SetUpstream - Text.SetUpstream.Local - Text.SetUpstream.Unset @@ -268,17 +274,18 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-99.75%25-yellow) +### ![ru__RU](https://img.shields.io/badge/ru__RU-99.62%25-yellow)
Missing keys in ru_RU.axaml - Text.Hotkeys.Global.SwitchWorkspace - Text.Repository.ShowSubmodulesAsTree +- Text.Repository.WorkspaceSwitcher
-### ![ta__IN](https://img.shields.io/badge/ta__IN-94.41%25-yellow) +### ![ta__IN](https://img.shields.io/badge/ta__IN-94.29%25-yellow)
Missing keys in ta_IN.axaml @@ -312,6 +319,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.ShowSubmodulesAsTree - Text.Repository.ViewLogs - Text.Repository.Visit +- Text.Repository.WorkspaceSwitcher - Text.Submodule.Status - Text.Submodule.Status.Modified - Text.Submodule.Status.NotInited @@ -330,7 +338,7 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-95.55%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-95.43%25-yellow)
Missing keys in uk_UA.axaml @@ -360,6 +368,7 @@ This document shows the translation status of each locale file in the repository - Text.Repository.ShowSubmodulesAsTree - Text.Repository.ViewLogs - Text.Repository.Visit +- Text.Repository.WorkspaceSwitcher - Text.Submodule.Status - Text.Submodule.Status.Modified - Text.Submodule.Status.NotInited From fd35e0817da331a444a83b718494b33a1b700a27 Mon Sep 17 00:00:00 2001 From: AquariusStar <48148723+AquariusStar@users.noreply.github.com> Date: Sun, 18 May 2025 10:02:30 +0300 Subject: [PATCH 51/60] localization: update russian translate (#1331) --- src/Resources/Locales/ru_RU.axaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index ca5cc384..1fabffda 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -390,6 +390,7 @@ Перейти на предыдущую вкладку Создать новую вкладку Открыть диалоговое окно настроек + Переключить активное рабочее место РЕПОЗИТОРИЙ Зафиксировать сформированные изменения Зафиксировать и выложить сформированные изменения @@ -621,6 +622,7 @@ Сообщение SHA Текущая ветка + Показывать подмодули как дерево Показывать метки как катлог ПРОПУСТИТЬ Статистикa @@ -637,6 +639,7 @@ Использовать относительное время в историях Просмотр журналов Посетить '{0}' в браузере + Переключить рабочее место РАБОЧИЕ КАТАЛОГИ ДОБАВИТЬ РАБОЧИЙ КАТАЛОГ ОБРЕЗАТЬ From 36c2e083cc087a2a0007cf44abd35df2f455fb69 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 18 May 2025 07:02:46 +0000 Subject: [PATCH 52/60] doc: Update translation status and sort locale files --- TRANSLATION.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index aee0e2a0..d810b5b2 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -274,16 +274,7 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-99.62%25-yellow) - -
-Missing keys in ru_RU.axaml - -- Text.Hotkeys.Global.SwitchWorkspace -- Text.Repository.ShowSubmodulesAsTree -- Text.Repository.WorkspaceSwitcher - -
+### ![ru__RU](https://img.shields.io/badge/ru__RU-%E2%88%9A-brightgreen) ### ![ta__IN](https://img.shields.io/badge/ta__IN-94.29%25-yellow) From 9614b995d85e93dc891e6da9b0a276d4dfc02c83 Mon Sep 17 00:00:00 2001 From: leo Date: Sun, 18 May 2025 19:36:17 +0800 Subject: [PATCH 53/60] refactor: workspace/page switcher (#1330) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- src/Resources/Locales/en_US.axaml | 4 +- src/Resources/Locales/ru_RU.axaml | 2 +- src/Resources/Locales/zh_CN.axaml | 4 +- src/Resources/Locales/zh_TW.axaml | 4 +- src/ViewModels/Launcher.cs | 25 ++-- src/ViewModels/LauncherPageSwitcher.cs | 77 +++++++++++ src/ViewModels/Repository.cs | 2 +- src/ViewModels/WorkspaceSwitcher.cs | 2 +- src/Views/Hotkeys.axaml | 11 +- src/Views/Launcher.axaml | 8 +- src/Views/Launcher.axaml.cs | 18 ++- ...ector.axaml => LauncherPageSwitcher.axaml} | 53 ++++---- src/Views/LauncherPageSwitcher.axaml.cs | 49 +++++++ src/Views/LauncherTabBar.axaml | 104 ++++++++++++++- src/Views/LauncherTabBar.axaml.cs | 111 +++++++++++++++- src/Views/LauncherTabsSelector.axaml.cs | 120 ------------------ src/Views/WorkspaceSwitcher.axaml | 4 +- 17 files changed, 418 insertions(+), 180 deletions(-) create mode 100644 src/ViewModels/LauncherPageSwitcher.cs rename src/Views/{LauncherTabsSelector.axaml => LauncherPageSwitcher.axaml} (70%) create mode 100644 src/Views/LauncherPageSwitcher.axaml.cs delete mode 100644 src/Views/LauncherTabsSelector.axaml.cs diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 4ce0a1ad..65b9d325 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -387,6 +387,7 @@ Create new page Open Preferences dialog Switch active workspace + Switch active page REPOSITORY Commit staged changes Commit and push staged changes @@ -429,6 +430,8 @@ Open in Browser ERROR NOTICE + Switch Workspace + Switch Tab Merge Branch Into: Merge Option: @@ -635,7 +638,6 @@ Use relative time in histories View Logs Visit '{0}' in Browser - Switch Workspace WORKTREES Add Worktree Prune diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index 1fabffda..a569cd97 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -433,6 +433,7 @@ Открыть в браузере ОШИБКА УВЕДОМЛЕНИЕ + Переключить рабочее место Влить ветку В: Опции слияния: @@ -639,7 +640,6 @@ Использовать относительное время в историях Просмотр журналов Посетить '{0}' в браузере - Переключить рабочее место РАБОЧИЕ КАТАЛОГИ ДОБАВИТЬ РАБОЧИЙ КАТАЛОГ ОБРЕЗАТЬ diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 1fd1a610..1344dfed 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -391,6 +391,7 @@ 新建页面 打开偏好设置面板 切换工作区 + 切换显示页面 仓库页面快捷键 提交暂存区更改 提交暂存区更改并推送 @@ -433,6 +434,8 @@ 在浏览器中访问 出错了 系统提示 + 切换工作区 + 切换页面 合并分支 目标分支 : 合并方式 : @@ -639,7 +642,6 @@ 在提交列表中使用相对时间 查看命令日志 访问远程仓库 '{0}' - 切换工作区 工作树列表 新增工作树 清理 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index eca8214c..a95f7211 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -391,6 +391,7 @@ 新增頁面 開啟偏好設定面板 切換工作區 + 切換目前頁面 存放庫頁面快速鍵 提交暫存區變更 提交暫存區變更並推送 @@ -433,6 +434,8 @@ 在瀏覽器中開啟連結 發生錯誤 系統提示 + 切換工作區 + 切換目前頁面 合併分支 目標分支: 合併方式: @@ -639,7 +642,6 @@ 在提交列表中使用相對時間 檢視 Git 指令記錄 檢視遠端存放庫 '{0}' - 切換工作區 工作區列表 新增工作區 清理 diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs index 9a54bb32..3b6a4dd8 100644 --- a/src/ViewModels/Launcher.cs +++ b/src/ViewModels/Launcher.cs @@ -23,12 +23,6 @@ namespace SourceGit.ViewModels private set; } - public WorkspaceSwitcher WorkspaceSwitcher - { - get => _workspaceSwitcher; - set => SetProperty(ref _workspaceSwitcher, value); - } - public Workspace ActiveWorkspace { get => _activeWorkspace; @@ -50,6 +44,12 @@ namespace SourceGit.ViewModels } } + public object Switcher + { + get => _switcher; + set => SetProperty(ref _switcher, value); + } + public Launcher(string startupRepo) { _ignoreIndexChange = true; @@ -138,12 +138,17 @@ namespace SourceGit.ViewModels public void OpenWorkspaceSwitcher() { - WorkspaceSwitcher = new WorkspaceSwitcher(this); + Switcher = new WorkspaceSwitcher(this); } - public void CancelWorkspaceSwitcher() + public void OpenTabSwitcher() { - WorkspaceSwitcher = null; + Switcher = new LauncherPageSwitcher(this); + } + + public void CancelSwitcher() + { + Switcher = null; } public void SwitchWorkspace(Workspace to) @@ -618,6 +623,6 @@ namespace SourceGit.ViewModels private LauncherPage _activePage = null; private bool _ignoreIndexChange = false; private string _title = string.Empty; - private WorkspaceSwitcher _workspaceSwitcher = null; + private object _switcher = null; } } diff --git a/src/ViewModels/LauncherPageSwitcher.cs b/src/ViewModels/LauncherPageSwitcher.cs new file mode 100644 index 00000000..b0dfaca3 --- /dev/null +++ b/src/ViewModels/LauncherPageSwitcher.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class LauncherPageSwitcher : ObservableObject + { + public List VisiblePages + { + get => _visiblePages; + private set => SetProperty(ref _visiblePages, value); + } + + public string SearchFilter + { + get => _searchFilter; + set + { + if (SetProperty(ref _searchFilter, value)) + UpdateVisiblePages(); + } + } + + public LauncherPage SelectedPage + { + get => _selectedPage; + set => SetProperty(ref _selectedPage, value); + } + + public LauncherPageSwitcher(Launcher launcher) + { + _launcher = launcher; + UpdateVisiblePages(); + } + + public void ClearFilter() + { + SearchFilter = string.Empty; + } + + public void Switch() + { + if (_selectedPage is { }) + _launcher.ActivePage = _selectedPage; + + _launcher.CancelSwitcher(); + } + + private void UpdateVisiblePages() + { + var visible = new List(); + if (string.IsNullOrEmpty(_searchFilter)) + { + visible.AddRange(_launcher.Pages); + } + else + { + foreach (var page in _launcher.Pages) + { + if (page.Node.Name.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase) || + (page.Node.IsRepository && page.Node.Id.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase))) + { + visible.Add(page); + } + } + } + + VisiblePages = visible; + } + + private Launcher _launcher = null; + private List _visiblePages = []; + private string _searchFilter = string.Empty; + private LauncherPage _selectedPage = null; + } +} diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index d24f6fbf..a3f63251 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -2632,7 +2632,7 @@ namespace SourceGit.ViewModels if (node.Path.Equals(path, StringComparison.Ordinal)) return node; - if (path!.StartsWith(node.Path, StringComparison.Ordinal)) + if (path.StartsWith(node.Path, StringComparison.Ordinal)) { var founded = FindBranchNode(node.Children, path); if (founded != null) diff --git a/src/ViewModels/WorkspaceSwitcher.cs b/src/ViewModels/WorkspaceSwitcher.cs index 01d62744..41f47631 100644 --- a/src/ViewModels/WorkspaceSwitcher.cs +++ b/src/ViewModels/WorkspaceSwitcher.cs @@ -44,7 +44,7 @@ namespace SourceGit.ViewModels if (_selectedWorkspace is { }) _launcher.SwitchWorkspace(_selectedWorkspace); - _launcher.CancelWorkspaceSwitcher(); + _launcher.CancelSwitcher(); } private void UpdateVisibleWorkspaces() diff --git a/src/Views/Hotkeys.axaml b/src/Views/Hotkeys.axaml index 5d9a6f9f..5275f264 100644 --- a/src/Views/Hotkeys.axaml +++ b/src/Views/Hotkeys.axaml @@ -45,8 +45,8 @@ FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Increase}}" Margin="0,0,0,8"/> - - + + @@ -55,7 +55,7 @@ - + @@ -70,8 +70,11 @@ - + + + + + IsVisible="{Binding Switcher, Converter={x:Static ObjectConverters.IsNotNull}}"> - + + + + + diff --git a/src/Views/Launcher.axaml.cs b/src/Views/Launcher.axaml.cs index 02cc4f08..abcbaba9 100644 --- a/src/Views/Launcher.axaml.cs +++ b/src/Views/Launcher.axaml.cs @@ -133,8 +133,8 @@ namespace SourceGit.Views return; } - // Ctrl+Shift+P opens preference dialog (macOS use hotkeys in system menu bar) - if (!OperatingSystem.IsMacOS() && e is { KeyModifiers: (KeyModifiers.Control | KeyModifiers.Shift), Key: Key.P }) + // Ctrl+, opens preference dialog (macOS use hotkeys in system menu bar) + if (!OperatingSystem.IsMacOS() && e is { KeyModifiers: KeyModifiers.Control, Key: Key.OemComma }) { App.ShowWindow(new Preferences(), true); e.Handled = true; @@ -149,7 +149,7 @@ namespace SourceGit.Views } // Ctrl+Q quits the application (macOS use hotkeys in system menu bar) - if (!OperatingSystem.IsMacOS() && e.KeyModifiers == KeyModifiers.Control && e.Key == Key.Q) + if (!OperatingSystem.IsMacOS() && e is { KeyModifiers: KeyModifiers.Control, Key: Key.Q }) { App.Quit(0); return; @@ -157,10 +157,18 @@ namespace SourceGit.Views if (e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control)) { - if (e.Key == Key.P) + if (e.KeyModifiers.HasFlag(KeyModifiers.Shift) && e.Key == Key.P) { vm.OpenWorkspaceSwitcher(); e.Handled = true; + return; + } + + if (e.Key == Key.P) + { + vm.OpenTabSwitcher(); + e.Handled = true; + return; } if (e.Key == Key.W) @@ -257,7 +265,7 @@ namespace SourceGit.Views else if (e.Key == Key.Escape) { vm.ActivePage.CancelPopup(); - vm.CancelWorkspaceSwitcher(); + vm.CancelSwitcher(); e.Handled = true; return; } diff --git a/src/Views/LauncherTabsSelector.axaml b/src/Views/LauncherPageSwitcher.axaml similarity index 70% rename from src/Views/LauncherTabsSelector.axaml rename to src/Views/LauncherPageSwitcher.axaml index 109a2ce7..09f42038 100644 --- a/src/Views/LauncherTabsSelector.axaml +++ b/src/Views/LauncherPageSwitcher.axaml @@ -3,19 +3,27 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="using:SourceGit.ViewModels" + xmlns:v="using:SourceGit.Views" xmlns:c="using:SourceGit.Converters" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="SourceGit.Views.LauncherTabsSelector" - x:Name="ThisControl"> - - + + + + + VerticalContentAlignment="Center" + v:AutoFocusBehaviour.IsEnabled="True"> - + ItemsSource="{Binding VisiblePages, Mode=OneWay}" + SelectedItem="{Binding SelectedPage, Mode=TwoWay}"> @@ -72,30 +83,28 @@ - + - - diff --git a/src/Views/LauncherPageSwitcher.axaml.cs b/src/Views/LauncherPageSwitcher.axaml.cs new file mode 100644 index 00000000..277eb549 --- /dev/null +++ b/src/Views/LauncherPageSwitcher.axaml.cs @@ -0,0 +1,49 @@ +using Avalonia.Controls; +using Avalonia.Input; + +namespace SourceGit.Views +{ + public partial class LauncherPageSwitcher : UserControl + { + public LauncherPageSwitcher() + { + InitializeComponent(); + } + + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + + if (e.Key == Key.Enter && DataContext is ViewModels.LauncherPageSwitcher switcher) + { + switcher.Switch(); + e.Handled = true; + } + } + + private void OnItemDoubleTapped(object sender, TappedEventArgs e) + { + if (DataContext is ViewModels.LauncherPageSwitcher switcher) + { + switcher.Switch(); + e.Handled = true; + } + } + + private void OnSearchBoxKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Down && PagesListBox.ItemCount > 0) + { + PagesListBox.Focus(NavigationMethod.Directional); + + if (PagesListBox.SelectedIndex < 0) + PagesListBox.SelectedIndex = 0; + else if (PagesListBox.SelectedIndex < PagesListBox.ItemCount) + PagesListBox.SelectedIndex++; + + e.Handled = true; + } + } + } +} + diff --git a/src/Views/LauncherTabBar.axaml b/src/Views/LauncherTabBar.axaml index 0376e259..f770a5d9 100644 --- a/src/Views/LauncherTabBar.axaml +++ b/src/Views/LauncherTabBar.axaml @@ -40,7 +40,7 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Views/LauncherTabBar.axaml.cs b/src/Views/LauncherTabBar.axaml.cs index 12bca91f..b75d93d6 100644 --- a/src/Views/LauncherTabBar.axaml.cs +++ b/src/Views/LauncherTabBar.axaml.cs @@ -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 SearchFilterProperty = + AvaloniaProperty.Register(nameof(SearchFilter)); + + public string SearchFilter + { + get => GetValue(SearchFilterProperty); + set => SetValue(SearchFilterProperty, value); + } + + public AvaloniaList 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; diff --git a/src/Views/LauncherTabsSelector.axaml.cs b/src/Views/LauncherTabsSelector.axaml.cs deleted file mode 100644 index 61d7a966..00000000 --- a/src/Views/LauncherTabsSelector.axaml.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; - -using Avalonia; -using Avalonia.Collections; -using Avalonia.Controls; -using Avalonia.Interactivity; - -namespace SourceGit.Views -{ - public class LauncherTabSelectedEventArgs : RoutedEventArgs - { - public ViewModels.LauncherPage Page { get; } - - public LauncherTabSelectedEventArgs(ViewModels.LauncherPage page) - { - RoutedEvent = LauncherTabsSelector.PageSelectedEvent; - Page = page; - } - } - - public partial class LauncherTabsSelector : UserControl - { - public static readonly StyledProperty> PagesProperty = - AvaloniaProperty.Register>(nameof(Pages)); - - public AvaloniaList Pages - { - get => GetValue(PagesProperty); - set => SetValue(PagesProperty, value); - } - - public static readonly StyledProperty SearchFilterProperty = - AvaloniaProperty.Register(nameof(SearchFilter)); - - public string SearchFilter - { - get => GetValue(SearchFilterProperty); - set => SetValue(SearchFilterProperty, value); - } - - public static readonly RoutedEvent PageSelectedEvent = - RoutedEvent.Register(nameof(PageSelected), RoutingStrategies.Tunnel | RoutingStrategies.Bubble); - - public event EventHandler PageSelected - { - add { AddHandler(PageSelectedEvent, value); } - remove { RemoveHandler(PageSelectedEvent, value); } - } - - public AvaloniaList VisiblePages - { - get; - private set; - } - - public LauncherTabsSelector() - { - VisiblePages = new AvaloniaList(); - InitializeComponent(); - } - - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) - { - base.OnPropertyChanged(change); - - if (change.Property == PagesProperty || change.Property == SearchFilterProperty) - UpdateVisiblePages(); - } - - private void OnClearSearchFilter(object sender, RoutedEventArgs e) - { - SearchFilter = string.Empty; - } - - private void OnPageSelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (sender is ListBox { SelectedItem: ViewModels.LauncherPage page }) - { - _isProcessingSelection = true; - RaiseEvent(new LauncherTabSelectedEventArgs(page)); - _isProcessingSelection = false; - } - - e.Handled = true; - } - - private void UpdateVisiblePages() - { - if (_isProcessingSelection) - return; - - VisiblePages.Clear(); - - if (Pages == null) - return; - - var filter = SearchFilter?.Trim() ?? ""; - if (string.IsNullOrEmpty(filter)) - { - foreach (var p in Pages) - VisiblePages.Add(p); - - return; - } - - foreach (var page in Pages) - { - if (!page.Node.IsRepository) - continue; - - if (page.Node.Name.Contains(filter, StringComparison.OrdinalIgnoreCase) || - page.Node.Id.Contains(filter, StringComparison.OrdinalIgnoreCase)) - VisiblePages.Add(page); - } - } - - private bool _isProcessingSelection = false; - } -} - diff --git a/src/Views/WorkspaceSwitcher.axaml b/src/Views/WorkspaceSwitcher.axaml index 49fed451..aa621b73 100644 --- a/src/Views/WorkspaceSwitcher.axaml +++ b/src/Views/WorkspaceSwitcher.axaml @@ -9,7 +9,7 @@ x:DataType="vm:WorkspaceSwitcher"> @@ -82,7 +82,7 @@ - + Date: Sun, 18 May 2025 11:36:39 +0000 Subject: [PATCH 54/60] doc: Update translation status and sort locale files --- TRANSLATION.md | 58 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index d810b5b2..26e21624 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -6,7 +6,7 @@ This document shows the translation status of each locale file in the repository ### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen) -### ![de__DE](https://img.shields.io/badge/de__DE-98.48%25-yellow) +### ![de__DE](https://img.shields.io/badge/de__DE-98.23%25-yellow)
Missing keys in de_DE.axaml @@ -14,9 +14,11 @@ This document shows the translation status of each locale file in the repository - Text.GitFlow.FinishWithPush - Text.GitFlow.FinishWithSquash - Text.Hotkeys.Global.SwitchWorkspace +- Text.Hotkeys.Global.SwitchTab - Text.Hotkeys.TextEditor.OpenExternalMergeTool +- Text.Launcher.SwitchWorkspace +- Text.Launcher.SwitchTab - Text.Repository.ShowSubmodulesAsTree -- Text.Repository.WorkspaceSwitcher - Text.Submodule.Status - Text.Submodule.Status.Modified - Text.Submodule.Status.NotInited @@ -26,17 +28,19 @@ This document shows the translation status of each locale file in the repository
-### ![es__ES](https://img.shields.io/badge/es__ES-99.75%25-yellow) +### ![es__ES](https://img.shields.io/badge/es__ES-99.49%25-yellow)
Missing keys in es_ES.axaml - Text.Hotkeys.Global.SwitchWorkspace -- Text.Repository.WorkspaceSwitcher +- Text.Hotkeys.Global.SwitchTab +- Text.Launcher.SwitchWorkspace +- Text.Launcher.SwitchTab
-### ![fr__FR](https://img.shields.io/badge/fr__FR-94.29%25-yellow) +### ![fr__FR](https://img.shields.io/badge/fr__FR-94.05%25-yellow)
Missing keys in fr_FR.axaml @@ -61,7 +65,10 @@ This document shows the translation status of each locale file in the repository - Text.GitFlow.FinishWithPush - Text.GitFlow.FinishWithSquash - Text.Hotkeys.Global.SwitchWorkspace +- Text.Hotkeys.Global.SwitchTab - Text.Hotkeys.TextEditor.OpenExternalMergeTool +- Text.Launcher.SwitchWorkspace +- Text.Launcher.SwitchTab - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.BranchSort - Text.Repository.BranchSort.ByCommitterDate @@ -70,7 +77,6 @@ This document shows the translation status of each locale file in the repository - Text.Repository.ShowSubmodulesAsTree - Text.Repository.ViewLogs - Text.Repository.Visit -- Text.Repository.WorkspaceSwitcher - Text.Submodule.Status - Text.Submodule.Status.Modified - Text.Submodule.Status.NotInited @@ -89,17 +95,19 @@ This document shows the translation status of each locale file in the repository
-### ![it__IT](https://img.shields.io/badge/it__IT-99.75%25-yellow) +### ![it__IT](https://img.shields.io/badge/it__IT-99.49%25-yellow)
Missing keys in it_IT.axaml - Text.Hotkeys.Global.SwitchWorkspace -- Text.Repository.WorkspaceSwitcher +- Text.Hotkeys.Global.SwitchTab +- Text.Launcher.SwitchWorkspace +- Text.Launcher.SwitchTab
-### ![ja__JP](https://img.shields.io/badge/ja__JP-94.04%25-yellow) +### ![ja__JP](https://img.shields.io/badge/ja__JP-93.80%25-yellow)
Missing keys in ja_JP.axaml @@ -124,7 +132,10 @@ This document shows the translation status of each locale file in the repository - Text.GitFlow.FinishWithPush - Text.GitFlow.FinishWithSquash - Text.Hotkeys.Global.SwitchWorkspace +- Text.Hotkeys.Global.SwitchTab - Text.Hotkeys.TextEditor.OpenExternalMergeTool +- Text.Launcher.SwitchWorkspace +- Text.Launcher.SwitchTab - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.BranchSort - Text.Repository.BranchSort.ByCommitterDate @@ -135,7 +146,6 @@ This document shows the translation status of each locale file in the repository - Text.Repository.Tags.OrderByNameDes - Text.Repository.ViewLogs - Text.Repository.Visit -- Text.Repository.WorkspaceSwitcher - Text.Submodule.Status - Text.Submodule.Status.Modified - Text.Submodule.Status.NotInited @@ -154,7 +164,7 @@ This document shows the translation status of each locale file in the repository
-### ![pt__BR](https://img.shields.io/badge/pt__BR-85.79%25-yellow) +### ![pt__BR](https://img.shields.io/badge/pt__BR-85.57%25-yellow)
Missing keys in pt_BR.axaml @@ -208,11 +218,14 @@ This document shows the translation status of each locale file in the repository - Text.GitFlow.FinishWithSquash - Text.Hotkeys.Global.Clone - Text.Hotkeys.Global.SwitchWorkspace +- Text.Hotkeys.Global.SwitchTab - Text.Hotkeys.TextEditor.OpenExternalMergeTool - Text.InProgress.CherryPick.Head - Text.InProgress.Merge.Operating - Text.InProgress.Rebase.StoppedAt - Text.InProgress.Revert.Head +- Text.Launcher.SwitchWorkspace +- Text.Launcher.SwitchTab - Text.Merge.Source - Text.MergeMultiple - Text.MergeMultiple.CommitChanges @@ -245,7 +258,6 @@ This document shows the translation status of each locale file in the repository - Text.Repository.UseRelativeTimeInHistories - Text.Repository.ViewLogs - Text.Repository.Visit -- Text.Repository.WorkspaceSwitcher - Text.SetUpstream - Text.SetUpstream.Local - Text.SetUpstream.Unset @@ -274,9 +286,17 @@ This document shows the translation status of each locale file in the repository
-### ![ru__RU](https://img.shields.io/badge/ru__RU-%E2%88%9A-brightgreen) +### ![ru__RU](https://img.shields.io/badge/ru__RU-99.75%25-yellow) -### ![ta__IN](https://img.shields.io/badge/ta__IN-94.29%25-yellow) +
+Missing keys in ru_RU.axaml + +- Text.Hotkeys.Global.SwitchTab +- Text.Launcher.SwitchTab + +
+ +### ![ta__IN](https://img.shields.io/badge/ta__IN-94.05%25-yellow)
Missing keys in ta_IN.axaml @@ -301,7 +321,10 @@ This document shows the translation status of each locale file in the repository - Text.GitFlow.FinishWithPush - Text.GitFlow.FinishWithSquash - Text.Hotkeys.Global.SwitchWorkspace +- Text.Hotkeys.Global.SwitchTab - Text.Hotkeys.TextEditor.OpenExternalMergeTool +- Text.Launcher.SwitchWorkspace +- Text.Launcher.SwitchTab - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.BranchSort - Text.Repository.BranchSort.ByCommitterDate @@ -310,7 +333,6 @@ This document shows the translation status of each locale file in the repository - Text.Repository.ShowSubmodulesAsTree - Text.Repository.ViewLogs - Text.Repository.Visit -- Text.Repository.WorkspaceSwitcher - Text.Submodule.Status - Text.Submodule.Status.Modified - Text.Submodule.Status.NotInited @@ -329,7 +351,7 @@ This document shows the translation status of each locale file in the repository
-### ![uk__UA](https://img.shields.io/badge/uk__UA-95.43%25-yellow) +### ![uk__UA](https://img.shields.io/badge/uk__UA-95.19%25-yellow)
Missing keys in uk_UA.axaml @@ -350,7 +372,10 @@ This document shows the translation status of each locale file in the repository - Text.GitFlow.FinishWithPush - Text.GitFlow.FinishWithSquash - Text.Hotkeys.Global.SwitchWorkspace +- Text.Hotkeys.Global.SwitchTab - Text.Hotkeys.TextEditor.OpenExternalMergeTool +- Text.Launcher.SwitchWorkspace +- Text.Launcher.SwitchTab - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.BranchSort - Text.Repository.BranchSort.ByCommitterDate @@ -359,7 +384,6 @@ This document shows the translation status of each locale file in the repository - Text.Repository.ShowSubmodulesAsTree - Text.Repository.ViewLogs - Text.Repository.Visit -- Text.Repository.WorkspaceSwitcher - Text.Submodule.Status - Text.Submodule.Status.Modified - Text.Submodule.Status.NotInited From 4b849d9d5ccdab6d97ce0671cc4d29e63c45d3cf Mon Sep 17 00:00:00 2001 From: leo Date: Sun, 18 May 2025 20:33:55 +0800 Subject: [PATCH 55/60] ux: update workspace/page switcher popup layout Signed-off-by: leo --- src/Resources/Locales/en_US.axaml | 4 ++-- src/Resources/Locales/ru_RU.axaml | 2 +- src/Resources/Locales/zh_CN.axaml | 4 ++-- src/Resources/Locales/zh_TW.axaml | 4 ++-- src/Views/Launcher.axaml | 4 ++-- src/Views/LauncherPageSwitcher.axaml | 10 +++++----- src/Views/WorkspaceSwitcher.axaml | 10 +++++----- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index 65b9d325..bb259272 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -430,8 +430,8 @@ Open in Browser ERROR NOTICE - Switch Workspace - Switch Tab + Workspaces + Pages Merge Branch Into: Merge Option: diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml index a569cd97..77a7ba4f 100644 --- a/src/Resources/Locales/ru_RU.axaml +++ b/src/Resources/Locales/ru_RU.axaml @@ -433,7 +433,7 @@ Открыть в браузере ОШИБКА УВЕДОМЛЕНИЕ - Переключить рабочее место + Рабочие места Влить ветку В: Опции слияния: diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index 1344dfed..18569a14 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -434,8 +434,8 @@ 在浏览器中访问 出错了 系统提示 - 切换工作区 - 切换页面 + 工作区列表 + 页面列表 合并分支 目标分支 : 合并方式 : diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index a95f7211..ded99a14 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -434,8 +434,8 @@ 在瀏覽器中開啟連結 發生錯誤 系統提示 - 切換工作區 - 切換目前頁面 + 工作區列表 + 頁面列表 合併分支 目標分支: 合併方式: diff --git a/src/Views/Launcher.axaml b/src/Views/Launcher.axaml index c9565452..18e307fe 100644 --- a/src/Views/Launcher.axaml +++ b/src/Views/Launcher.axaml @@ -103,13 +103,13 @@ - + - + diff --git a/src/Views/LauncherPageSwitcher.axaml b/src/Views/LauncherPageSwitcher.axaml index 09f42038..4d785b55 100644 --- a/src/Views/LauncherPageSwitcher.axaml +++ b/src/Views/LauncherPageSwitcher.axaml @@ -8,15 +8,15 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="SourceGit.Views.LauncherPageSwitcher" x:DataType="vm:LauncherPageSwitcher"> - + + HorizontalAlignment="Center"/> - + + HorizontalAlignment="Center"/> Date: Sun, 18 May 2025 12:34:17 +0000 Subject: [PATCH 56/60] doc: Update translation status and sort locale files --- TRANSLATION.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/TRANSLATION.md b/TRANSLATION.md index 26e21624..1a9d00d1 100644 --- a/TRANSLATION.md +++ b/TRANSLATION.md @@ -16,8 +16,8 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.Global.SwitchWorkspace - Text.Hotkeys.Global.SwitchTab - Text.Hotkeys.TextEditor.OpenExternalMergeTool -- Text.Launcher.SwitchWorkspace -- Text.Launcher.SwitchTab +- Text.Launcher.Workspaces +- Text.Launcher.Pages - Text.Repository.ShowSubmodulesAsTree - Text.Submodule.Status - Text.Submodule.Status.Modified @@ -35,8 +35,8 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.Global.SwitchWorkspace - Text.Hotkeys.Global.SwitchTab -- Text.Launcher.SwitchWorkspace -- Text.Launcher.SwitchTab +- Text.Launcher.Workspaces +- Text.Launcher.Pages
@@ -67,8 +67,8 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.Global.SwitchWorkspace - Text.Hotkeys.Global.SwitchTab - Text.Hotkeys.TextEditor.OpenExternalMergeTool -- Text.Launcher.SwitchWorkspace -- Text.Launcher.SwitchTab +- Text.Launcher.Workspaces +- Text.Launcher.Pages - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.BranchSort - Text.Repository.BranchSort.ByCommitterDate @@ -102,8 +102,8 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.Global.SwitchWorkspace - Text.Hotkeys.Global.SwitchTab -- Text.Launcher.SwitchWorkspace -- Text.Launcher.SwitchTab +- Text.Launcher.Workspaces +- Text.Launcher.Pages @@ -134,8 +134,8 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.Global.SwitchWorkspace - Text.Hotkeys.Global.SwitchTab - Text.Hotkeys.TextEditor.OpenExternalMergeTool -- Text.Launcher.SwitchWorkspace -- Text.Launcher.SwitchTab +- Text.Launcher.Workspaces +- Text.Launcher.Pages - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.BranchSort - Text.Repository.BranchSort.ByCommitterDate @@ -224,8 +224,8 @@ This document shows the translation status of each locale file in the repository - Text.InProgress.Merge.Operating - Text.InProgress.Rebase.StoppedAt - Text.InProgress.Revert.Head -- Text.Launcher.SwitchWorkspace -- Text.Launcher.SwitchTab +- Text.Launcher.Workspaces +- Text.Launcher.Pages - Text.Merge.Source - Text.MergeMultiple - Text.MergeMultiple.CommitChanges @@ -292,7 +292,7 @@ This document shows the translation status of each locale file in the repository Missing keys in ru_RU.axaml - Text.Hotkeys.Global.SwitchTab -- Text.Launcher.SwitchTab +- Text.Launcher.Pages @@ -323,8 +323,8 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.Global.SwitchWorkspace - Text.Hotkeys.Global.SwitchTab - Text.Hotkeys.TextEditor.OpenExternalMergeTool -- Text.Launcher.SwitchWorkspace -- Text.Launcher.SwitchTab +- Text.Launcher.Workspaces +- Text.Launcher.Pages - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.BranchSort - Text.Repository.BranchSort.ByCommitterDate @@ -374,8 +374,8 @@ This document shows the translation status of each locale file in the repository - Text.Hotkeys.Global.SwitchWorkspace - Text.Hotkeys.Global.SwitchTab - Text.Hotkeys.TextEditor.OpenExternalMergeTool -- Text.Launcher.SwitchWorkspace -- Text.Launcher.SwitchTab +- Text.Launcher.Workspaces +- Text.Launcher.Pages - Text.Preferences.Git.IgnoreCRAtEOLInDiff - Text.Repository.BranchSort - Text.Repository.BranchSort.ByCommitterDate From 5e85f6fefed553c71fb4ddb9b2dacd333f93aab6 Mon Sep 17 00:00:00 2001 From: leo Date: Sun, 18 May 2025 20:47:04 +0800 Subject: [PATCH 57/60] enhance: auto-select the first page by default Signed-off-by: leo --- src/ViewModels/LauncherPageSwitcher.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ViewModels/LauncherPageSwitcher.cs b/src/ViewModels/LauncherPageSwitcher.cs index b0dfaca3..a73a216f 100644 --- a/src/ViewModels/LauncherPageSwitcher.cs +++ b/src/ViewModels/LauncherPageSwitcher.cs @@ -67,6 +67,7 @@ namespace SourceGit.ViewModels } VisiblePages = visible; + SelectedPage = visible.Count > 0 ? visible[0] : null; } private Launcher _launcher = null; From b78f6b0ea8da7aa857aa27326f683d7995ebcf7a Mon Sep 17 00:00:00 2001 From: qiufengshe <172344058@qq.com> Date: Sun, 18 May 2025 20:52:05 +0800 Subject: [PATCH 58/60] perf: minimize temporary strings for better performance (#1332) --- src/ViewModels/Histories.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ViewModels/Histories.cs b/src/ViewModels/Histories.cs index 555954d9..f21d2636 100644 --- a/src/ViewModels/Histories.cs +++ b/src/ViewModels/Histories.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.IO; @@ -387,7 +387,7 @@ namespace SourceGit.ViewModels { var builder = new StringBuilder(); foreach (var c in selected) - builder.AppendLine($"{c.SHA.Substring(0, 10)} - {c.Subject}"); + builder.AppendLine($"{c.SHA.AsSpan(0, 10)} - {c.Subject}"); App.CopyText(builder.ToString()); e.Handled = true; @@ -780,7 +780,7 @@ namespace SourceGit.ViewModels copyInfo.Icon = App.CreateMenuIcon("Icons.Info"); copyInfo.Click += (_, e) => { - App.CopyText($"{commit.SHA.Substring(0, 10)} - {commit.Subject}"); + App.CopyText($"{commit.SHA.AsSpan(0, 10)} - {commit.Subject}"); e.Handled = true; }; From aff003fd6dab3e181cddcf53d2a61c823c2d41bb Mon Sep 17 00:00:00 2001 From: leo Date: Sun, 18 May 2025 22:00:35 +0800 Subject: [PATCH 59/60] enhance: cleanup unused resources Signed-off-by: leo --- src/ViewModels/Launcher.cs | 9 +++++---- src/ViewModels/LauncherPageSwitcher.cs | 19 ++++++++++++------- src/ViewModels/WorkspaceSwitcher.cs | 13 +++++++++---- src/Views/Launcher.axaml | 5 +++-- src/Views/Launcher.axaml.cs | 7 +++++++ src/Views/LauncherPageSwitcher.axaml.cs | 2 +- src/Views/LauncherTabBar.axaml | 2 +- src/Views/LauncherTabBar.axaml.cs | 20 +++++++++++++------- 8 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs index 3b6a4dd8..4c0714df 100644 --- a/src/ViewModels/Launcher.cs +++ b/src/ViewModels/Launcher.cs @@ -44,10 +44,10 @@ namespace SourceGit.ViewModels } } - public object Switcher + public IDisposable Switcher { get => _switcher; - set => SetProperty(ref _switcher, value); + private set => SetProperty(ref _switcher, value); } public Launcher(string startupRepo) @@ -148,12 +148,13 @@ namespace SourceGit.ViewModels public void CancelSwitcher() { + Switcher?.Dispose(); Switcher = null; } public void SwitchWorkspace(Workspace to) { - if (to.IsActive) + if (to == null || to.IsActive) return; foreach (var one in Pages) @@ -623,6 +624,6 @@ namespace SourceGit.ViewModels private LauncherPage _activePage = null; private bool _ignoreIndexChange = false; private string _title = string.Empty; - private object _switcher = null; + private IDisposable _switcher = null; } } diff --git a/src/ViewModels/LauncherPageSwitcher.cs b/src/ViewModels/LauncherPageSwitcher.cs index a73a216f..5f53021d 100644 --- a/src/ViewModels/LauncherPageSwitcher.cs +++ b/src/ViewModels/LauncherPageSwitcher.cs @@ -4,14 +4,14 @@ using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.ViewModels { - public class LauncherPageSwitcher : ObservableObject + public class LauncherPageSwitcher : ObservableObject, IDisposable { public List VisiblePages { get => _visiblePages; private set => SetProperty(ref _visiblePages, value); } - + public string SearchFilter { get => _searchFilter; @@ -27,13 +27,13 @@ namespace SourceGit.ViewModels get => _selectedPage; set => SetProperty(ref _selectedPage, value); } - + public LauncherPageSwitcher(Launcher launcher) { _launcher = launcher; UpdateVisiblePages(); } - + public void ClearFilter() { SearchFilter = string.Empty; @@ -41,12 +41,17 @@ namespace SourceGit.ViewModels public void Switch() { - if (_selectedPage is { }) - _launcher.ActivePage = _selectedPage; - + _launcher.ActivePage = _selectedPage ?? _launcher.ActivePage; _launcher.CancelSwitcher(); } + public void Dispose() + { + _visiblePages.Clear(); + _selectedPage = null; + _searchFilter = string.Empty; + } + private void UpdateVisiblePages() { var visible = new List(); diff --git a/src/ViewModels/WorkspaceSwitcher.cs b/src/ViewModels/WorkspaceSwitcher.cs index 41f47631..7a2da9be 100644 --- a/src/ViewModels/WorkspaceSwitcher.cs +++ b/src/ViewModels/WorkspaceSwitcher.cs @@ -4,7 +4,7 @@ using CommunityToolkit.Mvvm.ComponentModel; namespace SourceGit.ViewModels { - public class WorkspaceSwitcher : ObservableObject + public class WorkspaceSwitcher : ObservableObject, IDisposable { public List VisibleWorkspaces { @@ -41,12 +41,17 @@ namespace SourceGit.ViewModels public void Switch() { - if (_selectedWorkspace is { }) - _launcher.SwitchWorkspace(_selectedWorkspace); - + _launcher.SwitchWorkspace(_selectedWorkspace); _launcher.CancelSwitcher(); } + public void Dispose() + { + _visibleWorkspaces.Clear(); + _selectedWorkspace = null; + _searchFilter = string.Empty; + } + private void UpdateVisibleWorkspaces() { var visible = new List(); diff --git a/src/Views/Launcher.axaml b/src/Views/Launcher.axaml index 18e307fe..bd115fef 100644 --- a/src/Views/Launcher.axaml +++ b/src/Views/Launcher.axaml @@ -104,9 +104,10 @@ - + IsVisible="{Binding Switcher, Converter={x:Static ObjectConverters.IsNotNull}}" + PointerPressed="OnCancelSwitcher"> diff --git a/src/Views/Launcher.axaml.cs b/src/Views/Launcher.axaml.cs index abcbaba9..be4cdf5b 100644 --- a/src/Views/Launcher.axaml.cs +++ b/src/Views/Launcher.axaml.cs @@ -322,6 +322,13 @@ namespace SourceGit.Views e.Handled = true; } + private void OnCancelSwitcher(object sender, PointerPressedEventArgs e) + { + if (e.Source == sender) + (DataContext as ViewModels.Launcher)?.CancelSwitcher(); + e.Handled = true; + } + private KeyModifiers _unhandledModifiers = KeyModifiers.None; private WindowState _lastWindowState = WindowState.Normal; } diff --git a/src/Views/LauncherPageSwitcher.axaml.cs b/src/Views/LauncherPageSwitcher.axaml.cs index 277eb549..1effb93c 100644 --- a/src/Views/LauncherPageSwitcher.axaml.cs +++ b/src/Views/LauncherPageSwitcher.axaml.cs @@ -9,7 +9,7 @@ namespace SourceGit.Views { InitializeComponent(); } - + protected override void OnKeyDown(KeyEventArgs e) { base.OnKeyDown(e); diff --git a/src/Views/LauncherTabBar.axaml b/src/Views/LauncherTabBar.axaml index f770a5d9..a56da2b0 100644 --- a/src/Views/LauncherTabBar.axaml +++ b/src/Views/LauncherTabBar.axaml @@ -141,7 +141,7 @@