diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs b/src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs index d8fc511b5..fc6b5f2ae 100644 --- a/src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs +++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs @@ -79,8 +79,9 @@ or nameof(PackagesPageViewModel.SortAscending)) // Double-click a list row → show details PackageList.DoubleTapped += (_, _) => _ = ShowDetailsForPackage(SelectedItem); - // Keyboard shortcuts on the package list - PackageList.KeyDown += PackageList_KeyDown; + // Keyboard shortcuts on the package list. Handled on the tunnel route (and even when + // already handled) because the DataGrid swallows Enter on the bubble route otherwise. + PackageList.AddHandler(KeyDownEvent, PackageList_KeyDown, RoutingStrategies.Tunnel, handledEventsToo: true); // Type-to-search: printable characters typed while the list is focused // redirect focus + the typed character to the global search box. @@ -289,6 +290,34 @@ private void MegaQueryBlock_KeyDown(object? sender, KeyEventArgs e) ViewModel.SubmitSearch(); } + // Accelerator hints shown in package context menus; handling lives in PackageList_KeyDown below. + // Rendered manually (not via MenuItem.InputGesture) because Avalonia's Key enum aliases + // Enter→Return and would display "Return" instead of WinUI's "Enter". + protected const string MainActionShortcut = "Ctrl+Enter"; + protected const string OptionsShortcut = "Alt+Enter"; + protected const string DetailsShortcut = "Enter"; + + /// Builds a menu header with the label on the left and a dimmed, right-aligned shortcut hint. + protected static Control ShortcutHeader(string label, string shortcut) + { + var grid = new Grid + { + ColumnDefinitions = new ColumnDefinitions("*,Auto"), + HorizontalAlignment = HorizontalAlignment.Stretch, + }; + grid.Children.Add(new TextBlock { Text = label, VerticalAlignment = VerticalAlignment.Center }); + var hint = new TextBlock + { + Text = shortcut, + Opacity = 0.6, + Margin = new Thickness(24, 0, 0, 0), + VerticalAlignment = VerticalAlignment.Center, + }; + Grid.SetColumn(hint, 1); + grid.Children.Add(hint); + return grid; + } + private void PackageList_KeyDown(object? sender, KeyEventArgs e) { var pkg = SelectedItem; diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/DiscoverSoftwarePage.cs b/src/UniGetUI.Avalonia/Views/SoftwarePages/DiscoverSoftwarePage.cs index 538d8f2c3..507e2b22c 100644 --- a/src/UniGetUI.Avalonia/Views/SoftwarePages/DiscoverSoftwarePage.cs +++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/DiscoverSoftwarePage.cs @@ -113,13 +113,13 @@ protected override void GenerateToolBar(PackagesPageViewModel vm) _menuDownloadInstaller.Click += (_, _) => _ = AvaloniaPackageOperationHelper.AskLocationAndDownloadAsync( SelectedItem, TEL_InstallReferral.DIRECT_SEARCH); - var menuInstall = new MenuItem { Header = CoreTools.Translate("Install"), Icon = LoadMenuIcon("download") }; + var menuInstall = new MenuItem { Header = ShortcutHeader(CoreTools.Translate("Install"), MainActionShortcut), Icon = LoadMenuIcon("download") }; menuInstall.Click += (_, _) => _ = LaunchInstall([SelectedItem!]); - var menuInstallOptions = new MenuItem { Header = CoreTools.Translate("Install options"), Icon = LoadMenuIcon("options") }; + var menuInstallOptions = new MenuItem { Header = ShortcutHeader(CoreTools.Translate("Install options"), OptionsShortcut), Icon = LoadMenuIcon("options") }; menuInstallOptions.Click += (_, _) => _ = ShowInstallationOptionsForPackage(SelectedItem); - var menuDetails = new MenuItem { Header = CoreTools.Translate("Package details"), Icon = LoadMenuIcon("info_round") }; + var menuDetails = new MenuItem { Header = ShortcutHeader(CoreTools.Translate("Package details"), DetailsShortcut), Icon = LoadMenuIcon("info_round") }; menuDetails.Click += (_, _) => _ = ShowDetailsForPackage(SelectedItem); var menu = new ContextMenu(); diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/InstalledPackagesPage.cs b/src/UniGetUI.Avalonia/Views/SoftwarePages/InstalledPackagesPage.cs index e1d378c41..d816834c1 100644 --- a/src/UniGetUI.Avalonia/Views/SoftwarePages/InstalledPackagesPage.cs +++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/InstalledPackagesPage.cs @@ -131,14 +131,14 @@ protected override void GenerateToolBar(PackagesPageViewModel vm) { var menuUninstall = new MenuItem { - Header = CoreTools.Translate("Uninstall"), + Header = ShortcutHeader(CoreTools.Translate("Uninstall"), MainActionShortcut), Icon = LoadMenuIcon("delete"), }; menuUninstall.Click += (_, _) => _ = LaunchUninstall([SelectedItem!]); _menuInstallationOptions = new MenuItem { - Header = CoreTools.Translate("Uninstall options"), + Header = ShortcutHeader(CoreTools.Translate("Uninstall options"), OptionsShortcut), Icon = LoadMenuIcon("options"), }; _menuInstallationOptions.Click += (_, _) => _ = ShowInstallationOptionsForPackage(SelectedItem); @@ -203,7 +203,7 @@ protected override void GenerateToolBar(PackagesPageViewModel vm) _menuDetails = new MenuItem { - Header = CoreTools.Translate("Package details"), + Header = ShortcutHeader(CoreTools.Translate("Package details"), DetailsShortcut), Icon = LoadMenuIcon("info_round"), }; _menuDetails.Click += (_, _) => _ = ShowDetailsForPackage(SelectedItem); diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/PackageBundlesPage.cs b/src/UniGetUI.Avalonia/Views/SoftwarePages/PackageBundlesPage.cs index 6216d51ca..1f825cf9a 100644 --- a/src/UniGetUI.Avalonia/Views/SoftwarePages/PackageBundlesPage.cs +++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/PackageBundlesPage.cs @@ -127,10 +127,10 @@ private static IReadOnlyList GetCheckedNonInstalledPackages(PackagesPa // ─── Context menu ───────────────────────────────────────────────────────── protected override ContextMenu? GenerateContextMenu() { - _menuInstall = new MenuItem { Header = CoreTools.Translate("Install"), Icon = LoadMenuIcon("download") }; + _menuInstall = new MenuItem { Header = ShortcutHeader(CoreTools.Translate("Install"), MainActionShortcut), Icon = LoadMenuIcon("download") }; _menuInstall.Click += (_, _) => _ = ImportAndInstallPackage(SelectedItem is { } p ? [p] : []); - _menuInstallOptions = new MenuItem { Header = CoreTools.Translate("Install options"), Icon = LoadMenuIcon("options") }; + _menuInstallOptions = new MenuItem { Header = ShortcutHeader(CoreTools.Translate("Install options"), OptionsShortcut), Icon = LoadMenuIcon("options") }; _menuInstallOptions.Click += (_, _) => { if (SelectedItem is ImportedPackage imported) @@ -163,7 +163,7 @@ private static IReadOnlyList GetCheckedNonInstalledPackages(PackagesPa } }; - _menuDetails = new MenuItem { Header = CoreTools.Translate("Package details"), Icon = LoadMenuIcon("info_round") }; + _menuDetails = new MenuItem { Header = ShortcutHeader(CoreTools.Translate("Package details"), DetailsShortcut), Icon = LoadMenuIcon("info_round") }; _menuDetails.Click += (_, _) => _ = ShowDetailsForPackage(SelectedItem); var menu = new ContextMenu(); diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/SoftwareUpdatesPage.cs b/src/UniGetUI.Avalonia/Views/SoftwarePages/SoftwareUpdatesPage.cs index 7bc6994c0..48fc7f3fc 100644 --- a/src/UniGetUI.Avalonia/Views/SoftwarePages/SoftwareUpdatesPage.cs +++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/SoftwareUpdatesPage.cs @@ -109,14 +109,14 @@ protected override void GenerateToolBar(PackagesPageViewModel vm) { var menuUpdate = new MenuItem { - Header = CoreTools.Translate("Update"), + Header = ShortcutHeader(CoreTools.Translate("Update"), MainActionShortcut), Icon = LoadMenuIcon("update"), }; menuUpdate.Click += (_, _) => _ = LaunchUpdate([SelectedItem!]); var menuUpdateOptions = new MenuItem { - Header = CoreTools.Translate("Update options"), + Header = ShortcutHeader(CoreTools.Translate("Update options"), OptionsShortcut), Icon = LoadMenuIcon("options"), }; menuUpdateOptions.Click += (_, _) => _ = ShowInstallationOptionsForPackage(SelectedItem); @@ -233,7 +233,7 @@ protected override void GenerateToolBar(PackagesPageViewModel vm) var menuDetails = new MenuItem { - Header = CoreTools.Translate("Package details"), + Header = ShortcutHeader(CoreTools.Translate("Package details"), DetailsShortcut), Icon = LoadMenuIcon("info_round"), }; menuDetails.Click += (_, _) => _ = ShowDetailsForPackage(SelectedItem);