diff --git a/src/Files.App.Controls/Omnibar/EventArgs.cs b/src/Files.App.Controls/Omnibar/EventArgs.cs index e702c0d8d3cb..71622230d9a0 100644 --- a/src/Files.App.Controls/Omnibar/EventArgs.cs +++ b/src/Files.App.Controls/Omnibar/EventArgs.cs @@ -10,4 +10,6 @@ public record class OmnibarSuggestionChosenEventArgs(OmnibarMode Mode, object Se public record class OmnibarTextChangedEventArgs(OmnibarMode Mode, OmnibarTextChangeReason Reason); public record class OmnibarModeChangedEventArgs(OmnibarMode? OldMode, OmnibarMode NewMode); + + public record class OmnibarIsFocusedChangedEventArgs(bool IsFocused); } diff --git a/src/Files.App.Controls/Omnibar/Omnibar.Events.cs b/src/Files.App.Controls/Omnibar/Omnibar.Events.cs index f33680ad704f..0655c00e1003 100644 --- a/src/Files.App.Controls/Omnibar/Omnibar.Events.cs +++ b/src/Files.App.Controls/Omnibar/Omnibar.Events.cs @@ -39,6 +39,8 @@ private void AutoSuggestBox_GotFocus(object sender, RoutedEventArgs e) GlobalHelper.WriteDebugStringForOmnibar("The TextBox got the focus."); IsFocused = true; + IsFocusedChanged?.Invoke(this, new(IsFocused)); + _textBox.SelectAll(); } @@ -52,6 +54,7 @@ private void AutoSuggestBox_LostFocus(object sender, RoutedEventArgs e) GlobalHelper.WriteDebugStringForOmnibar("The TextBox lost the focus."); IsFocused = false; + IsFocusedChanged?.Invoke(this, new(IsFocused)); // Reset to the default mode when Omnibar loses focus CurrentSelectedMode = Modes?.FirstOrDefault(); diff --git a/src/Files.App.Controls/Omnibar/Omnibar.cs b/src/Files.App.Controls/Omnibar/Omnibar.cs index fbe301a3b9df..4977b1396d86 100644 --- a/src/Files.App.Controls/Omnibar/Omnibar.cs +++ b/src/Files.App.Controls/Omnibar/Omnibar.cs @@ -42,6 +42,7 @@ public partial class Omnibar : Control public event TypedEventHandler? SuggestionChosen; public event TypedEventHandler? TextChanged; public event TypedEventHandler? ModeChanged; + public event TypedEventHandler IsFocusedChanged; // Constructor diff --git a/src/Files.App.Controls/Omnibar/Omnibar.xaml b/src/Files.App.Controls/Omnibar/Omnibar.xaml index 546902e4663a..41ffec18a56b 100644 --- a/src/Files.App.Controls/Omnibar/Omnibar.xaml +++ b/src/Files.App.Controls/Omnibar/Omnibar.xaml @@ -130,6 +130,7 @@ x:Name="PART_ModeButton" Width="{StaticResource OmnibarModeDefaultClickAreaWidth}" Margin="1" + VerticalAlignment="Stretch" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0" diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml b/src/Files.App/UserControls/NavigationToolbar.xaml index 5d4a2db52e38..53dec5082945 100644 --- a/src/Files.App/UserControls/NavigationToolbar.xaml +++ b/src/Files.App/UserControls/NavigationToolbar.xaml @@ -350,7 +350,7 @@ Grid.Column="1" x:Load="{x:Bind ViewModel.EnableOmnibar, Mode=OneWay}" CurrentSelectedModeName="{x:Bind ViewModel.OmnibarCurrentSelectedModeName, Mode=TwoWay}" - IsFocused="{x:Bind ViewModel.IsOmnibarFocused, Mode=TwoWay}" + IsFocusedChanged="Omnibar_IsFocusedChanged" ModeChanged="Omnibar_ModeChanged" PreviewKeyDown="Omnibar_PreviewKeyDown" QuerySubmitted="Omnibar_QuerySubmitted" @@ -412,9 +412,9 @@ UpdateTextOnSelect="False"> - + - + @@ -458,8 +458,44 @@ IconOnInactive="{controls:ThemedIconMarkup Style={StaticResource App.ThemedIcons.Omnibar.Search}, IconType=Outline}" IsAutoFocusEnabled="True" IsEnabled="False" + ItemsSource="{x:Bind ViewModel.OmnibarSearchModeSuggestionItems, Mode=OneWay}" ModeName="{x:Bind Commands.Search.LabelWithHotKey, Mode=OneWay}" - PlaceholderText="{helpers:ResourceString Name=OmnibarSearchModeTextPlaceholder}" /> + PlaceholderText="{helpers:ResourceString Name=OmnibarSearchModeTextPlaceholder}" + Text="{x:Bind ViewModel.OmnibarSearchModeText, Mode=TwoWay}" + UpdateTextOnSelect="False"> + + + + + + + + + + + + + + + + + + diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml.cs b/src/Files.App/UserControls/NavigationToolbar.xaml.cs index 719b32093f3c..2ec9dda88d35 100644 --- a/src/Files.App/UserControls/NavigationToolbar.xaml.cs +++ b/src/Files.App/UserControls/NavigationToolbar.xaml.cs @@ -428,11 +428,66 @@ private void BreadcrumbBar_ItemDropDownFlyoutClosed(object sender, BreadcrumbBar e.Flyout.Items.Clear(); } - private void Omnibar_ModeChanged(object sender, OmnibarModeChangedEventArgs e) + private async void Omnibar_ModeChanged(object sender, OmnibarModeChangedEventArgs e) { - // Reset the command palette text when switching modes - if (Omnibar.CurrentSelectedMode == OmnibarCommandPaletteMode) + if (e.NewMode == OmnibarPathMode) + { + ViewModel.PathText = string.IsNullOrEmpty(ContentPageContext.ShellPage?.ShellViewModel?.WorkingDirectory) + ? Constants.UserEnvironmentPaths.HomePath + : ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory; + + await DispatcherQueue.EnqueueOrInvokeAsync(async () => + { + await ViewModel.PopulateOmnibarSuggestionsForPathMode(); + }); + } + else if (e.NewMode == OmnibarCommandPaletteMode) + { ViewModel.OmnibarCommandPaletteModeText = string.Empty; + + await DispatcherQueue.EnqueueOrInvokeAsync(() => + { + ViewModel.PopulateOmnibarSuggestionsForCommandPaletteMode(); + }); + } + else if (e.NewMode == OmnibarSearchMode) + { + + } + } + + private async void Omnibar_IsFocusedChanged(Omnibar sender, OmnibarIsFocusedChangedEventArgs args) + { + if (args.IsFocused) + { + if (Omnibar.CurrentSelectedMode == OmnibarPathMode) + { + ViewModel.PathText = string.IsNullOrEmpty(ContentPageContext.ShellPage?.ShellViewModel?.WorkingDirectory) + ? Constants.UserEnvironmentPaths.HomePath + : ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory; + + await DispatcherQueue.EnqueueOrInvokeAsync(async () => + { + await ViewModel.PopulateOmnibarSuggestionsForPathMode(); + }); + } + else if (Omnibar.CurrentSelectedMode == OmnibarCommandPaletteMode) + { + ViewModel.OmnibarCommandPaletteModeText = string.Empty; + + if (ViewModel.OmnibarCommandPaletteModeSuggestionItems.Count is 0) + { + await DispatcherQueue.EnqueueOrInvokeAsync(() => + { + ViewModel.PopulateOmnibarSuggestionsForCommandPaletteMode(); + }); + } + } + else if (Omnibar.CurrentSelectedMode == OmnibarSearchMode) + { + + } + } } private async void Omnibar_PreviewKeyDown(object sender, KeyRoutedEventArgs e) diff --git a/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs b/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs index eb6d1590cdde..faa79474a8c1 100644 --- a/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs @@ -78,6 +78,8 @@ public sealed partial class NavigationToolbarViewModel : ObservableObject, IAddr internal ObservableCollection OmnibarCommandPaletteModeSuggestionItems { get; } = []; + internal ObservableCollection OmnibarSearchModeSuggestionItems { get; } = []; + public bool IsSingleItemOverride { get; set; } public bool SearchHasFocus { get; private set; } @@ -231,66 +233,14 @@ public string? PathText private string? _OmnibarCommandPaletteModeText; public string? OmnibarCommandPaletteModeText { get => _OmnibarCommandPaletteModeText; set => SetProperty(ref _OmnibarCommandPaletteModeText, value); } - private bool _IsOmnibarFocused; - public bool IsOmnibarFocused - { - get => _IsOmnibarFocused; - set - { - // NOTE: Don't call ObservableObject.SetProperty() here since we don't want to change focus logic outside of the control. - - _IsOmnibarFocused = value; - - if (value) - { - switch (OmnibarCurrentSelectedModeName) - { - 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 string? _OmnibarSearchModeText; + public string? OmnibarSearchModeText { get => _OmnibarSearchModeText; set => SetProperty(ref _OmnibarSearchModeText, 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; - } - } - } + set => SetProperty(ref _OmnibarCurrentSelectedModeName, value); } private CurrentInstanceViewModel _InstanceViewModel; @@ -1100,8 +1050,6 @@ private static async Task LaunchApplicationFromPath(string currentInput, s public async Task PopulateOmnibarSuggestionsForPathMode() { - PathModeSuggestionItems.Clear(); - var result = await SafetyExtensions.IgnoreExceptions((Func>)(async () => { List? newSuggestions = []; @@ -1200,49 +1148,41 @@ void AddNoResultsItem() public void PopulateOmnibarSuggestionsForCommandPaletteMode() { - OmnibarCommandPaletteModeText ??= string.Empty; - OmnibarCommandPaletteModeSuggestionItems.Clear(); - if (ContentPageContext.SelectedItems.Count == 1 && ContentPageContext.SelectedItem is not null && !ContentPageContext.SelectedItem.IsFolder) { - var dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread(); - - dispatcherQueue.TryEnqueue(() => + try { - try + var selectedItemPath = ContentPageContext.SelectedItem.ItemPath; + var fileActionEntity = ActionManager.Instance.EntityFactory.CreateFileEntity(selectedItemPath); + var actions = ActionManager.Instance.ActionRuntime.ActionCatalog.GetActionsForInputs(new[] { fileActionEntity }); + + foreach (var action in actions.Where(a => a.Definition.Description.Contains(OmnibarCommandPaletteModeText, StringComparison.OrdinalIgnoreCase))) { - var selectedItemPath = ContentPageContext.SelectedItem.ItemPath; - var fileActionEntity = ActionManager.Instance.EntityFactory.CreateFileEntity(selectedItemPath); - var actions = ActionManager.Instance.ActionRuntime.ActionCatalog.GetActionsForInputs(new[] { fileActionEntity }); + var newItem = new NavigationBarSuggestionItem + { + PrimaryDisplay = action.Definition.Description, + SearchText = OmnibarCommandPaletteModeText, + ActionInstance = action + }; - foreach (var action in actions.Where(a => a.Definition.Description.Contains(OmnibarCommandPaletteModeText, StringComparison.OrdinalIgnoreCase))) + if (Uri.TryCreate(action.Definition.IconFullPath, UriKind.RelativeOrAbsolute, out Uri? validUri)) { - var newItem = new NavigationBarSuggestionItem + try { - PrimaryDisplay = action.Definition.Description, - SearchText = OmnibarCommandPaletteModeText, - ActionInstance = action - }; - - if (Uri.TryCreate(action.Definition.IconFullPath, UriKind.RelativeOrAbsolute, out Uri? validUri)) + newItem.ActionIconSource = new BitmapImage(validUri); + } + catch (Exception) { - try - { - newItem.ActionIconSource = new BitmapImage(validUri); - } - catch (Exception) - { - } } - - OmnibarCommandPaletteModeSuggestionItems.Add(newItem); } + + OmnibarCommandPaletteModeSuggestionItems.Add(newItem); } - catch (Exception ex) - { - App.Logger.LogWarning(ex, ex.Message); - } - }); + } + catch (Exception ex) + { + App.Logger.LogWarning(ex, ex.Message); + } } var suggestionItems = Commands