diff --git a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.Properties.cs b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.Properties.cs
index 36dca955a6c1..a02306d2a95c 100644
--- a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.Properties.cs
+++ b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.Properties.cs
@@ -15,5 +15,11 @@ public partial class BreadcrumbBar : Control
[GeneratedDependencyProperty]
public partial object? ItemTemplate { get; set; }
+
+ [GeneratedDependencyProperty]
+ public partial string? EllipsisButtonToolTip { get; set; }
+
+ [GeneratedDependencyProperty]
+ public partial string? RootItemToolTip { get; set; }
}
}
diff --git a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml
index 213ab4cd8340..071c43d19e5a 100644
--- a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml
+++ b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml
@@ -13,6 +13,7 @@
8,0
16,0,8,0
2,0,0,0
+ 32
2,2,2,2
2,2,2,2
@@ -55,8 +56,8 @@
x:Name="PART_RootBreadcrumbBarItem"
Grid.Column="0"
Padding="{StaticResource BreadcrumbBarRootItemPadding}"
- AutomationProperties.AccessibilityView="Content"
- CornerRadius="{StaticResource BreadcrumbBarRootItemCornerRadius}">
+ CornerRadius="{StaticResource BreadcrumbBarRootItemCornerRadius}"
+ ItemToolTip="{TemplateBinding RootItemToolTip}">
@@ -64,8 +65,8 @@
x:Name="PART_EllipsisBreadcrumbBarItem"
Grid.Column="1"
Margin="{StaticResource BreadcrumbBarItemMargin}"
- AutomationProperties.AccessibilityView="Content"
IsEllipsis="True"
+ ToolTipService.ToolTip="{TemplateBinding EllipsisButtonToolTip}"
Visibility="Collapsed">
@@ -96,7 +97,7 @@
-
+
@@ -114,120 +115,116 @@
x:Name="PART_LayoutRoot"
TabFocusNavigation="Once"
XYFocusKeyboardNavigation="Enabled">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+ AutomationProperties.Name="Chevron"
+ Background="{TemplateBinding Background}"
+ BorderBrush="{TemplateBinding BorderBrush}"
+ BorderThickness="{TemplateBinding BorderThickness}"
+ CornerRadius="{StaticResource BreadcrumbBarChevronCornerRaduis}"
+ Style="{StaticResource BreadcrumbBarItemChevronButtonStyle}"
+ ToolTipService.ToolTip="{TemplateBinding ChevronToolTip}"
+ UseSystemFocusVisuals="True">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarItem.Properties.cs b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarItem.Properties.cs
index 7b1709d84b26..47cae0a537a4 100644
--- a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarItem.Properties.cs
+++ b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarItem.Properties.cs
@@ -13,6 +13,12 @@ public partial class BreadcrumbBarItem
[GeneratedDependencyProperty]
public partial bool IsLastItem { get; set; }
+ [GeneratedDependencyProperty]
+ public partial string ItemToolTip { get; set; }
+
+ [GeneratedDependencyProperty]
+ public partial string ChevronToolTip { get; set; }
+
partial void OnIsEllipsisChanged(bool newValue)
{
VisualStateManager.GoToState(this, newValue ? "ChevronCollapsed" : "ChevronVisible", true);
diff --git a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarItemAutomationPeer.cs b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarItemAutomationPeer.cs
index 42d81617f28c..bddb74a7bf8f 100644
--- a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarItemAutomationPeer.cs
+++ b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarItemAutomationPeer.cs
@@ -24,7 +24,7 @@ protected override string GetLocalizedControlTypeCore()
protected override object GetPatternCore(PatternInterface patternInterface)
{
- if (patternInterface is PatternInterface.Invoke)
+ if (patternInterface is PatternInterface.ExpandCollapse or PatternInterface.Invoke)
return this;
return base.GetPatternCore(patternInterface);
@@ -37,12 +37,15 @@ protected override string GetClassNameCore()
protected override AutomationControlType GetAutomationControlTypeCore()
{
- return AutomationControlType.Button;
+ return AutomationControlType.SplitButton;
}
- ///
- /// Sends a request to invoke the item associated with the automation peer.
- ///
+ protected override bool IsControlElementCore()
+ {
+ return true;
+ }
+
+ ///
public void Invoke()
{
if (Owner is not BreadcrumbBarItem item)
diff --git a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarLayout.cs b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarLayout.cs
index da0313988121..f1a0d2efcc25 100644
--- a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarLayout.cs
+++ b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarLayout.cs
@@ -33,13 +33,15 @@ protected override Size MeasureOverride(NonVirtualizingLayoutContext context, Si
var accumulatedSize = new Size(0, 0);
_availableSize = availableSize;
+ var indexAfterEllipsis = GetFirstIndexToRender(context);
+
// Go through all items and measure them
- foreach (var item in context.Children)
+ for (int index = 0; index < context.Children.Count; index++)
{
- if (item is BreadcrumbBarItem breadcrumbItem)
+ if (context.Children[index] is BreadcrumbBarItem breadcrumbItem)
{
breadcrumbItem.Measure(availableSize);
- accumulatedSize.Width += breadcrumbItem.DesiredSize.Width;
+ accumulatedSize.Width += index < indexAfterEllipsis ? 0: breadcrumbItem.DesiredSize.Width;
accumulatedSize.Height = Math.Max(accumulatedSize.Height, breadcrumbItem.DesiredSize.Height);
}
}
@@ -49,7 +51,7 @@ protected override Size MeasureOverride(NonVirtualizingLayoutContext context, Si
_ellipsisButton ??= context.Children[0] as BreadcrumbBarItem;
// Sets the ellipsis item's visibility based on whether the items are overflowing
- EllipsisIsRendered = accumulatedSize.Width > availableSize.Width;
+ EllipsisIsRendered = indexAfterEllipsis is not 0;
return accumulatedSize;
}
diff --git a/src/Files.App.Controls/Omnibar/Omnibar.Events.cs b/src/Files.App.Controls/Omnibar/Omnibar.Events.cs
index 9f33112c8ee0..4499c41ab5d4 100644
--- a/src/Files.App.Controls/Omnibar/Omnibar.Events.cs
+++ b/src/Files.App.Controls/Omnibar/Omnibar.Events.cs
@@ -22,6 +22,16 @@ private void AutoSuggestBox_GettingFocus(UIElement sender, GettingFocusEventArgs
_previouslyFocusedElement = new(args.OldFocusedElement as UIElement);
}
+ private void AutoSuggestBox_LosingFocus(UIElement sender, LosingFocusEventArgs args)
+ {
+ if (IsModeButtonPressed)
+ {
+ IsModeButtonPressed = false;
+ args.TryCancel();
+ return;
+ }
+ }
+
private void AutoSuggestBox_GotFocus(object sender, RoutedEventArgs e)
{
IsFocused = true;
@@ -70,7 +80,7 @@ private void AutoSuggestBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
_textBoxSuggestionsListView.SelectedIndex = nextIndex;
- ChooseSuggestionItem(_textBoxSuggestionsListView.SelectedItem);
+ ChooseSuggestionItem(_textBoxSuggestionsListView.SelectedItem, true);
}
}
else if (e.Key == VirtualKey.Escape)
@@ -127,5 +137,10 @@ private void AutoSuggestBoxSuggestionsListView_ItemClick(object sender, ItemClic
ChooseSuggestionItem(e.ClickedItem);
SubmitQuery(e.ClickedItem);
}
+
+ private void AutoSuggestBoxSuggestionsListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ _textBoxSuggestionsListView.ScrollIntoView(_textBoxSuggestionsListView.SelectedItem);
+ }
}
}
diff --git a/src/Files.App.Controls/Omnibar/Omnibar.cs b/src/Files.App.Controls/Omnibar/Omnibar.cs
index f4d29468e1ff..50c4eecacd43 100644
--- a/src/Files.App.Controls/Omnibar/Omnibar.cs
+++ b/src/Files.App.Controls/Omnibar/Omnibar.cs
@@ -33,6 +33,9 @@ public partial class Omnibar : Control
private WeakReference _previouslyFocusedElement = new(null);
+ // NOTE: This is a workaround to keep Omnibar's focus on a mode button being clicked
+ internal bool IsModeButtonPressed { get; set; }
+
// Events
public event TypedEventHandler? QuerySubmitted;
@@ -71,11 +74,13 @@ protected override void OnApplyTemplate()
SizeChanged += Omnibar_SizeChanged;
_textBox.GettingFocus += AutoSuggestBox_GettingFocus;
_textBox.GotFocus += AutoSuggestBox_GotFocus;
+ _textBox.LosingFocus += AutoSuggestBox_LosingFocus;
_textBox.LostFocus += AutoSuggestBox_LostFocus;
_textBox.KeyDown += AutoSuggestBox_KeyDown;
_textBox.TextChanged += AutoSuggestBox_TextChanged;
_textBoxSuggestionsPopup.GettingFocus += AutoSuggestBoxSuggestionsPopup_GettingFocus;
_textBoxSuggestionsListView.ItemClick += AutoSuggestBoxSuggestionsListView_ItemClick;
+ _textBoxSuggestionsListView.SelectionChanged += AutoSuggestBoxSuggestionsListView_SelectionChanged;
// Set the default width
_textBoxSuggestionsContainerBorder.Width = ActualWidth;
@@ -148,6 +153,11 @@ protected void ChangeMode(OmnibarMode? oldMode, OmnibarMode newMode)
VisualStateManager.GoToState(newMode, "Focused", true);
newMode.IsTabStop = false;
+
+ _textBox.PlaceholderText = newMode.PlaceholderText ?? string.Empty;
+ _textBoxSuggestionsListView.ItemTemplate = newMode.SuggestionItemTemplate;
+ _textBoxSuggestionsListView.ItemsSource = newMode.SuggestionItemsSource;
+
if (newMode.IsAutoFocusEnabled)
{
_textBox.Focus(FocusState.Pointer);
@@ -196,12 +206,13 @@ public bool TryToggleIsSuggestionsPopupOpen(bool wantToOpen)
return false;
}
- public void ChooseSuggestionItem(object obj)
+ public void ChooseSuggestionItem(object obj, bool isOriginatedFromArrowKey = false)
{
if (CurrentSelectedMode is null)
return;
- if (CurrentSelectedMode.UpdateTextOnSelect)
+ if (CurrentSelectedMode.UpdateTextOnSelect ||
+ (isOriginatedFromArrowKey && CurrentSelectedMode.UpdateTextOnArrowKeys))
{
_textChangeReason = OmnibarTextChangeReason.SuggestionChosen;
ChangeTextBoxText(GetObjectText(obj));
diff --git a/src/Files.App.Controls/Omnibar/Omnibar.xaml b/src/Files.App.Controls/Omnibar/Omnibar.xaml
index 64eabed99947..26c90b65eb0f 100644
--- a/src/Files.App.Controls/Omnibar/Omnibar.xaml
+++ b/src/Files.App.Controls/Omnibar/Omnibar.xaml
@@ -67,7 +67,6 @@
FontStretch="{TemplateBinding FontStretch}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
- PlaceholderText="{Binding CurrentSelectedMode.PlaceholderText, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
ScrollViewer.BringIntoViewOnFocusChange="False"
Style="{StaticResource DefaultOmnibarTextBoxStyle}"
UseSystemFocusVisuals="{TemplateBinding UseSystemFocusVisuals}" />
@@ -96,11 +95,7 @@
MaxHeight="{ThemeResource AutoSuggestListMaxHeight}"
Margin="{ThemeResource AutoSuggestListPadding}"
IsItemClickEnabled="True"
- ItemTemplate="{Binding CurrentSelectedMode.SuggestionItemTemplate, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
- ItemsSource="{Binding CurrentSelectedMode.SuggestionItemsSource, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
- SelectionMode="Single">
-
-
+ SelectionMode="Single" />
@@ -138,7 +133,7 @@
-
+
-
+
diff --git a/src/Files.App.Controls/Omnibar/OmnibarMode.Events.cs b/src/Files.App.Controls/Omnibar/OmnibarMode.Events.cs
index e7f73fd5262c..fdc6fa6b3c7f 100644
--- a/src/Files.App.Controls/Omnibar/OmnibarMode.Events.cs
+++ b/src/Files.App.Controls/Omnibar/OmnibarMode.Events.cs
@@ -30,6 +30,8 @@ private void ModeButton_PointerReleased(object sender, PointerRoutedEventArgs e)
VisualStateManager.GoToState(this, "PointerOver", true);
+ owner.IsModeButtonPressed = true;
+
// Change the current mode
owner.CurrentSelectedMode = this;
}
diff --git a/src/Files.App.Controls/Omnibar/OmnibarMode.Properties.cs b/src/Files.App.Controls/Omnibar/OmnibarMode.Properties.cs
index dbac55f6ca1f..6245ebbca02f 100644
--- a/src/Files.App.Controls/Omnibar/OmnibarMode.Properties.cs
+++ b/src/Files.App.Controls/Omnibar/OmnibarMode.Properties.cs
@@ -43,6 +43,9 @@ public partial class OmnibarMode
[GeneratedDependencyProperty(DefaultValue = true)]
public partial bool UpdateTextOnSelect { get; set; }
+ [GeneratedDependencyProperty(DefaultValue = true)]
+ public partial bool UpdateTextOnArrowKeys { get; set; }
+
[GeneratedDependencyProperty]
public partial bool IsAutoFocusEnabled { get; set; }
diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw
index 8a5b39ff452e..7040ba60c3f2 100644
--- a/src/Files.App/Strings/en-US/Resources.resw
+++ b/src/Files.App/Strings/en-US/Resources.resw
@@ -4240,4 +4240,10 @@
Icon files
This is the friendly name for a variety of different icon files.
+
+ Show collapsed path breadcrumbs
+
+
+ Show child folders
+
diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml b/src/Files.App/UserControls/NavigationToolbar.xaml
index 30f1f6f82475..e1056c2544ed 100644
--- a/src/Files.App/UserControls/NavigationToolbar.xaml
+++ b/src/Files.App/UserControls/NavigationToolbar.xaml
@@ -324,6 +324,8 @@
CurrentSelectedMode="{x:Bind ViewModel.OmnibarCurrentSelectedMode, Mode=TwoWay}"
CurrentSelectedModeName="{x:Bind ViewModel.OmnibarCurrentSelectedModeName, Mode=TwoWay}"
IsFocused="{x:Bind ViewModel.IsOmnibarFocused, Mode=TwoWay}"
+ LostFocus="Omnibar_LostFocus"
+ PreviewKeyDown="Omnibar_PreviewKeyDown"
QuerySubmitted="Omnibar_QuerySubmitted"
TextChanged="Omnibar_TextChanged">
@@ -340,10 +342,12 @@
+ ItemsSource="{x:Bind ViewModel.PathComponents, Mode=OneWay}"
+ RootItemToolTip="{helpers:ResourceString Name=Home}">
-
+
diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml.cs b/src/Files.App/UserControls/NavigationToolbar.xaml.cs
index 9d7751f1b88e..e2b093d36d22 100644
--- a/src/Files.App/UserControls/NavigationToolbar.xaml.cs
+++ b/src/Files.App/UserControls/NavigationToolbar.xaml.cs
@@ -260,6 +260,7 @@ private async void Omnibar_QuerySubmitted(Omnibar sender, OmnibarQuerySubmittedE
if (Omnibar.CurrentSelectedMode == OmnibarPathMode)
{
await ViewModel.HandleItemNavigationAsync(args.Text);
+ (MainPageViewModel.SelectedTabItem?.TabItemContent as Control)?.Focus(FocusState.Programmatic);
}
else if (Omnibar.CurrentSelectedMode == OmnibarCommandPaletteMode)
{
@@ -278,13 +279,10 @@ await DialogDisplayHelper.ShowDialogAsync(Strings.CommandNotExecutable.GetLocali
string.Format(Strings.CommandNotExecutableContent.GetLocalizedResource(), command.Code));
else
await command.ExecuteAsync();
-
- ViewModel.OmnibarCurrentSelectedMode = OmnibarPathMode;
- return;
}
// Try invoking Windows app action
- if (ActionManager.Instance.ActionRuntime is not null && item.ActionInstance is ActionInstance actionInstance)
+ else if (ActionManager.Instance.ActionRuntime is not null && item.ActionInstance is ActionInstance actionInstance)
{
// Workaround for https://github.com/microsoft/App-Actions-On-Windows-Samples/issues/7
var action = ActionManager.Instance.ActionRuntime.ActionCatalog.GetAllActions()
@@ -295,9 +293,9 @@ await DialogDisplayHelper.ShowDialogAsync(Strings.CommandNotExecutable.GetLocali
var overload = action.GetOverloads().FirstOrDefault();
await overload?.InvokeAsync(actionInstance.Context);
}
-
- ViewModel.OmnibarCurrentSelectedMode = OmnibarPathMode;
}
+
+ (MainPageViewModel.SelectedTabItem?.TabItemContent as Control)?.Focus(FocusState.Programmatic);
}
else if (Omnibar.CurrentSelectedMode == OmnibarSearchMode)
{
@@ -412,5 +410,23 @@ private void BreadcrumbBar_ItemDropDownFlyoutClosed(object sender, BreadcrumbBar
// Clear the flyout items to save memory
e.Flyout.Items.Clear();
}
+
+ private void Omnibar_LostFocus(object sender, RoutedEventArgs e)
+ {
+ if (ViewModel.OmnibarCurrentSelectedMode == OmnibarCommandPaletteMode)
+ {
+ ViewModel.OmnibarCurrentSelectedMode = OmnibarPathMode;
+ ViewModel.OmnibarCommandPaletteModeText = string.Empty;
+ }
+ }
+
+ private void Omnibar_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
+ {
+ if (e.Key is VirtualKey.Escape)
+ {
+ Omnibar.IsFocused = false;
+ (MainPageViewModel.SelectedTabItem?.TabItemContent as Control)?.Focus(FocusState.Programmatic);
+ }
+ }
}
}