From dba4123677b7fbc8a3972caf8a4385f6474c4e96 Mon Sep 17 00:00:00 2001 From: 0x5BFA <62196528+0x5bfa@users.noreply.github.com> Date: Fri, 4 Jul 2025 13:52:45 +0900 Subject: [PATCH 1/4] FIxed "The mode change cuases dead-lock in the UI thread" --- src/Files.App.Controls/Omnibar/EventArgs.cs | 2 + .../Omnibar/Omnibar.Events.cs | 3 + src/Files.App.Controls/Omnibar/Omnibar.cs | 1 + .../UserControls/NavigationToolbar.xaml | 40 +++++- .../UserControls/NavigationToolbar.xaml.cs | 58 ++++++++- .../NavigationToolbarViewModel.cs | 118 +++++------------- 6 files changed, 128 insertions(+), 94 deletions(-) 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/UserControls/NavigationToolbar.xaml b/src/Files.App/UserControls/NavigationToolbar.xaml index 5d4a2db52e38..092eff11edde 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" @@ -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..cd1c177f954f 100644 --- a/src/Files.App/UserControls/NavigationToolbar.xaml.cs +++ b/src/Files.App/UserControls/NavigationToolbar.xaml.cs @@ -428,11 +428,63 @@ 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; + + 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 From bbd8fabede52074a0bb02c7d22e6061788782e93 Mon Sep 17 00:00:00 2001 From: 0x5BFA <62196528+0x5bfa@users.noreply.github.com> Date: Fri, 4 Jul 2025 14:07:02 +0900 Subject: [PATCH 2/4] Update the margin of the keyboard UI in the palette suggestions & fixed the mode button's height --- src/Files.App.Controls/Omnibar/Omnibar.xaml | 1 + src/Files.App/UserControls/NavigationToolbar.xaml | 1 + 2 files changed, 2 insertions(+) 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 092eff11edde..78e2b6b1fa87 100644 --- a/src/Files.App/UserControls/NavigationToolbar.xaml +++ b/src/Files.App/UserControls/NavigationToolbar.xaml @@ -445,6 +445,7 @@ From 9b5a8d6d6026fece283110b53d6cfa8fb22c6e65 Mon Sep 17 00:00:00 2001 From: 0x5BFA <62196528+0x5bfa@users.noreply.github.com> Date: Tue, 8 Jul 2025 10:32:54 +0900 Subject: [PATCH 3/4] Req --- .../UserControls/NavigationToolbar.xaml | 5 ++--- .../UserControls/NavigationToolbar.xaml.cs | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml b/src/Files.App/UserControls/NavigationToolbar.xaml index 78e2b6b1fa87..1792e7dda15d 100644 --- a/src/Files.App/UserControls/NavigationToolbar.xaml +++ b/src/Files.App/UserControls/NavigationToolbar.xaml @@ -412,9 +412,9 @@ UpdateTextOnSelect="False"> - + - + @@ -445,7 +445,6 @@ diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml.cs b/src/Files.App/UserControls/NavigationToolbar.xaml.cs index cd1c177f954f..132564606ca8 100644 --- a/src/Files.App/UserControls/NavigationToolbar.xaml.cs +++ b/src/Files.App/UserControls/NavigationToolbar.xaml.cs @@ -466,19 +466,25 @@ private async void Omnibar_IsFocusedChanged(Omnibar sender, OmnibarIsFocusedChan ? Constants.UserEnvironmentPaths.HomePath : ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory; - await DispatcherQueue.EnqueueOrInvokeAsync(async () => + if (ViewModel.PathModeSuggestionItems.Count is 0) { - await ViewModel.PopulateOmnibarSuggestionsForPathMode(); - }); + await DispatcherQueue.EnqueueOrInvokeAsync(async () => + { + await ViewModel.PopulateOmnibarSuggestionsForPathMode(); + }); + } } else if (Omnibar.CurrentSelectedMode == OmnibarCommandPaletteMode) { ViewModel.OmnibarCommandPaletteModeText = string.Empty; - await DispatcherQueue.EnqueueOrInvokeAsync(() => + if (ViewModel.OmnibarCommandPaletteModeSuggestionItems.Count is 0) { - ViewModel.PopulateOmnibarSuggestionsForCommandPaletteMode(); - }); + await DispatcherQueue.EnqueueOrInvokeAsync(() => + { + ViewModel.PopulateOmnibarSuggestionsForCommandPaletteMode(); + }); + } } else if (Omnibar.CurrentSelectedMode == OmnibarSearchMode) { From 1037964ffcbfbaf36589a7d569b11f6d1eaa7d36 Mon Sep 17 00:00:00 2001 From: 0x5BFA <62196528+0x5bfa@users.noreply.github.com> Date: Tue, 8 Jul 2025 11:50:31 +0900 Subject: [PATCH 4/4] Req --- src/Files.App/UserControls/NavigationToolbar.xaml | 2 +- src/Files.App/UserControls/NavigationToolbar.xaml.cs | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml b/src/Files.App/UserControls/NavigationToolbar.xaml index 1792e7dda15d..53dec5082945 100644 --- a/src/Files.App/UserControls/NavigationToolbar.xaml +++ b/src/Files.App/UserControls/NavigationToolbar.xaml @@ -412,7 +412,7 @@ UpdateTextOnSelect="False"> - + diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml.cs b/src/Files.App/UserControls/NavigationToolbar.xaml.cs index 132564606ca8..2ec9dda88d35 100644 --- a/src/Files.App/UserControls/NavigationToolbar.xaml.cs +++ b/src/Files.App/UserControls/NavigationToolbar.xaml.cs @@ -466,13 +466,10 @@ private async void Omnibar_IsFocusedChanged(Omnibar sender, OmnibarIsFocusedChan ? Constants.UserEnvironmentPaths.HomePath : ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory; - if (ViewModel.PathModeSuggestionItems.Count is 0) + await DispatcherQueue.EnqueueOrInvokeAsync(async () => { - await DispatcherQueue.EnqueueOrInvokeAsync(async () => - { - await ViewModel.PopulateOmnibarSuggestionsForPathMode(); - }); - } + await ViewModel.PopulateOmnibarSuggestionsForPathMode(); + }); } else if (Omnibar.CurrentSelectedMode == OmnibarCommandPaletteMode) {