Skip to content

Code Quality: Improved Omnibar UX 2 #17157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
}
}
12 changes: 8 additions & 4 deletions src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,17 @@
x:Name="PART_RootBreadcrumbBarItem"
Grid.Column="0"
Padding="{StaticResource BreadcrumbBarRootItemPadding}"
AutomationProperties.AccessibilityView="Content"
CornerRadius="{StaticResource BreadcrumbBarRootItemCornerRadius}">
CornerRadius="{StaticResource BreadcrumbBarRootItemCornerRadius}"
ItemToolTip="{TemplateBinding RootItemToolTip}">
<ContentPresenter Content="{Binding RootItem, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}" />
</local:BreadcrumbBarItem>

<local:BreadcrumbBarItem
x:Name="PART_EllipsisBreadcrumbBarItem"
Grid.Column="1"
Margin="{StaticResource BreadcrumbBarItemMargin}"
AutomationProperties.AccessibilityView="Content"
IsEllipsis="True"
ToolTipService.ToolTip="{TemplateBinding EllipsisButtonToolTip}"
Visibility="Collapsed">
<FontIcon FontSize="{StaticResource BreadcrumbBarEllipsisFontSize}" Glyph="&#xE712;" />
</local:BreadcrumbBarItem>
Expand Down Expand Up @@ -125,11 +125,13 @@
Padding="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Raw"
AutomationProperties.Name="{TemplateBinding Content}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Control.IsTemplateFocusTarget="True"
CornerRadius="{TemplateBinding CornerRadius}"
ToolTipService.ToolTip="{TemplateBinding ItemToolTip}"
UseSystemFocusVisuals="True">
<Button.Resources>
<ResourceDictionary>
Expand Down Expand Up @@ -177,12 +179,14 @@
Margin="{StaticResource BreadcrumbBarItemMargin}"
Padding="{StaticResource BreadcrumbBarChevronPadding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
AutomationProperties.AccessibilityView="Content"
AutomationProperties.AccessibilityView="Raw"
AutomationProperties.Name="Chevron"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you try changing this to AutomationProperties.ID?

Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{StaticResource BreadcrumbBarChevronCornerRaduis}"
Style="{StaticResource BreadcrumbBarItemChevronButtonStyle}"
ToolTipService.ToolTip="{TemplateBinding ChevronToolTip}"
UseSystemFocusVisuals="True">
<Button.Resources>
<ResourceDictionary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -37,12 +37,15 @@ protected override string GetClassNameCore()

protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Button;
return AutomationControlType.SplitButton;
}

/// <summary>
/// Sends a request to invoke the item associated with the automation peer.
/// </summary>
protected override bool IsControlElementCore()
{
return true;
}

/// <inheritdoc/>
public void Invoke()
{
if (Owner is not BreadcrumbBarItem item)
Expand Down
10 changes: 6 additions & 4 deletions src/Files.App.Controls/BreadcrumbBar/BreadcrumbBarLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand All @@ -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;
}
Expand Down
17 changes: 16 additions & 1 deletion src/Files.App.Controls/Omnibar/Omnibar.Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
}
}
15 changes: 13 additions & 2 deletions src/Files.App.Controls/Omnibar/Omnibar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public partial class Omnibar : Control

private WeakReference<UIElement?> _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<Omnibar, OmnibarQuerySubmittedEventArgs>? QuerySubmitted;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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));
Expand Down
7 changes: 1 addition & 6 deletions src/Files.App.Controls/Omnibar/Omnibar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -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}" />
Expand Down Expand Up @@ -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">
<ListView.ItemContainerTransitions />
</ListView>
SelectionMode="Single" />
</Border>
</Popup>

Expand Down
2 changes: 2 additions & 0 deletions src/Files.App.Controls/Omnibar/OmnibarMode.Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 3 additions & 0 deletions src/Files.App.Controls/Omnibar/OmnibarMode.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down
6 changes: 6 additions & 0 deletions src/Files.App/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -4236,4 +4236,10 @@
<value>Status center progress ping</value>
<comment>Screen reader name for the status center progress ring</comment>
</data>
<data name="BreadcrumbBarEllipsisButtonToolTip" xml:space="preserve">
<value>Show collapesed path breadcrumbs</value>
</data>
<data name="BreadcrumbBarChevronButtonToolTip" xml:space="preserve">
<value>Show child folders</value>
</data>
</root>
11 changes: 9 additions & 2 deletions src/Files.App/UserControls/NavigationToolbar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,12 @@
<controls:OmnibarMode.ContentOnInactive>
<controls:BreadcrumbBar
x:Name="BreadcrumbBar"
EllipsisButtonToolTip="{helpers:ResourceString Name=BreadcrumbBarEllipsisButtonToolTip}"
ItemClicked="BreadcrumbBar_ItemClicked"
ItemDropDownFlyoutClosed="BreadcrumbBar_ItemDropDownFlyoutClosed"
ItemDropDownFlyoutOpening="BreadcrumbBar_ItemDropDownFlyoutOpening"
ItemsSource="{x:Bind ViewModel.PathComponents, Mode=OneWay}">
ItemsSource="{x:Bind ViewModel.PathComponents, Mode=OneWay}"
RootItemToolTip="{helpers:ResourceString Name=Home}">
<controls:BreadcrumbBar.RootItem>
<Image
Width="16"
Expand All @@ -352,7 +354,12 @@
</controls:BreadcrumbBar.RootItem>
<controls:BreadcrumbBar.ItemTemplate>
<DataTemplate x:DataType="dataitems:PathBoxItem">
<controls:BreadcrumbBarItem Content="{x:Bind Title, Mode=OneWay}" />
<controls:BreadcrumbBarItem
AutomationProperties.AccessibilityView="Content"
AutomationProperties.AutomationId="{x:Bind Title, Mode=OneWay}"
ChevronToolTip="{helpers:ResourceString Name=BreadcrumbBarChevronButtonToolTip}"
Content="{x:Bind Title, Mode=OneWay}"
ItemToolTip="{x:Bind Title, Mode=OneWay}" />
</DataTemplate>
</controls:BreadcrumbBar.ItemTemplate>
</controls:BreadcrumbBar>
Expand Down
9 changes: 8 additions & 1 deletion src/Files.App/UserControls/NavigationToolbar.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,13 @@ private async void Omnibar_QuerySubmitted(Omnibar sender, OmnibarQuerySubmittedE
}
else if (Omnibar.CurrentSelectedMode == OmnibarCommandPaletteMode)
{
if (args.Item is not NavigationBarSuggestionItem item || item.Text is not { } commandText)
string commandText = args.Item is NavigationBarSuggestionItem { Text: string itemText }
? itemText
: args.Text is string text
? text
: string.Empty;

if (string.IsNullOrEmpty(commandText))
return;

var command = Commands[commandText];
Expand All @@ -276,6 +282,7 @@ await DialogDisplayHelper.ShowDialogAsync(Strings.CommandNotExecutable.GetLocali
await command.ExecuteAsync();

ViewModel.OmnibarCurrentSelectedMode = OmnibarPathMode;
ViewModel.OmnibarCommandPaletteModeText = string.Empty;
}
else if (Omnibar.CurrentSelectedMode == OmnibarSearchMode)
{
Expand Down