Skip to content

Code Quality: Improved Omnibar 4 #17189

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 6 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
2 changes: 2 additions & 0 deletions src/Files.App.Controls/Omnibar/EventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ public record class OmnibarQuerySubmittedEventArgs(OmnibarMode Mode, object? Ite
public record class OmnibarSuggestionChosenEventArgs(OmnibarMode Mode, object SelectedItem);

public record class OmnibarTextChangedEventArgs(OmnibarMode Mode, OmnibarTextChangeReason Reason);

public record class OmnibarModeChangedEventArgs(OmnibarMode? OldMode, OmnibarMode NewMode);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace Files.App.Controls
{
/// <summary>
/// An interface that provides a way to get the text member path of <see cref="OmnibarMode.SuggestionItemsSource"/>.
/// An interface that provides a way to get the text member path of <see cref="OmnibarMode.ItemsSource"/>.
/// </summary>
/// <remarks>
/// An alternative to this interface is to use an <see cref="Microsoft.UI.Xaml.Data.IBindableCustomPropertyImplementation"/> powered by CsWinRT.
Expand Down
2 changes: 1 addition & 1 deletion src/Files.App.Controls/Omnibar/Omnibar.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ partial void OnCurrentSelectedModePropertyChanged(DependencyPropertyChangedEvent
return;

ChangeMode(e.OldValue as OmnibarMode, newMode);
CurrentSelectedModeName = newMode.ModeName;
CurrentSelectedModeName = newMode.Name;
}

partial void OnCurrentSelectedModeNameChanged(string? newValue)
Expand Down
22 changes: 15 additions & 7 deletions src/Files.App.Controls/Omnibar/Omnibar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public partial class Omnibar : Control
public event TypedEventHandler<Omnibar, OmnibarQuerySubmittedEventArgs>? QuerySubmitted;
public event TypedEventHandler<Omnibar, OmnibarSuggestionChosenEventArgs>? SuggestionChosen;
public event TypedEventHandler<Omnibar, OmnibarTextChangedEventArgs>? TextChanged;
public event TypedEventHandler<Omnibar, OmnibarModeChangedEventArgs>? ModeChanged;

// Constructor

Expand Down Expand Up @@ -155,9 +156,11 @@ protected void ChangeMode(OmnibarMode? oldMode, OmnibarMode newMode)
VisualStateManager.GoToState(newMode, "Focused", true);
newMode.IsTabStop = false;

ModeChanged?.Invoke(this, new(oldMode, newMode!));

_textBox.PlaceholderText = newMode.PlaceholderText ?? string.Empty;
_textBoxSuggestionsListView.ItemTemplate = newMode.SuggestionItemTemplate;
_textBoxSuggestionsListView.ItemsSource = newMode.SuggestionItemsSource;
_textBoxSuggestionsListView.ItemTemplate = newMode.ItemTemplate;
_textBoxSuggestionsListView.ItemsSource = newMode.ItemsSource;

if (newMode.IsAutoFocusEnabled)
{
Expand All @@ -179,10 +182,10 @@ protected void ChangeMode(OmnibarMode? oldMode, OmnibarMode newMode)
{
VisualStateManager.GoToState(_textBox, "InputAreaVisible", true);
}

TryToggleIsSuggestionsPopupOpen(true);
}

TryToggleIsSuggestionsPopupOpen(true);

// Remove the reposition transition from the all modes
foreach (var mode in Modes)
{
Expand All @@ -196,12 +199,17 @@ internal protected void FocusTextBox()
_textBox.Focus(FocusState.Keyboard);
}

public bool TryToggleIsSuggestionsPopupOpen(bool wantToOpen)
internal protected bool TryToggleIsSuggestionsPopupOpen(bool wantToOpen)
{
if (wantToOpen && (!IsFocused || CurrentSelectedMode?.SuggestionItemsSource is null || (CurrentSelectedMode?.SuggestionItemsSource is IList collection && collection.Count is 0)) ||
_textBoxSuggestionsPopup is null)
if (_textBoxSuggestionsPopup is null)
return false;

if (wantToOpen && (!IsFocused || CurrentSelectedMode?.ItemsSource is null || (CurrentSelectedMode?.ItemsSource is IList collection && collection.Count is 0)))
{
_textBoxSuggestionsPopup.IsOpen = false;
return false;
}

_textBoxSuggestionsPopup.IsOpen = wantToOpen;

return false;
Expand Down
30 changes: 22 additions & 8 deletions src/Files.App.Controls/Omnibar/Omnibar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,21 @@
<BrushTransition Duration="0:0:0.083" />
</Border.BackgroundTransition>

<ContentPresenter
x:Name="PART_ModeButtonIconPresenter"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{Binding IconOnInactive, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}" />
<Grid>
<ContentPresenter
x:Name="PART_ModeButtonInactiveIconPresenter"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{Binding IconOnInactive, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="Visible" />

<ContentPresenter
x:Name="PART_ModeButtonActiveIconPresenter"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{Binding IconOnActive, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="Collapsed" />
</Grid>
</Border>

<ContentPresenter
Expand All @@ -172,7 +182,8 @@
<VisualState x:Name="PointerPressed">
<VisualState.Setters>
<Setter Target="PART_ModeButton.Background" Value="{ThemeResource SubtleFillColorTertiaryBrush}" />
<Setter Target="PART_ModeButtonIconPresenter.Content" Value="{Binding IconOnActive, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}" />
<Setter Target="PART_ModeButtonInactiveIconPresenter.Visibility" Value="Collapsed" />
<Setter Target="PART_ModeButtonActiveIconPresenter.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
Expand All @@ -181,13 +192,16 @@
<VisualState x:Name="Unfocused" />
<VisualState x:Name="CurrentUnfocused">
<VisualState.Setters>
<Setter Target="PART_ModeButtonIconPresenter.Visibility" Value="Collapsed" />
<Setter Target="PART_ModeButtonInactiveIconPresenter.Visibility" Value="Collapsed" />
<Setter Target="PART_ModeButtonActiveIconPresenter.Visibility" Value="Collapsed" />
<Setter Target="PART_ModeButton.Visibility" Value="Collapsed" />
<Setter Target="PART_InactiveContent.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Target="PART_ModeButtonIconPresenter.Content" Value="{Binding IconOnActive, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}" />
<Setter Target="PART_ModeButtonInactiveIconPresenter.Visibility" Value="Collapsed" />
<Setter Target="PART_ModeButtonActiveIconPresenter.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
Expand Down
8 changes: 1 addition & 7 deletions src/Files.App.Controls/Omnibar/OmnibarMode.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,9 @@ public partial class OmnibarMode
[GeneratedDependencyProperty]
public partial FrameworkElement? IconOnInactive { get; set; }

[GeneratedDependencyProperty]
public partial object? SuggestionItemsSource { get; set; }

[GeneratedDependencyProperty]
public partial DataTemplate? SuggestionItemTemplate { get; set; }

[GeneratedDependencyProperty]
/// <remark>
/// Implement <see cref="IOmnibarTextMemberPathProvider"/> in <see cref="SuggestionItemsSource"/> to get the text member path from the suggestion item correctly.
/// Implement <see cref="IOmnibarTextMemberPathProvider"/> in <see cref="ItemsSource"/> to get the text member path from the suggestion item correctly.
/// </remark>
public partial string? TextMemberPath { get; set; }

Expand Down
10 changes: 9 additions & 1 deletion src/Files.App.Controls/Omnibar/OmnibarMode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
namespace Files.App.Controls
{
[DebuggerDisplay("{" + nameof(ToString) + "(),nq}")]
public partial class OmnibarMode : Control
public partial class OmnibarMode : ItemsControl
{
// Constants

Expand Down Expand Up @@ -66,6 +66,14 @@ protected override void OnKeyUp(KeyRoutedEventArgs args)
}
}

protected override void OnItemsChanged(object e)
{
base.OnItemsChanged(e);

if (_ownerRef is not null && _ownerRef.TryGetTarget(out var owner))
owner.TryToggleIsSuggestionsPopupOpen(true);
}

private void OmnibarMode_Loaded(object sender, RoutedEventArgs e)
{
// Set this mode as the current mode if it is the default mode
Expand Down
13 changes: 6 additions & 7 deletions src/Files.App/UserControls/NavigationToolbar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,6 @@
x:Name="Omnibar"
Grid.Column="1"
x:Load="{x:Bind ViewModel.EnableOmnibar, Mode=OneWay}"
CurrentSelectedMode="{x:Bind ViewModel.OmnibarCurrentSelectedMode, Mode=TwoWay}"
CurrentSelectedModeName="{x:Bind ViewModel.OmnibarCurrentSelectedModeName, Mode=TwoWay}"
IsFocused="{x:Bind ViewModel.IsOmnibarFocused, Mode=TwoWay}"
LostFocus="Omnibar_LostFocus"
Expand All @@ -334,9 +333,9 @@
IconOnActive="{controls:ThemedIconMarkup Style={StaticResource App.ThemedIcons.Omnibar.Path}, IsFilled=True}"
IconOnInactive="{controls:ThemedIconMarkup Style={StaticResource App.ThemedIcons.Omnibar.Path}, IconType=Outline}"
IsDefault="True"
ItemsSource="{x:Bind ViewModel.PathModeSuggestionItems, Mode=OneWay}"
ModeName="{x:Bind Commands.EditPath.LabelWithHotKey, Mode=OneWay}"
PlaceholderText="{helpers:ResourceString Name=OmnibarPathModeTextPlaceholder}"
SuggestionItemsSource="{x:Bind ViewModel.PathModeSuggestionItems, Mode=OneWay}"
Text="{x:Bind ViewModel.PathText, Mode=TwoWay}"
TextMemberPath="Path">
<controls:OmnibarMode.ContentOnInactive>
Expand Down Expand Up @@ -365,25 +364,25 @@
</controls:BreadcrumbBar.ItemTemplate>
</controls:BreadcrumbBar>
</controls:OmnibarMode.ContentOnInactive>
<controls:OmnibarMode.SuggestionItemTemplate>
<controls:OmnibarMode.ItemTemplate>
<DataTemplate x:DataType="datamodels:OmnibarPathModeSuggestionModel">
<TextBlock Text="{x:Bind DisplayName, Mode=OneWay}" />
</DataTemplate>
</controls:OmnibarMode.SuggestionItemTemplate>
</controls:OmnibarMode.ItemTemplate>
</controls:OmnibarMode>

<controls:OmnibarMode
x:Name="OmnibarCommandPaletteMode"
IconOnActive="{controls:ThemedIconMarkup Style={StaticResource App.ThemedIcons.Omnibar.Commands}, IsFilled=True}"
IconOnInactive="{controls:ThemedIconMarkup Style={StaticResource App.ThemedIcons.Omnibar.Commands}, IconType=Outline}"
IsAutoFocusEnabled="True"
ItemsSource="{x:Bind ViewModel.OmnibarCommandPaletteModeSuggestionItems, Mode=OneWay}"
ModeName="{x:Bind Commands.OpenCommandPalette.LabelWithHotKey, Mode=OneWay}"
PlaceholderText="{helpers:ResourceString Name=OmnibarCommandPaletteModeTextPlaceholder}"
SuggestionItemsSource="{x:Bind ViewModel.OmnibarCommandPaletteModeSuggestionItems, Mode=OneWay}"
Text="{x:Bind ViewModel.OmnibarCommandPaletteModeText, Mode=TwoWay}"
TextMemberPath="Text"
UpdateTextOnSelect="False">
<controls:OmnibarMode.SuggestionItemTemplate>
<controls:OmnibarMode.ItemTemplate>
<DataTemplate x:DataType="dataitems:NavigationBarSuggestionItem">
<Grid ColumnSpacing="12">
<Grid.ColumnDefinitions>
Expand Down Expand Up @@ -422,7 +421,7 @@
HotKeys="{x:Bind HotKeys}" />
</Grid>
</DataTemplate>
</controls:OmnibarMode.SuggestionItemTemplate>
</controls:OmnibarMode.ItemTemplate>
</controls:OmnibarMode>

<controls:OmnibarMode
Expand Down
5 changes: 3 additions & 2 deletions src/Files.App/UserControls/NavigationToolbar.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public sealed partial class NavigationToolbar : UserControl
private readonly MainPageViewModel MainPageViewModel = Ioc.Default.GetRequiredService<MainPageViewModel>();
private readonly ICommandManager Commands = Ioc.Default.GetRequiredService<ICommandManager>();
private readonly StatusCenterViewModel OngoingTasksViewModel = Ioc.Default.GetRequiredService<StatusCenterViewModel>();
private readonly IContentPageContext ContentPageContext = Ioc.Default.GetRequiredService<IContentPageContext>();

// Properties

Expand Down Expand Up @@ -413,9 +414,9 @@ private void BreadcrumbBar_ItemDropDownFlyoutClosed(object sender, BreadcrumbBar

private void Omnibar_LostFocus(object sender, RoutedEventArgs e)
{
if (ViewModel.OmnibarCurrentSelectedMode == OmnibarCommandPaletteMode)
if (Omnibar.CurrentSelectedMode == OmnibarCommandPaletteMode)
{
ViewModel.OmnibarCurrentSelectedMode = OmnibarPathMode;
Omnibar.CurrentSelectedMode = OmnibarPathMode;
ViewModel.OmnibarCommandPaletteModeText = string.Empty;
}
}
Expand Down
43 changes: 33 additions & 10 deletions src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using CommunityToolkit.WinUI;
using Files.App.Controls;
using Files.Shared.Helpers;
using Microsoft.Extensions.Logging;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
Expand Down Expand Up @@ -242,7 +243,7 @@ public bool IsOmnibarFocused

if (value)
{
switch (OmnibarCurrentSelectedMode.Name)
switch (OmnibarCurrentSelectedModeName)
{
case OmnibarPathModeName:
PathText =
Expand All @@ -263,11 +264,34 @@ public bool IsOmnibarFocused
}
}

private OmnibarMode _OmnibarCurrentSelectedMode;
public OmnibarMode OmnibarCurrentSelectedMode { get => _OmnibarCurrentSelectedMode; set => SetProperty(ref _OmnibarCurrentSelectedMode, value); }

private string _OmnibarCurrentSelectedModeName;
public string OmnibarCurrentSelectedModeName { get => _OmnibarCurrentSelectedModeName; set => SetProperty(ref _OmnibarCurrentSelectedModeName, value); }
private string _OmnibarCurrentSelectedModeName = OmnibarPathModeName;
public string OmnibarCurrentSelectedModeName
{
get => _OmnibarCurrentSelectedModeName;
set
{
if (SetProperty(ref _OmnibarCurrentSelectedModeName, value) && IsOmnibarFocused)
{
switch (value)
{
case OmnibarPathModeName:
PathText =
string.IsNullOrEmpty(ContentPageContext.ShellPage?.ShellViewModel?.WorkingDirectory)
? Constants.UserEnvironmentPaths.HomePath
: ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory;
_ = PopulateOmnibarSuggestionsForPathMode();
break;
case OmnibarPaletteModeName:
PopulateOmnibarSuggestionsForCommandPaletteMode();
break;
case OmnibarSearchModeName:
break;
default:
break;
}
}
}
}

private CurrentInstanceViewModel _InstanceViewModel;
public CurrentInstanceViewModel InstanceViewModel
Expand Down Expand Up @@ -738,7 +762,6 @@ await DialogDisplayHelper.ShowDialogAsync(Strings.InvalidItemDialogTitle.GetLoca
}

PathControlDisplayText = ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory;
IsOmnibarFocused = false;
}

public void PathBoxItem_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
Expand Down Expand Up @@ -1077,6 +1100,8 @@ private static async Task<bool> LaunchApplicationFromPath(string currentInput, s

public async Task PopulateOmnibarSuggestionsForPathMode()
{
PathModeSuggestionItems.Clear();

var result = await SafetyExtensions.IgnoreExceptions((Func<Task<bool>>)(async () =>
{
List<OmnibarPathModeSuggestionModel>? newSuggestions = [];
Expand Down Expand Up @@ -1117,9 +1142,7 @@ public async Task PopulateOmnibarSuggestionsForPathMode()

// If there are no suggestions, show "No suggestions"
if (newSuggestions.Count is 0)
{
AddNoResultsItem();
}
return false;

// Check whether at least one item is in common between the old and the new suggestions
// since the suggestions popup becoming empty causes flickering
Expand Down
4 changes: 2 additions & 2 deletions tests/Files.App.UITests/Views/OmnibarPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@
</controls:OmnibarMode>

<controls:OmnibarMode
DisplayMemberPath="{x:Bind Omnibar1_TextMemberPathForPaletteMode}"
IconOnActive="{controls:ThemedIconMarkup Style={StaticResource App.ThemedIcons.Omnibar.Commands}, IsFilled=True}"
IconOnInactive="{controls:ThemedIconMarkup Style={StaticResource App.ThemedIcons.Omnibar.Commands}, IconType=Outline}"
ModeName="Palette"
PlaceholderText="Enter a palette command..."
SuggestionItemsSource="{x:Bind Omnibar1_PaletteSuggestions, Mode=OneWay}">
SuggestionItemsSource="{x:Bind Omnibar1_PaletteSuggestions, Mode=OneWay}"
TextMemberPath="{x:Bind Omnibar1_TextMemberPathForPaletteMode}">
<controls:OmnibarMode.SuggestionItemTemplate>
<DataTemplate x:DataType="data:OmnibarPaletteSuggestionItem">
<Grid Height="48" ColumnSpacing="12">
Expand Down
Loading