diff --git a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.cs b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.cs index 500fee8a96a0..5dfcacf2029d 100644 --- a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.cs +++ b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using Microsoft.UI.Xaml.Automation; +using Microsoft.UI.Xaml.Input; using Windows.Foundation; namespace Files.App.Controls @@ -25,6 +26,8 @@ public partial class BreadcrumbBar : Control private bool _isEllipsisRendered; + private bool _focusedViaKeyboard = false; // Used to determine if the BreadcrumbBar was focused via keyboard on Tab focus + // Properties public int IndexAfterEllipsis @@ -62,10 +65,18 @@ protected override void OnApplyTemplate() _ellipsisBreadcrumbBarItem.SetOwner(this); _itemsRepeater.Layout = _itemsRepeaterLayout; + //GettingFocus += BreadcrumbBar_GettingFocus; + //GettingFocus += BreadcrumbBar_GotFocus; _itemsRepeater.ElementPrepared += ItemsRepeater_ElementPrepared; + _itemsRepeater.ElementClearing += ItemsRepeater_ElementClearing; _itemsRepeater.ItemsSourceView.CollectionChanged += ItemsSourceView_CollectionChanged; } + private void BreadcrumbBar_GettingFocus(UIElement sender, GettingFocusEventArgs args) + { + _focusedViaKeyboard = args.InputDevice is FocusInputDeviceKind.Keyboard; + } + internal protected virtual void RaiseItemClickedEvent(BreadcrumbBarItem item) { var index = _itemsRepeater?.GetElementIndex(item) ?? throw new ArgumentNullException($"{_itemsRepeater} is null."); @@ -121,11 +132,19 @@ internal bool TryGetElement(int index, out BreadcrumbBarItem? item) // Event methods + private void BreadcrumbBar_GotFocus(object sender, RoutedEventArgs e) + { + _rootBreadcrumbBarItem?.Focus(FocusState.Keyboard); + } + private void ItemsRepeater_ElementPrepared(ItemsRepeater sender, ItemsRepeaterElementPreparedEventArgs args) { if (args.Element is not BreadcrumbBarItem item || _itemsRepeater is null) return; + item.IsLastItem = false; + item.IsEllipsis = false; + if (args.Index == _itemsRepeater.ItemsSourceView.Count - 1) { _lastBreadcrumbBarItem = item; @@ -148,5 +167,14 @@ private void ItemsSourceView_CollectionChanged(object? sender, System.Collection item.IsLastItem = true; } } + + private void ItemsRepeater_ElementClearing(ItemsRepeater sender, ItemsRepeaterElementClearingEventArgs args) + { + if (args.Element is BreadcrumbBarItem item) + { + item.IsLastItem = false; + item.IsEllipsis = false; + } + } } } diff --git a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml index 071c43d19e5a..bfb717524991 100644 --- a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml +++ b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml @@ -57,7 +57,8 @@ Grid.Column="0" Padding="{StaticResource BreadcrumbBarRootItemPadding}" CornerRadius="{StaticResource BreadcrumbBarRootItemCornerRadius}" - ItemToolTip="{TemplateBinding RootItemToolTip}"> + ItemToolTip="{TemplateBinding RootItemToolTip}" + TabIndex="0"> diff --git a/src/Files.App.Controls/Omnibar/Omnibar.Events.cs b/src/Files.App.Controls/Omnibar/Omnibar.Events.cs index bdb8de3e3fac..e2353a2871b4 100644 --- a/src/Files.App.Controls/Omnibar/Omnibar.Events.cs +++ b/src/Files.App.Controls/Omnibar/Omnibar.Events.cs @@ -30,6 +30,11 @@ private void AutoSuggestBox_LosingFocus(UIElement sender, LosingFocusEventArgs a args.TryCancel(); return; } + + if (args.InputDevice is FocusInputDeviceKind.Keyboard || args.Direction is FocusNavigationDirection.Next or FocusNavigationDirection.Previous) + { + CurrentSelectedMode?.ContentOnInactive?.Focus(FocusState.Programmatic); + } } private void AutoSuggestBox_GotFocus(object sender, RoutedEventArgs e) diff --git a/src/Files.App.Controls/Omnibar/Omnibar.cs b/src/Files.App.Controls/Omnibar/Omnibar.cs index e13c04274558..2eb28055084b 100644 --- a/src/Files.App.Controls/Omnibar/Omnibar.cs +++ b/src/Files.App.Controls/Omnibar/Omnibar.cs @@ -124,7 +124,6 @@ protected void ChangeMode(OmnibarMode? oldMode, OmnibarMode newMode) // Add the reposition transition to the all modes mode.Transitions = [new RepositionThemeTransition()]; mode.UpdateLayout(); - mode.IsTabStop = true; } var index = _modesHostGrid.Children.IndexOf(newMode); @@ -154,7 +153,6 @@ protected void ChangeMode(OmnibarMode? oldMode, OmnibarMode newMode) ChangeTextBoxText(newMode.Text ?? string.Empty); VisualStateManager.GoToState(newMode, "Focused", true); - newMode.IsTabStop = false; ModeChanged?.Invoke(this, new(oldMode, newMode!)); diff --git a/src/Files.App.Controls/Omnibar/Omnibar.xaml b/src/Files.App.Controls/Omnibar/Omnibar.xaml index c08f2fc5de71..b7313de35ecc 100644 --- a/src/Files.App.Controls/Omnibar/Omnibar.xaml +++ b/src/Files.App.Controls/Omnibar/Omnibar.xaml @@ -117,8 +117,8 @@ - - + diff --git a/src/Files.App.Controls/Omnibar/OmnibarMode.Events.cs b/src/Files.App.Controls/Omnibar/OmnibarMode.Events.cs index fdc6fa6b3c7f..583ce4f8c7c1 100644 --- a/src/Files.App.Controls/Omnibar/OmnibarMode.Events.cs +++ b/src/Files.App.Controls/Omnibar/OmnibarMode.Events.cs @@ -7,6 +7,17 @@ namespace Files.App.Controls { public partial class OmnibarMode { + private void ModeButton_KeyDown(object sender, KeyRoutedEventArgs e) + { + if (_ownerRef is null || _ownerRef.TryGetTarget(out var owner) is false || owner.CurrentSelectedMode == this) + return; + + if (e.Key is Windows.System.VirtualKey.Enter) + { + owner.CurrentSelectedMode = this; + } + } + private void ModeButton_PointerEntered(object sender, PointerRoutedEventArgs e) { if (_ownerRef is null || _ownerRef.TryGetTarget(out var owner) is false || owner.CurrentSelectedMode == this) diff --git a/src/Files.App.Controls/Omnibar/OmnibarMode.cs b/src/Files.App.Controls/Omnibar/OmnibarMode.cs index 1a3b49e975d9..3f057d852d15 100644 --- a/src/Files.App.Controls/Omnibar/OmnibarMode.cs +++ b/src/Files.App.Controls/Omnibar/OmnibarMode.cs @@ -35,6 +35,7 @@ protected override void OnApplyTemplate() ?? throw new MissingFieldException($"Could not find {TemplatePartName_ModeButton} in the given {nameof(OmnibarMode)}'s style."); Loaded += OmnibarMode_Loaded; + _modeButton.KeyDown += ModeButton_KeyDown; _modeButton.PointerEntered += ModeButton_PointerEntered; _modeButton.PointerPressed += ModeButton_PointerPressed; _modeButton.PointerReleased += ModeButton_PointerReleased; diff --git a/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs b/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs index 216f0835c966..19c22b9345d9 100644 --- a/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs @@ -253,7 +253,8 @@ public bool IsOmnibarFocused _ = PopulateOmnibarSuggestionsForPathMode(); break; case OmnibarPaletteModeName: - PopulateOmnibarSuggestionsForCommandPaletteMode(); + if (OmnibarCommandPaletteModeSuggestionItems.Count is 0) + PopulateOmnibarSuggestionsForCommandPaletteMode(); break; case OmnibarSearchModeName: break; @@ -282,7 +283,8 @@ public string OmnibarCurrentSelectedModeName _ = PopulateOmnibarSuggestionsForPathMode(); break; case OmnibarPaletteModeName: - PopulateOmnibarSuggestionsForCommandPaletteMode(); + if (OmnibarCommandPaletteModeSuggestionItems.Count is 0) + PopulateOmnibarSuggestionsForCommandPaletteMode(); break; case OmnibarSearchModeName: break; @@ -1100,8 +1102,6 @@ private static async Task LaunchApplicationFromPath(string currentInput, s public async Task PopulateOmnibarSuggestionsForPathMode() { - PathModeSuggestionItems.Clear(); - var result = await SafetyExtensions.IgnoreExceptions((Func>)(async () => { List? newSuggestions = [];