From b9d269809b6b13fde2c511d4685843ff297baf32 Mon Sep 17 00:00:00 2001 From: 0x5BFA <62196528+0x5bfa@users.noreply.github.com> Date: Sun, 6 Apr 2025 16:54:34 +0900 Subject: [PATCH 1/4] Init --- .../Omnibar/Omnibar.Events.cs | 7 +- .../Omnibar/Omnibar.Properties.cs | 16 + src/Files.App.Controls/Omnibar/Omnibar.cs | 23 +- src/Files.App.Controls/Omnibar/Omnibar.xaml | 1 - .../Omnibar/OmnibarMode.Properties.cs | 13 +- .../Data/Items/NavigationBarSuggestionItem.cs | 1 + .../Data/Models/BreadcrumbBarItemModel.cs | 7 + .../Models/OmnibarPathModeSuggestionModel.cs | 20 ++ src/Files.App/Strings/en-US/Resources.resw | 3 + .../UserControls/NavigationToolbar.xaml | 123 +++++++- .../UserControls/NavigationToolbar.xaml.cs | 142 ++++++--- .../UserControls/PathBreadcrumb.xaml.cs | 10 +- .../NavigationToolbarViewModel.cs | 284 ++++++++++++++++-- src/Files.App/Views/Shells/BaseShellPage.cs | 7 +- 14 files changed, 559 insertions(+), 98 deletions(-) create mode 100644 src/Files.App/Data/Models/BreadcrumbBarItemModel.cs create mode 100644 src/Files.App/Data/Models/OmnibarPathModeSuggestionModel.cs diff --git a/src/Files.App.Controls/Omnibar/Omnibar.Events.cs b/src/Files.App.Controls/Omnibar/Omnibar.Events.cs index 06161def1f95..ebd4f5bcb457 100644 --- a/src/Files.App.Controls/Omnibar/Omnibar.Events.cs +++ b/src/Files.App.Controls/Omnibar/Omnibar.Events.cs @@ -16,7 +16,7 @@ private void Omnibar_SizeChanged(object sender, SizeChangedEventArgs e) private void AutoSuggestBox_GotFocus(object sender, RoutedEventArgs e) { - _isFocused = true; + IsFocused = true; VisualStateManager.GoToState(CurrentSelectedMode, "Focused", true); VisualStateManager.GoToState(_textBox, "InputAreaVisible", true); @@ -30,7 +30,7 @@ private void AutoSuggestBox_LostFocus(object sender, RoutedEventArgs e) if (_textBox.ContextFlyout.IsOpen) return; - _isFocused = false; + IsFocused = false; if (CurrentSelectedMode?.ContentOnInactive is not null) { @@ -92,7 +92,8 @@ private void AutoSuggestBox_KeyDown(object sender, KeyRoutedEventArgs e) private void AutoSuggestBox_TextChanged(object sender, TextChangedEventArgs e) { - CurrentSelectedMode!.Text = _textBox.Text; + if (string.Compare(_textBox.Text, CurrentSelectedMode!.Text, StringComparison.OrdinalIgnoreCase) is not 0) + CurrentSelectedMode!.Text = _textBox.Text; // UpdateSuggestionListView(); diff --git a/src/Files.App.Controls/Omnibar/Omnibar.Properties.cs b/src/Files.App.Controls/Omnibar/Omnibar.Properties.cs index e530e55e69fd..d4d8ff449cab 100644 --- a/src/Files.App.Controls/Omnibar/Omnibar.Properties.cs +++ b/src/Files.App.Controls/Omnibar/Omnibar.Properties.cs @@ -13,7 +13,23 @@ public partial class Omnibar [GeneratedDependencyProperty] public partial OmnibarMode? CurrentSelectedMode { get; set; } + [GeneratedDependencyProperty] + public partial string? CurrentSelectedModeName { get; set; } + [GeneratedDependencyProperty] public partial Thickness AutoSuggestBoxPadding { get; set; } + + [GeneratedDependencyProperty] + public partial bool IsFocused { get; set; } + + partial void OnCurrentSelectedModeChanged(OmnibarMode? newValue) + { + CurrentSelectedModeName = newValue?.ModeName; + } + + partial void OnIsFocusedChanged(bool newValue) + { + //_textBox?.Focus(newValue ? FocusState.Programmatic : FocusState.Unfocused); + } } } diff --git a/src/Files.App.Controls/Omnibar/Omnibar.cs b/src/Files.App.Controls/Omnibar/Omnibar.cs index 9f3d5fae3710..fe8c2e20b2da 100644 --- a/src/Files.App.Controls/Omnibar/Omnibar.cs +++ b/src/Files.App.Controls/Omnibar/Omnibar.cs @@ -28,7 +28,6 @@ public partial class Omnibar : Control private Border _textBoxSuggestionsContainerBorder = null!; private ListView _textBoxSuggestionsListView = null!; - private bool _isFocused; private string _userInput = string.Empty; private OmnibarTextChangeReason _textChangeReason = OmnibarTextChangeReason.None; @@ -148,7 +147,7 @@ public void ChangeMode(OmnibarMode modeToExpand, bool shouldFocus = false, bool CurrentSelectedMode = modeToExpand; _textChangeReason = OmnibarTextChangeReason.ProgrammaticChange; - _textBox.Text = CurrentSelectedMode.Text ?? string.Empty; + ChangeTextBoxText(CurrentSelectedMode.Text ?? string.Empty); // Move cursor of the TextBox to the tail _textBox.Select(_textBox.Text.Length, 0); @@ -156,7 +155,7 @@ public void ChangeMode(OmnibarMode modeToExpand, bool shouldFocus = false, bool VisualStateManager.GoToState(CurrentSelectedMode, "Focused", true); CurrentSelectedMode.OnChangingCurrentMode(true); - if (_isFocused) + if (IsFocused) { VisualStateManager.GoToState(CurrentSelectedMode, "Focused", true); VisualStateManager.GoToState(_textBox, "InputAreaVisible", true); @@ -174,7 +173,7 @@ public void ChangeMode(OmnibarMode modeToExpand, bool shouldFocus = false, bool if (shouldFocus) _textBox.Focus(FocusState.Keyboard); - TryToggleIsSuggestionsPopupOpen(_isFocused && CurrentSelectedMode?.SuggestionItemsSource is not null); + TryToggleIsSuggestionsPopupOpen(IsFocused && CurrentSelectedMode?.SuggestionItemsSource is not null); // Remove the reposition transition from the all modes if (useTransition) @@ -189,7 +188,7 @@ public void ChangeMode(OmnibarMode modeToExpand, bool shouldFocus = false, bool public bool TryToggleIsSuggestionsPopupOpen(bool wantToOpen) { - if (wantToOpen && (!_isFocused || CurrentSelectedMode?.SuggestionItemsSource is null)) + if (wantToOpen && (!IsFocused || CurrentSelectedMode?.SuggestionItemsSource is null)) return false; _textBoxSuggestionsPopup.IsOpen = wantToOpen; @@ -205,10 +204,15 @@ public void ChooseSuggestionItem(object obj) if (CurrentSelectedMode.UpdateTextOnSelect) { _textChangeReason = OmnibarTextChangeReason.SuggestionChosen; - _textBox.Text = GetObjectText(obj); + ChangeTextBoxText(GetObjectText(obj)); } SuggestionChosen?.Invoke(this, new(CurrentSelectedMode, obj)); + } + + internal protected void ChangeTextBoxText(string text) + { + _textBox.Text = text; // Move the cursor to the end of the TextBox _textBox?.Select(_textBox.Text.Length, 0); @@ -233,7 +237,7 @@ private string GetObjectText(object obj) return obj is string text ? text : obj is IOmnibarTextMemberPathProvider textMemberPathProvider - ? textMemberPathProvider.GetTextMemberPath(CurrentSelectedMode.DisplayMemberPath ?? string.Empty) + ? textMemberPathProvider.GetTextMemberPath(CurrentSelectedMode.TextMemberPath ?? string.Empty) : obj.ToString() ?? string.Empty; } @@ -245,10 +249,7 @@ private void RevertTextToUserInput() _textBoxSuggestionsListView.SelectedIndex = -1; _textChangeReason = OmnibarTextChangeReason.ProgrammaticChange; - _textBox.Text = _userInput ?? ""; - - // Move the cursor to the end of the TextBox - _textBox?.Select(_textBox.Text.Length, 0); + ChangeTextBoxText(_userInput ?? ""); } } } diff --git a/src/Files.App.Controls/Omnibar/Omnibar.xaml b/src/Files.App.Controls/Omnibar/Omnibar.xaml index 439ec2674897..64eabed99947 100644 --- a/src/Files.App.Controls/Omnibar/Omnibar.xaml +++ b/src/Files.App.Controls/Omnibar/Omnibar.xaml @@ -133,7 +133,6 @@ Height="{TemplateBinding Height}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Background="{TemplateBinding Background}" - CornerRadius="{TemplateBinding CornerRadius}" TabFocusNavigation="Local"> + /// Implement in to get the text member path from the suggestion item correctly. + /// + public partial string? TextMemberPath { get; set; } [GeneratedDependencyProperty(DefaultValue = true)] public partial bool UpdateTextOnSelect { get; set; } + + partial void OnTextChanged(string? newValue) + { + if (_ownerRef is null || _ownerRef.TryGetTarget(out var owner) is false) + return; + + owner.ChangeTextBoxText(newValue ?? string.Empty); + } } } diff --git a/src/Files.App/Data/Items/NavigationBarSuggestionItem.cs b/src/Files.App/Data/Items/NavigationBarSuggestionItem.cs index 46912d9ed444..35970397d594 100644 --- a/src/Files.App/Data/Items/NavigationBarSuggestionItem.cs +++ b/src/Files.App/Data/Items/NavigationBarSuggestionItem.cs @@ -3,6 +3,7 @@ namespace Files.App.Data.Items { + [Obsolete("Remove once Omnibar goes out of experimental.")] public sealed partial class NavigationBarSuggestionItem : ObservableObject { private string? _Text; diff --git a/src/Files.App/Data/Models/BreadcrumbBarItemModel.cs b/src/Files.App/Data/Models/BreadcrumbBarItemModel.cs new file mode 100644 index 000000000000..d8620ca2ba79 --- /dev/null +++ b/src/Files.App/Data/Models/BreadcrumbBarItemModel.cs @@ -0,0 +1,7 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +namespace Files.App.Data.Models +{ + internal record BreadcrumbBarItemModel(string Text); +} diff --git a/src/Files.App/Data/Models/OmnibarPathModeSuggestionModel.cs b/src/Files.App/Data/Models/OmnibarPathModeSuggestionModel.cs new file mode 100644 index 000000000000..4142d00f0941 --- /dev/null +++ b/src/Files.App/Data/Models/OmnibarPathModeSuggestionModel.cs @@ -0,0 +1,20 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +using Files.App.Controls; + +namespace Files.App.Data.Models +{ + internal record OmnibarPathModeSuggestionModel(string Path, string DisplayName) : IOmnibarTextMemberPathProvider + { + public string GetTextMemberPath(string textMemberPath) + { + return textMemberPath switch + { + nameof(Path) => Path, + nameof(DisplayName) => DisplayName, + _ => string.Empty + }; + } + } +} diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw index d30aeb398fa4..16e341e71349 100644 --- a/src/Files.App/Strings/en-US/Resources.resw +++ b/src/Files.App/Strings/en-US/Resources.resw @@ -4202,4 +4202,7 @@ Drag files or folders here to interact with them across different tabs + + Enter a path to navigate to... + \ No newline at end of file diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml b/src/Files.App/UserControls/NavigationToolbar.xaml index e416a23d7492..7fe8371ec8e5 100644 --- a/src/Files.App/UserControls/NavigationToolbar.xaml +++ b/src/Files.App/UserControls/NavigationToolbar.xaml @@ -9,6 +9,8 @@ xmlns:converters="using:Files.App.Converters" xmlns:converters1="using:CommunityToolkit.WinUI.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:dataitems="using:Files.App.Data.Items" + xmlns:datamodels="using:Files.App.Data.Models" xmlns:helpers="using:Files.App.Helpers" xmlns:items="using:Files.App.Data.Items" xmlns:keyboard="using:Files.App.UserControls.KeyboardShortcut" @@ -211,6 +213,7 @@ + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (HistoryItemClicked); } + // Methods + private void NavToolbar_Loading(FrameworkElement _, object e) { Loading -= NavToolbar_Loading; @@ -104,7 +99,7 @@ private void VisiblePath_LostFocus(object _, RoutedEventArgs e) if (App.AppModel.IsMainWindowClosed) return; - var element = FocusManager.GetFocusedElement(MainWindow.Instance.Content.XamlRoot); + var element = Microsoft.UI.Xaml.Input.FocusManager.GetFocusedElement(MainWindow.Instance.Content.XamlRoot); if (element is FlyoutBase or AppBarButton or Popup) return; @@ -195,9 +190,9 @@ private async Task AddHistoryItemsAsync(IEnumerable items, IList var flyoutItem = new MenuFlyoutItem { - Icon = new FontIcon { Glyph = "\uE8B7" }, // Use font icon as placeholder + Icon = new FontIcon() { Glyph = "\uE8B7" }, // Placeholder icon Text = fileName, - Command = historyItemClickedCommand, + Command = new RelayCommand(HistoryItemClicked), CommandParameter = new ToolbarHistoryItemModel(item, isBackMode) }; @@ -205,58 +200,115 @@ private async Task AddHistoryItemsAsync(IEnumerable items, IList // Start loading the thumbnail in the background _ = LoadFlyoutItemIconAsync(flyoutItem, args.NavPathParam); + + async Task LoadFlyoutItemIconAsync(MenuFlyoutItem flyoutItem, string path) + { + var imageSource = await NavigationHelpers.GetIconForPathAsync(path); + + if (imageSource is not null) + flyoutItem.Icon = new ImageIcon() { Source = imageSource }; + } + + void HistoryItemClicked(ToolbarHistoryItemModel? itemModel) + { + if (itemModel is null) + return; + + var shellPage = Ioc.Default.GetRequiredService().ShellPage; + if (shellPage is null) + return; + + if (itemModel.IsBackMode) + { + // Remove all entries after the target entry in the BackwardStack + while (shellPage.BackwardStack.Last() != itemModel.PageStackEntry) + { + shellPage.BackwardStack.RemoveAt(shellPage.BackwardStack.Count - 1); + } + + // Navigate back + shellPage.Back_Click(); + } + else + { + // Remove all entries before the target entry in the ForwardStack + while (shellPage.ForwardStack.First() != itemModel.PageStackEntry) + { + shellPage.ForwardStack.RemoveAt(0); + } + + // Navigate forward + shellPage.Forward_Click(); + } + } } } - private async Task LoadFlyoutItemIconAsync(MenuFlyoutItem flyoutItem, string path) + private void ClickablePath_GettingFocus(UIElement sender, GettingFocusEventArgs args) { - var imageSource = await NavigationHelpers.GetIconForPathAsync(path); + if (args.InputDevice != FocusInputDeviceKind.Keyboard) + return; - if (imageSource is not null) - flyoutItem.Icon = new ImageIcon { Source = imageSource }; + var previousControl = args.OldFocusedElement as FrameworkElement; + if (previousControl?.Name == nameof(HomeButton) || previousControl?.Name == nameof(Refresh)) + ViewModel.IsEditModeEnabled = true; } - private void HistoryItemClicked(ToolbarHistoryItemModel? itemModel) + private async void Omnibar_QuerySubmitted(Omnibar sender, OmnibarQuerySubmittedEventArgs args) { - if (itemModel is null) - return; + await ViewModel.HandleItemNavigationAsync(args.Text); + } - var shellPage = Ioc.Default.GetRequiredService().ShellPage; - if (shellPage is null) - return; + private async void Omnibar_SuggestionChosen(Omnibar sender, OmnibarSuggestionChosenEventArgs args) + { + if (args.SelectedItem is OmnibarPathModeSuggestionModel item && + !string.IsNullOrEmpty(item.Path)) + await ViewModel.HandleItemNavigationAsync(item.Path); + } - if (itemModel.IsBackMode) - { - // Remove all entries after the target entry in the BackwardStack - while (shellPage.BackwardStack.Last() != itemModel.PageStackEntry) - { - shellPage.BackwardStack.RemoveAt(shellPage.BackwardStack.Count - 1); - } + private async void Omnibar_TextChanged(Omnibar sender, OmnibarTextChangedEventArgs args) + { + await ViewModel.PopulateOmnibarSuggestionsForPathMode(); + } - // Navigate back - shellPage.Back_Click(); - } - else + private async void BreadcrumbBar_ItemClicked(Controls.BreadcrumbBar sender, Controls.BreadcrumbBarItemClickedEventArgs args) + { + if (args.IsRootItem) { - // Remove all entries before the target entry in the ForwardStack - while (shellPage.ForwardStack.First() != itemModel.PageStackEntry) - { - shellPage.ForwardStack.RemoveAt(0); - } - - // Navigate forward - shellPage.Forward_Click(); + await ViewModel.HandleItemNavigationAsync("Home"); + return; } + + await ViewModel.HandleFolderNavigationAsync(ViewModel.PathComponents[args.Index].Path); } - private void ClickablePath_GettingFocus(UIElement sender, GettingFocusEventArgs args) + private async void BreadcrumbBar_ItemDropDownFlyoutOpening(object sender, BreadcrumbBarItemDropDownFlyoutEventArgs e) { - if (args.InputDevice != FocusInputDeviceKind.Keyboard) + if (e.IsRootItem) + { + // TODO: Populate a different flyout for the root item + e.Flyout.Items.Add(new MenuFlyoutHeaderItem() { Text = "Quick access" }); + e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Desktop" }); + e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Download" }); + e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Documents" }); + e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Pictures" }); + e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Music" }); + e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Videos" }); + e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Recycle bin" }); + e.Flyout.Items.Add(new MenuFlyoutHeaderItem() { Text = "Drives" }); + e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Local Disk (C:)" }); + e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Local Disk (D:)" }); + return; + } - var previousControl = args.OldFocusedElement as FrameworkElement; - if (previousControl?.Name == nameof(HomeButton) || previousControl?.Name == nameof(Refresh)) - ViewModel.IsEditModeEnabled = true; + await ViewModel.SetPathBoxDropDownFlyoutAsync(e.Flyout, ViewModel.PathComponents[e.Index]); + } + + private void BreadcrumbBar_ItemDropDownFlyoutClosed(object sender, BreadcrumbBarItemDropDownFlyoutEventArgs e) + { + // Clear the flyout items to save memory + e.Flyout.Items.Clear(); } } } diff --git a/src/Files.App/UserControls/PathBreadcrumb.xaml.cs b/src/Files.App/UserControls/PathBreadcrumb.xaml.cs index bb08408b5eaa..66726ee9e82b 100644 --- a/src/Files.App/UserControls/PathBreadcrumb.xaml.cs +++ b/src/Files.App/UserControls/PathBreadcrumb.xaml.cs @@ -50,7 +50,15 @@ private async void PathBoxItem_Drop(object sender, DragEventArgs e) private async void PathBoxItem_Tapped(object sender, TappedRoutedEventArgs e) { - await ViewModel.PathBoxItem_Tapped(sender, e); + if (sender is not TextBlock textBlock || + textBlock.DataContext is not PathBoxItem item || + item.Path is not { } path) + return; + + // TODO: Implement middle click retrieving. + await ViewModel.HandleFolderNavigationAsync(path); + + e.Handled = true; } private void PathBoxItem_PointerPressed(object sender, PointerRoutedEventArgs e) diff --git a/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs b/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs index 05e632463d26..4b588a54167a 100644 --- a/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs @@ -3,6 +3,7 @@ using CommunityToolkit.WinUI; using Files.App.Actions; +using Files.App.Controls; using Files.Shared.Helpers; using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; @@ -22,6 +23,10 @@ public sealed partial class NavigationToolbarViewModel : ObservableObject, IAddr private const int MaxSuggestionsCount = 10; + public const string OmnibarPathModeName = "Path"; + public const string OmnibarPaletteModeName = "Palette"; + public const string OmnibarSearchModeName = "Search"; + // Dependency injections private readonly IUserSettingsService UserSettingsService = Ioc.Default.GetRequiredService(); @@ -30,6 +35,7 @@ public sealed partial class NavigationToolbarViewModel : ObservableObject, IAddr private readonly DrivesViewModel drivesViewModel = Ioc.Default.GetRequiredService(); private readonly IUpdateService UpdateService = Ioc.Default.GetRequiredService(); private readonly ICommandManager Commands = Ioc.Default.GetRequiredService(); + private readonly IContentPageContext ContentPageContext = Ioc.Default.GetRequiredService(); // Fields @@ -63,6 +69,8 @@ public sealed partial class NavigationToolbarViewModel : ObservableObject, IAddr public ObservableCollection NavigationBarSuggestions { get; } = []; + internal ObservableCollection PathModeSuggestionItems { get; } = []; + public bool IsSingleItemOverride { get; set; } public bool SearchHasFocus { get; private set; } @@ -199,16 +207,55 @@ public bool IsSearchBoxVisible } private string? _PathText; + [Obsolete("Remove once Omnibar goes out of experimental.")] public string? PathText { get => _PathText; set { - _PathText = value; - OnPropertyChanged(nameof(PathText)); + if (SetProperty(ref _PathText, value)) + OnPropertyChanged(nameof(OmnibarPathModeText)); + } + } + + private bool _IsOmnibarFocused; + public bool IsOmnibarFocused + { + get => _IsOmnibarFocused; + set + { + if (SetProperty(ref _IsOmnibarFocused, value)) + { + if (value) + { + switch(OmnibarCurrentSelectedModeName) + { + case OmnibarPathModeName: + OmnibarPathModeText = + string.IsNullOrEmpty(ContentPageContext.ShellPage?.ShellViewModel?.WorkingDirectory) + ? Constants.UserEnvironmentPaths.HomePath + : ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory; + _ = PopulateOmnibarSuggestionsForPathMode(); + break; + case OmnibarPaletteModeName: + break; + case OmnibarSearchModeName: + break; + default: + throw new ArgumentOutOfRangeException(""); + } + + } + } } } + private string _OmnibarCurrentSelectedModeName; + public string OmnibarCurrentSelectedModeName { get => _OmnibarCurrentSelectedModeName; set => SetProperty(ref _OmnibarCurrentSelectedModeName, value); } + + private string _OmnibarPathModeText; + public string OmnibarPathModeText { get => _OmnibarPathModeText; set => SetProperty(ref _OmnibarPathModeText, value); } + private CurrentInstanceViewModel _InstanceViewModel; public CurrentInstanceViewModel InstanceViewModel { @@ -226,6 +273,7 @@ public CurrentInstanceViewModel InstanceViewModel } } + [Obsolete("Remove once Omnibar goes out of experimental.")] public bool IsEditModeEnabled { get => ManualEntryBoxLoaded; @@ -548,28 +596,124 @@ public void PathBoxItem_PointerPressed(object sender, PointerRoutedEventArgs e) _pointerRoutedEventArgs = ptrPt.Properties.IsMiddleButtonPressed ? e : null; } - public async Task PathBoxItem_Tapped(object sender, TappedRoutedEventArgs e) + public async Task HandleFolderNavigationAsync(string path, bool openNewTab = false) { - var itemTappedPath = ((sender as TextBlock)?.DataContext as PathBoxItem)?.Path; - if (itemTappedPath is null) - return; - - if (_pointerRoutedEventArgs is not null) + openNewTab |= _pointerRoutedEventArgs is not null; + if (openNewTab) { - await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(async () => - { - await NavigationHelpers.AddNewTabByPathAsync(typeof(ShellPanesPage), itemTappedPath, true); - }, DispatcherQueuePriority.Low); - e.Handled = true; + await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync( + async () => + { + await NavigationHelpers.AddNewTabByPathAsync(typeof(ShellPanesPage), path, true); + }, + DispatcherQueuePriority.Low); + _pointerRoutedEventArgs = null; return; } - ToolbarPathItemInvoked?.Invoke(this, new PathNavigationEventArgs() + ToolbarPathItemInvoked?.Invoke(this, new() { ItemPath = path }); + } + + public async Task HandleItemNavigationAsync(string path) + { + if (ContentPageContext.ShellPage is null || PathComponents.LastOrDefault()?.Path is not { } currentPath) + return; + + var isFtp = FtpHelpers.IsFtpPath(path); + var normalizedInput = NormalizePathInput(path, isFtp); + if (currentPath.Equals(normalizedInput, StringComparison.OrdinalIgnoreCase) || + string.IsNullOrWhiteSpace(normalizedInput)) + return; + + if (normalizedInput.Equals(ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory) && + ContentPageContext.ShellPage.CurrentPageType != typeof(HomePage)) + return; + + if (normalizedInput.Equals("Home", StringComparison.OrdinalIgnoreCase) || + normalizedInput.Equals(Strings.Home.GetLocalizedResource(), StringComparison.OrdinalIgnoreCase)) { - ItemPath = itemTappedPath - }); + SavePathToHistory("Home"); + ContentPageContext.ShellPage.NavigateHome(); + } + else if (normalizedInput.Equals("ReleaseNotes", StringComparison.OrdinalIgnoreCase) || + normalizedInput.Equals(Strings.ReleaseNotes.GetLocalizedResource(), StringComparison.OrdinalIgnoreCase)) + { + SavePathToHistory("ReleaseNotes"); + ContentPageContext.ShellPage.NavigateToReleaseNotes(); + } + else if (normalizedInput.Equals("Settings", StringComparison.OrdinalIgnoreCase) || + normalizedInput.Equals(Strings.Settings.GetLocalizedResource(), StringComparison.OrdinalIgnoreCase)) + { + //SavePathToHistory("Settings"); + //ContentPageContext.ShellPage.NavigateToSettings(); + } + else + { + normalizedInput = StorageFileExtensions.GetResolvedPath(normalizedInput, isFtp); + if (currentPath.Equals(normalizedInput, StringComparison.OrdinalIgnoreCase)) + return; + + var item = await FilesystemTasks.Wrap(() => DriveHelpers.GetRootFromPathAsync(normalizedInput)); + + var resFolder = await FilesystemTasks.Wrap(() => StorageFileExtensions.DangerousGetFolderWithPathFromPathAsync(normalizedInput, item)); + if (resFolder || FolderHelpers.CheckFolderAccessWithWin32(normalizedInput)) + { + var matchingDrive = drivesViewModel.Drives.Cast().FirstOrDefault(x => PathNormalization.NormalizePath(normalizedInput).StartsWith(PathNormalization.NormalizePath(x.Path), StringComparison.Ordinal)); + if (matchingDrive is not null && matchingDrive.Type == Data.Items.DriveType.CDRom && matchingDrive.MaxSpace == ByteSizeLib.ByteSize.FromBytes(0)) + { + bool ejectButton = await DialogDisplayHelper.ShowDialogAsync(Strings.InsertDiscDialog_Title.GetLocalizedResource(), string.Format(Strings.InsertDiscDialog_Text.GetLocalizedResource(), matchingDrive.Path), Strings.InsertDiscDialog_OpenDriveButton.GetLocalizedResource(), Strings.Close.GetLocalizedResource()); + if (ejectButton) + DriveHelpers.EjectDeviceAsync(matchingDrive.Path); + return; + } + + var pathToNavigate = resFolder.Result?.Path ?? normalizedInput; + SavePathToHistory(pathToNavigate); + ContentPageContext.ShellPage.NavigateToPath(pathToNavigate); + } + else if (isFtp) + { + SavePathToHistory(normalizedInput); + ContentPageContext.ShellPage.NavigateToPath(normalizedInput); + } + else // Not a folder or inaccessible + { + var resFile = await FilesystemTasks.Wrap(() => StorageFileExtensions.DangerousGetFileWithPathFromPathAsync(normalizedInput, item)); + if (resFile) + { + var pathToInvoke = resFile.Result.Path; + await Win32Helper.InvokeWin32ComponentAsync(pathToInvoke, ContentPageContext.ShellPage); + } + else // Not a file or not accessible + { + var workingDir = + string.IsNullOrEmpty(ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory) || + ContentPageContext.ShellPage.CurrentPageType == typeof(HomePage) + ? Constants.UserEnvironmentPaths.HomePath + : ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory; + + if (await LaunchApplicationFromPath(OmnibarPathModeText, workingDir)) + return; + + try + { + if (!await Windows.System.Launcher.LaunchUriAsync(new Uri(OmnibarPathModeText))) + await DialogDisplayHelper.ShowDialogAsync(Strings.InvalidItemDialogTitle.GetLocalizedResource(), + string.Format(Strings.InvalidItemDialogContent.GetLocalizedResource(), Environment.NewLine, resFolder.ErrorCode.ToString())); + } + catch (Exception ex) when (ex is UriFormatException || ex is ArgumentException) + { + await DialogDisplayHelper.ShowDialogAsync(Strings.InvalidItemDialogTitle.GetLocalizedResource(), + string.Format(Strings.InvalidItemDialogContent.GetLocalizedResource(), Environment.NewLine, resFolder.ErrorCode.ToString())); + } + } + } + } + + PathControlDisplayText = ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory; + IsOmnibarFocused = false; } public void PathBoxItem_PreviewKeyDown(object sender, KeyRoutedEventArgs e) @@ -677,12 +821,12 @@ public void SearchRegion_LostFocus(object sender, RoutedEventArgs e) private void SearchRegion_Escaped(object? sender, ISearchBoxViewModel _SearchBox) => CloseSearchBox(true); - public async Task SetPathBoxDropDownFlyoutAsync(MenuFlyout flyout, PathBoxItem pathItem, IShellPage shellPage) + public async Task SetPathBoxDropDownFlyoutAsync(MenuFlyout flyout, PathBoxItem pathItem) { var nextPathItemTitle = PathComponents[PathComponents.IndexOf(pathItem) + 1].Title; IList? childFolders = null; - StorageFolderWithPath folder = await shellPage.ShellViewModel.GetFolderWithPathFromPathAsync(pathItem.Path); + StorageFolderWithPath folder = await ContentPageContext.ShellPage.ShellViewModel.GetFolderWithPathFromPathAsync(pathItem.Path); if (folder is not null) childFolders = (await FilesystemTasks.Wrap(() => folder.GetFoldersWithPathAsync(string.Empty))).Result; @@ -723,7 +867,7 @@ public async Task SetPathBoxDropDownFlyoutAsync(MenuFlyout flyout, PathBoxItem p flyoutItem.Click += (sender, args) => { // Navigate to the directory - shellPage.NavigateToPath(childFolder.Path); + ContentPageContext.ShellPage.NavigateToPath(childFolder.Path); }; } @@ -755,6 +899,7 @@ private static string NormalizePathInput(string currentInput, bool isFtp) return currentInput; } + [Obsolete("Remove once Omnibar goes out of experimental.")] public async Task CheckPathInputAsync(string currentInput, string currentSelectedPath, IShellPage shellPage) { if (currentInput.StartsWith('>')) @@ -885,6 +1030,107 @@ private static async Task LaunchApplicationFromPath(string currentInput, s ); } + public async Task PopulateOmnibarSuggestionsForPathMode() + { + var result = await SafetyExtensions.IgnoreExceptions(async () => + { + List? newSuggestions = []; + var pathText = OmnibarPathModeText; + + // If the current input is special, populate navigation history instead. + if (string.IsNullOrWhiteSpace(pathText) || + pathText is "Home" or "ReleaseNotes" or "Settings") + { + // Load previously entered path + if (UserSettingsService.GeneralSettingsService.PathHistoryList is { } pathHistoryList) + { + newSuggestions.AddRange(pathHistoryList.Select(x => new OmnibarPathModeSuggestionModel(x, x))); + } + } + else + { + var isFtp = FtpHelpers.IsFtpPath(pathText); + pathText = NormalizePathInput(pathText, isFtp); + var expandedPath = StorageFileExtensions.GetResolvedPath(pathText, isFtp); + var folderPath = PathNormalization.GetParentDir(expandedPath) ?? expandedPath; + StorageFolderWithPath folder = await ContentPageContext.ShellPage.ShellViewModel.GetFolderWithPathFromPathAsync(folderPath); + if (folder is null) + return false; + + var currPath = await folder.GetFoldersWithPathAsync(Path.GetFileName(expandedPath), MaxSuggestionsCount); + if (currPath.Count >= MaxSuggestionsCount) + { + newSuggestions.AddRange(currPath.Select(x => new OmnibarPathModeSuggestionModel(x.Path, x.Item.DisplayName))); + } + else if (currPath.Any()) + { + var subPath = await currPath.First().GetFoldersWithPathAsync((uint)(MaxSuggestionsCount - currPath.Count)); + newSuggestions.AddRange(currPath.Select(x => new OmnibarPathModeSuggestionModel(x.Path, x.Item.DisplayName))); + newSuggestions.AddRange(subPath.Select(x => new OmnibarPathModeSuggestionModel(x.Path, PathNormalization.Combine(currPath.First().Item.DisplayName, x.Item.DisplayName)))); + } + } + + // If there are no suggestions, show "No suggestions" + if (newSuggestions.Count is 0) + { + AddNoResultsItem(); + } + + // Check whether at least one item is in common between the old and the new suggestions + // since the suggestions popup becoming empty causes flickering + if (!PathModeSuggestionItems.IntersectBy(newSuggestions, x => x.DisplayName).Any()) + { + // No items in common, update the list in-place + for (int index = 0; index < newSuggestions.Count; index++) + { + if (index < PathModeSuggestionItems.Count) + { + PathModeSuggestionItems[index] = newSuggestions[index]; + } + else + { + PathModeSuggestionItems.Add(newSuggestions[index]); + } + } + + while (PathModeSuggestionItems.Count > newSuggestions.Count) + PathModeSuggestionItems.RemoveAt(PathModeSuggestionItems.Count - 1); + } + else + { + // At least an element in common, show animation + foreach (var s in PathModeSuggestionItems.ExceptBy(newSuggestions, x => x.DisplayName).ToList()) + PathModeSuggestionItems.Remove(s); + + for (int index = 0; index < newSuggestions.Count; index++) + { + if (PathModeSuggestionItems.Count > index && PathModeSuggestionItems[index].DisplayName == newSuggestions[index].DisplayName) + { + PathModeSuggestionItems[index] = newSuggestions[index]; + } + else + PathModeSuggestionItems.Insert(index, newSuggestions[index]); + } + } + + return true; + }); + + if (!result) + { + AddNoResultsItem(); + } + + void AddNoResultsItem() + { + PathModeSuggestionItems.Clear(); + PathModeSuggestionItems.Add(new( + ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory, + Strings.NavigationToolbarVisiblePathNoResults.GetLocalizedResource())); + } + } + + [Obsolete("Remove once Omnibar goes out of experimental.")] public async Task SetAddressBarSuggestionsAsync(AutoSuggestBox sender, IShellPage shellpage) { if (sender.Text is not null && shellpage.ShellViewModel is not null) diff --git a/src/Files.App/Views/Shells/BaseShellPage.cs b/src/Files.App/Views/Shells/BaseShellPage.cs index 76000bad73c3..07d4fec378eb 100644 --- a/src/Files.App/Views/Shells/BaseShellPage.cs +++ b/src/Files.App/Views/Shells/BaseShellPage.cs @@ -422,7 +422,7 @@ protected async void ShellPage_AddressBarTextEntered(object sender, AddressBarTe protected async void ShellPage_ToolbarPathItemLoaded(object sender, ToolbarPathItemLoadedEventArgs e) { - await ToolbarViewModel.SetPathBoxDropDownFlyoutAsync(e.OpenedFlyout, e.Item, this); + await ToolbarViewModel.SetPathBoxDropDownFlyoutAsync(e.OpenedFlyout, e.Item); } protected async void ShellPage_ToolbarFlyoutOpening(object sender, ToolbarFlyoutOpeningEventArgs e) @@ -430,7 +430,7 @@ protected async void ShellPage_ToolbarFlyoutOpening(object sender, ToolbarFlyout var pathBoxItem = ((Button)e.OpeningFlyout.Target).DataContext as PathBoxItem; if (pathBoxItem is not null) - await ToolbarViewModel.SetPathBoxDropDownFlyoutAsync(e.OpeningFlyout, pathBoxItem, this); + await ToolbarViewModel.SetPathBoxDropDownFlyoutAsync(e.OpeningFlyout, pathBoxItem); } protected async void NavigationToolbar_QuerySubmitted(object sender, ToolbarQuerySubmittedEventArgs e) @@ -442,9 +442,10 @@ protected void NavigationToolbar_EditModeEnabled(object sender, EventArgs e) { ToolbarViewModel.ManualEntryBoxLoaded = true; ToolbarViewModel.ClickablePathLoaded = false; - ToolbarViewModel.PathText = string.IsNullOrEmpty(ShellViewModel?.WorkingDirectory) + ToolbarViewModel.OmnibarPathModeText = string.IsNullOrEmpty(ShellViewModel?.WorkingDirectory) ? Constants.UserEnvironmentPaths.HomePath : ShellViewModel.WorkingDirectory; + ToolbarViewModel.PathText = ToolbarViewModel.OmnibarPathModeText; } protected async void DrivesManager_PropertyChanged(object sender, PropertyChangedEventArgs e) From 6a80bcd186e36db70e5e522b7cf64e17ca8cce8d Mon Sep 17 00:00:00 2001 From: 0x5BFA <62196528+0x5bfa@users.noreply.github.com> Date: Thu, 24 Apr 2025 01:37:53 +0900 Subject: [PATCH 2/4] Updated the root item's UX Co-Authored-By: Yair <39923744+yaira2@users.noreply.github.com> --- .../UserControls/NavigationToolbar.xaml | 1 + .../UserControls/NavigationToolbar.xaml.cs | 58 +++++++++++++++---- .../NavigationToolbarViewModel.cs | 2 +- 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml b/src/Files.App/UserControls/NavigationToolbar.xaml index 7fe8371ec8e5..d1ca0828c7a1 100644 --- a/src/Files.App/UserControls/NavigationToolbar.xaml +++ b/src/Files.App/UserControls/NavigationToolbar.xaml @@ -435,6 +435,7 @@ diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml.cs b/src/Files.App/UserControls/NavigationToolbar.xaml.cs index 0d6d4cb0a295..140349ede499 100644 --- a/src/Files.App/UserControls/NavigationToolbar.xaml.cs +++ b/src/Files.App/UserControls/NavigationToolbar.xaml.cs @@ -273,31 +273,67 @@ private async void Omnibar_TextChanged(Omnibar sender, OmnibarTextChangedEventAr private async void BreadcrumbBar_ItemClicked(Controls.BreadcrumbBar sender, Controls.BreadcrumbBarItemClickedEventArgs args) { + // Navigation to the current folder should not happen + if (args.Index == ViewModel.PathComponents.Count - 1 || + ViewModel.PathComponents[args.Index].Path is not { } path) + return; + if (args.IsRootItem) { await ViewModel.HandleItemNavigationAsync("Home"); return; } - await ViewModel.HandleFolderNavigationAsync(ViewModel.PathComponents[args.Index].Path); + await ViewModel.HandleFolderNavigationAsync(path); } private async void BreadcrumbBar_ItemDropDownFlyoutOpening(object sender, BreadcrumbBarItemDropDownFlyoutEventArgs e) { if (e.IsRootItem) { - // TODO: Populate a different flyout for the root item + IHomeFolder homeFolder = new HomeFolder(); + e.Flyout.Items.Add(new MenuFlyoutHeaderItem() { Text = "Quick access" }); - e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Desktop" }); - e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Download" }); - e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Documents" }); - e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Pictures" }); - e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Music" }); - e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Videos" }); - e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Recycle bin" }); + + await foreach (var storable in homeFolder.GetQuickAccessFolderAsync()) + { + if (storable is not IWindowsStorable windowsStorable) + continue; + + var flyoutItem = new MenuFlyoutItem() + { + Text = windowsStorable.GetDisplayName(Windows.Win32.UI.Shell.SIGDN.SIGDN_PARENTRELATIVEFORUI), + Icon = new FontIcon { Glyph = "\uE8B7" }, // Use font icon as placeholder + }; + + e.Flyout.Items.Add(flyoutItem); + + windowsStorable.TryGetThumbnail((int)(16f * App.AppModel.AppWindowDPI), Windows.Win32.UI.Shell.SIIGBF.SIIGBF_ICONONLY, out var thumbnailData); + flyoutItem.Icon = new ImageIcon() { Source = await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() => thumbnailData.ToBitmapAsync(), Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal) }; + + windowsStorable.Dispose(); + } + e.Flyout.Items.Add(new MenuFlyoutHeaderItem() { Text = "Drives" }); - e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Local Disk (C:)" }); - e.Flyout.Items.Add(new MenuFlyoutItem() { Text = "Local Disk (D:)" }); + + await foreach (var storable in homeFolder.GetLogicalDrivesAsync()) + { + if (storable is not IWindowsStorable windowsStorable) + continue; + + var flyoutItem = new MenuFlyoutItem() + { + Text = windowsStorable.GetDisplayName(Windows.Win32.UI.Shell.SIGDN.SIGDN_PARENTRELATIVEFORUI), + Icon = new FontIcon { Glyph = "\uE8B7" }, // Use font icon as placeholder + }; + + e.Flyout.Items.Add(flyoutItem); + + windowsStorable.TryGetThumbnail((int)(16f * App.AppModel.AppWindowDPI), Windows.Win32.UI.Shell.SIIGBF.SIIGBF_ICONONLY, out var thumbnailData); + flyoutItem.Icon = new ImageIcon() { Source = await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() => thumbnailData.ToBitmapAsync(), Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal) }; + + windowsStorable.Dispose(); + } return; } diff --git a/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs b/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs index 4b588a54167a..057011e06c40 100644 --- a/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/NavigationToolbarViewModel.cs @@ -859,7 +859,7 @@ public async Task SetPathBoxDropDownFlyoutAsync(MenuFlyout flyout, PathBoxItem p { Icon = new FontIcon { Glyph = "\uE8B7" }, // Use font icon as placeholder Text = childFolder.Item.Name, - FontSize = 12, + FontSize = 12 }; if (workingPath != childFolder.Path) From e4c6ec18136fea512376096e1af899d3b1379c46 Mon Sep 17 00:00:00 2001 From: 0x5BFA <62196528+0x5bfa@users.noreply.github.com> Date: Mon, 28 Apr 2025 23:34:23 +0900 Subject: [PATCH 3/4] Wrap up Co-Authored-By: Yair <39923744+yaira2@users.noreply.github.com> --- src/Files.App.Controls/Omnibar/Omnibar.cs | 2 +- src/Files.App/Strings/en-US/Resources.resw | 9 +++++ .../UserControls/NavigationToolbar.xaml | 17 ++++------ .../UserControls/NavigationToolbar.xaml.cs | 33 ++++++++++++++----- .../NavigationToolbarViewModel.cs | 32 ++++++++---------- src/Files.App/Views/Shells/BaseShellPage.cs | 3 +- 6 files changed, 55 insertions(+), 41 deletions(-) diff --git a/src/Files.App.Controls/Omnibar/Omnibar.cs b/src/Files.App.Controls/Omnibar/Omnibar.cs index fe8c2e20b2da..fa780da79423 100644 --- a/src/Files.App.Controls/Omnibar/Omnibar.cs +++ b/src/Files.App.Controls/Omnibar/Omnibar.cs @@ -188,7 +188,7 @@ public void ChangeMode(OmnibarMode modeToExpand, bool shouldFocus = false, bool public bool TryToggleIsSuggestionsPopupOpen(bool wantToOpen) { - if (wantToOpen && (!IsFocused || CurrentSelectedMode?.SuggestionItemsSource is null)) + if (wantToOpen && (!IsFocused || CurrentSelectedMode?.SuggestionItemsSource is null || (CurrentSelectedMode?.SuggestionItemsSource is IList collection && collection.Count is 0))) return false; _textBoxSuggestionsPopup.IsOpen = wantToOpen; diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw index 16e341e71349..b24d44cef964 100644 --- a/src/Files.App/Strings/en-US/Resources.resw +++ b/src/Files.App/Strings/en-US/Resources.resw @@ -4202,7 +4202,16 @@ Drag files or folders here to interact with them across different tabs + + Command palette + Enter a path to navigate to... + + Find features and commands... + + + Search for files and folders... + \ No newline at end of file diff --git a/src/Files.App/UserControls/NavigationToolbar.xaml b/src/Files.App/UserControls/NavigationToolbar.xaml index d1ca0828c7a1..503e4d3f27be 100644 --- a/src/Files.App/UserControls/NavigationToolbar.xaml +++ b/src/Files.App/UserControls/NavigationToolbar.xaml @@ -112,7 +112,6 @@ AutomationProperties.FullDescription="{x:Bind Commands.NavigateBack.Description, Mode=OneWay}" AutomationProperties.Name="{x:Bind Commands.NavigateBack.Label, Mode=OneWay}" Command="{x:Bind Commands.NavigateBack, Mode=OneWay}" - IsEnabled="{x:Bind Commands.NavigateBack.IsExecutable, Mode=OneWay}" Style="{StaticResource AddressToolbarButtonStyle}" ToolTipService.ToolTip="{x:Bind Commands.NavigateBack.LabelWithHotKey, Mode=OneWay}"> @@ -142,7 +141,6 @@ AutomationProperties.FullDescription="{x:Bind Commands.NavigateForward.Description, Mode=OneWay}" AutomationProperties.Name="{x:Bind Commands.NavigateForward.Label, Mode=OneWay}" Command="{x:Bind Commands.NavigateForward, Mode=OneWay}" - IsEnabled="{x:Bind Commands.NavigateForward.IsExecutable, Mode=OneWay}" Style="{StaticResource AddressToolbarButtonStyle}" ToolTipService.ToolTip="{x:Bind Commands.NavigateForward.LabelWithHotKey, Mode=OneWay}"> @@ -172,7 +170,6 @@ AutomationProperties.FullDescription="{x:Bind Commands.NavigateUp.Description, Mode=OneWay}" AutomationProperties.Name="{x:Bind Commands.NavigateUp.Label, Mode=OneWay}" Command="{x:Bind Commands.NavigateUp, Mode=OneWay}" - IsEnabled="{x:Bind Commands.NavigateUp.IsExecutable, Mode=OneWay}" Style="{StaticResource AddressToolbarButtonStyle}" ToolTipService.ToolTip="{x:Bind Commands.NavigateUp.LabelWithHotKey, Mode=OneWay}"> @@ -184,7 +181,6 @@ AccessKeyInvoked="Button_AccessKeyInvoked" AutomationProperties.Name="{x:Bind Commands.RefreshItems.Label, Mode=OneWay}" Command="{x:Bind Commands.RefreshItems, Mode=OneWay}" - IsEnabled="{x:Bind Commands.RefreshItems.IsExecutable, Mode=OneWay}" Style="{StaticResource AddressToolbarButtonStyle}" ToolTipService.ToolTip="{x:Bind Commands.RefreshItems.LabelWithHotKey, Mode=OneWay}"> @@ -197,7 +193,6 @@ AccessKeyInvoked="Button_AccessKeyInvoked" AutomationProperties.Name="{x:Bind Commands.NavigateHome.Label, Mode=OneWay}" Command="{x:Bind Commands.NavigateHome, Mode=OneWay}" - IsEnabled="{x:Bind Commands.NavigateHome.IsExecutable, Mode=OneWay}" Style="{StaticResource AddressToolbarButtonStyle}" ToolTipService.ToolTip="{x:Bind Commands.NavigateHome.LabelWithHotKey, Mode=OneWay}"> @@ -350,10 +345,10 @@ IconOnActive="{controls:ThemedIconMarkup Style={StaticResource App.ThemedIcons.Omnibar.Path}, IsFilled=True}" IconOnInactive="{controls:ThemedIconMarkup Style={StaticResource App.ThemedIcons.Omnibar.Path}, IconType=Outline}" IsDefault="True" - ModeName="Path" + ModeName="{helpers:ResourceString Name=Path}" PlaceholderText="{helpers:ResourceString Name=OmnibarPathModeTextPlaceholder}" SuggestionItemsSource="{x:Bind ViewModel.PathModeSuggestionItems, Mode=OneWay}" - Text="{x:Bind ViewModel.OmnibarPathModeText, Mode=TwoWay}" + Text="{x:Bind ViewModel.PathText, Mode=TwoWay}" TextMemberPath="Path"> + ModeName="{helpers:ResourceString Name=CommandPalette}" + PlaceholderText="{helpers:ResourceString Name=OmnibarCommandPaletteModeTextPlaceholder}">