diff --git a/Settings.XamlStyler b/Settings.XamlStyler index 117aea82adf0..d831092fff19 100644 --- a/Settings.XamlStyler +++ b/Settings.XamlStyler @@ -1,3 +1,4 @@ { - "IndentWithTabs": true + "IndentWithTabs": true, + "NoNewLineMarkupExtensions": "x:Bind, Binding, controls:ThemedIconMarkup", } \ No newline at end of file diff --git a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.cs b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.cs index b43b0ab454c1..500fee8a96a0 100644 --- a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.cs +++ b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.cs @@ -42,7 +42,7 @@ public BreadcrumbBar() { DefaultStyleKey = typeof(BreadcrumbBar); - _itemsRepeaterLayout = new(this, 2d); + _itemsRepeaterLayout = new(this); } // Methods @@ -87,12 +87,13 @@ internal protected virtual void RaiseItemDropDownFlyoutClosed(BreadcrumbBarItem internal protected virtual void OnLayoutUpdated() { - if (_itemsRepeater is null) + if (_itemsRepeater is null || (_itemsRepeaterLayout.IndexAfterEllipsis > _itemsRepeaterLayout.VisibleItemsCount && _isEllipsisRendered)) return; + if (_ellipsisBreadcrumbBarItem is not null && _isEllipsisRendered != _itemsRepeaterLayout.EllipsisIsRendered) + _ellipsisBreadcrumbBarItem.Visibility = _itemsRepeaterLayout.EllipsisIsRendered ? Visibility.Visible : Visibility.Collapsed; + _isEllipsisRendered = _itemsRepeaterLayout.EllipsisIsRendered; - if (_ellipsisBreadcrumbBarItem is not null) - _ellipsisBreadcrumbBarItem.Visibility = _isEllipsisRendered ? Visibility.Visible : Visibility.Collapsed; for (int accessibilityIndex = 0, collectionIndex = _itemsRepeaterLayout.IndexAfterEllipsis; accessibilityIndex < _itemsRepeaterLayout.VisibleItemsCount; diff --git a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml index 5f92aed85ec2..213ab4cd8340 100644 --- a/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml +++ b/src/Files.App.Controls/BreadcrumbBar/BreadcrumbBar.xaml @@ -5,13 +5,14 @@ xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals" xmlns:local="using:Files.App.Controls"> - 32 + 34 120 16 4,0 8,0 16,0,8,0 + 2,0,0,0 2,2,2,2 2,2,2,2 @@ -21,21 +22,33 @@ + + + + + + - - diff --git a/src/Files.App.Controls/Omnibar/OmnibarModeSeparator.cs b/src/Files.App.Controls/Omnibar/OmnibarModeSeparator.cs new file mode 100644 index 000000000000..2eaf6fbed8ae --- /dev/null +++ b/src/Files.App.Controls/Omnibar/OmnibarModeSeparator.cs @@ -0,0 +1,22 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +namespace Files.App.Controls +{ + public partial class OmnibarModeSeparator : Control + { + // Constructor + + public OmnibarModeSeparator() + { + DefaultStyleKey = typeof(OmnibarMode); + } + + // Methods + + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + } + } +} diff --git a/src/Files.App.Controls/Omnibar/OmnibarTextChangeReason.cs b/src/Files.App.Controls/Omnibar/OmnibarTextChangeReason.cs new file mode 100644 index 000000000000..8a4c41e2b3be --- /dev/null +++ b/src/Files.App.Controls/Omnibar/OmnibarTextChangeReason.cs @@ -0,0 +1,16 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +namespace Files.App.Controls +{ + public enum OmnibarTextChangeReason + { + UserInput, + + SuggestionChosen, + + ProgrammaticChange, + + None, + } +} diff --git a/src/Files.App.Controls/ThemedIcon/ThemedIconMarkup.cs b/src/Files.App.Controls/ThemedIcon/ThemedIconMarkup.cs new file mode 100644 index 000000000000..23bd9a1342e7 --- /dev/null +++ b/src/Files.App.Controls/ThemedIcon/ThemedIconMarkup.cs @@ -0,0 +1,22 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +using Microsoft.UI.Xaml.Markup; + +namespace Files.App.Controls +{ + [MarkupExtensionReturnType(ReturnType = typeof(ThemedIcon))] + public sealed partial class ThemedIconMarkup : MarkupExtension + { + public Style Style { get; set; } = null!; + + public bool IsFilled { get; set; } + + public ThemedIconTypes IconType { get; set; } + + protected override object ProvideValue() + { + return new ThemedIcon() { Style = Style, IsFilled = IsFilled, IconType = IconType }; + } + } +} diff --git a/src/Files.App.Controls/Themes/Generic.xaml b/src/Files.App.Controls/Themes/Generic.xaml index 4e66b0e77870..910ef94ce52b 100644 --- a/src/Files.App.Controls/Themes/Generic.xaml +++ b/src/Files.App.Controls/Themes/Generic.xaml @@ -60,7 +60,6 @@ - diff --git a/tests/Files.App.UITests/Data/DummyItem2.cs b/tests/Files.App.UITests/Data/BreadcrumbBarItemModel.cs similarity index 55% rename from tests/Files.App.UITests/Data/DummyItem2.cs rename to tests/Files.App.UITests/Data/BreadcrumbBarItemModel.cs index 048ee1fa236e..9d6169ab1d69 100644 --- a/tests/Files.App.UITests/Data/DummyItem2.cs +++ b/tests/Files.App.UITests/Data/BreadcrumbBarItemModel.cs @@ -5,5 +5,5 @@ namespace Files.App.UITests.Data { - internal record DummyItem2(string Text, ObservableCollection? Children = null); + internal record BreadcrumbBarItemModel(string Text, ObservableCollection? Children = null); } diff --git a/tests/Files.App.UITests/Data/DummyItem1.cs b/tests/Files.App.UITests/Data/DummyItem1.cs deleted file mode 100644 index b7cbcc219245..000000000000 --- a/tests/Files.App.UITests/Data/DummyItem1.cs +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Files Community -// Licensed under the MIT License. - -namespace Files.App.UITests.Data -{ - internal record DummyItem1(string Title, string Description, string HotKeys); -} diff --git a/tests/Files.App.UITests/Data/OmnibarPaletteSuggestionItem.cs b/tests/Files.App.UITests/Data/OmnibarPaletteSuggestionItem.cs new file mode 100644 index 000000000000..db6d31d2519d --- /dev/null +++ b/tests/Files.App.UITests/Data/OmnibarPaletteSuggestionItem.cs @@ -0,0 +1,24 @@ +// Copyright (c) Files Community +// Licensed under the MIT License. + +using Files.App.Controls; +using System; + +namespace Files.App.UITests.Data +{ + public partial record OmnibarPaletteSuggestionItem(string Title, string Description, string HotKeys) + : IOmnibarTextMemberPathProvider + { + /// + public string GetTextMemberPath(string textMemberPath) + { + return textMemberPath switch + { + nameof(Title) => Title, + nameof(Description) => Description, + nameof(HotKeys) => HotKeys, + _ => throw new ArgumentOutOfRangeException(nameof(textMemberPath), textMemberPath, null), + }; + } + } +} diff --git a/tests/Files.App.UITests/Views/BreadcrumbBarPage.xaml b/tests/Files.App.UITests/Views/BreadcrumbBarPage.xaml index 2044818bbef3..bcff33b8e32f 100644 --- a/tests/Files.App.UITests/Views/BreadcrumbBarPage.xaml +++ b/tests/Files.App.UITests/Views/BreadcrumbBarPage.xaml @@ -15,7 +15,7 @@ - - - - + + diff --git a/tests/Files.App.UITests/Views/BreadcrumbBarPage.xaml.cs b/tests/Files.App.UITests/Views/BreadcrumbBarPage.xaml.cs index 32b5cd27c0c1..8b3deb1cc97e 100644 --- a/tests/Files.App.UITests/Views/BreadcrumbBarPage.xaml.cs +++ b/tests/Files.App.UITests/Views/BreadcrumbBarPage.xaml.cs @@ -12,7 +12,7 @@ namespace Files.App.UITests.Views { public sealed partial class BreadcrumbBarPage : Page { - private readonly ObservableCollection DummyItems; + private readonly ObservableCollection DummyItems; [GeneratedDependencyProperty] private partial string? ClickedItemName { get; set; } diff --git a/tests/Files.App.UITests/Views/OmnibarPage.xaml b/tests/Files.App.UITests/Views/OmnibarPage.xaml index 43ddf95bbc20..26a4a1604835 100644 --- a/tests/Files.App.UITests/Views/OmnibarPage.xaml +++ b/tests/Files.App.UITests/Views/OmnibarPage.xaml @@ -14,189 +14,133 @@ - + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + - + + - + - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - + - - - - - - - - + - + - - - - - - diff --git a/tests/Files.App.UITests/Views/OmnibarPage.xaml.cs b/tests/Files.App.UITests/Views/OmnibarPage.xaml.cs index a1d577b09b69..0fd9bc89e01e 100644 --- a/tests/Files.App.UITests/Views/OmnibarPage.xaml.cs +++ b/tests/Files.App.UITests/Views/OmnibarPage.xaml.cs @@ -1,6 +1,8 @@ // Copyright (c) Files Community // Licensed under the MIT License. +using CommunityToolkit.WinUI; +using Files.App.Controls; using Files.App.UITests.Data; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; @@ -10,13 +12,28 @@ namespace Files.App.UITests.Views { public sealed partial class OmnibarPage : Page { - private readonly ObservableCollection DummyItems1; + private readonly string Omnibar1_TextMemberPathForPaletteMode = nameof(OmnibarPaletteSuggestionItem.Title); + + private readonly ObservableCollection Omnibar1_PaletteSuggestions; + private readonly ObservableCollection Omnibar1_BreadcrumbBarItems; + + [GeneratedDependencyProperty(DefaultValue = "")] + private partial string Omnibar1_Text { get; set; } + + [GeneratedDependencyProperty(DefaultValue = "")] + private partial string Omnibar1_TextChangedReason { get; set; } + + [GeneratedDependencyProperty] + private partial int Omnibar1_ChosenSuggestionIndex { get; set; } + + [GeneratedDependencyProperty(DefaultValue = "")] + private partial string Omnibar1_SubmittedQuery { get; set; } public OmnibarPage() { InitializeComponent(); - DummyItems1 = + Omnibar1_PaletteSuggestions = [ new("Open online help page in browser", "Open online help page in browser", "Control + H"), new("Toggle full screen", "Toggle full screen", "Control + H"), @@ -28,6 +45,50 @@ public OmnibarPage() new("Undo the last file operation", "Undo the last file operation", "Control + H"), new("Toggle whether to show hidden items", "Toggle whether to show hidden items", "Control + H"), ]; + + Omnibar1_BreadcrumbBarItems = + [ + new("Local Disk (C:)"), + new("Users"), + new("me"), + new("OneDrive"), + new("Desktop"), + new("Folder1"), + new("Folder2"), + ]; + } + + private void Omnibar1_BreadcrumbBar_ItemDropDownFlyoutOpening(object sender, BreadcrumbBarItemDropDownFlyoutEventArgs e) + { + e.Flyout.Items.Add(new MenuFlyoutItem { Icon = new FontIcon() { Glyph = "\uE8B7" }, Text = "Item 1" }); + e.Flyout.Items.Add(new MenuFlyoutItem { Icon = new FontIcon() { Glyph = "\uE8B7" }, Text = "Item 2" }); + e.Flyout.Items.Add(new MenuFlyoutItem { Icon = new FontIcon() { Glyph = "\uE8B7" }, Text = "Item 3" }); + } + + private void Omnibar1_BreadcrumbBar_ItemDropDownFlyoutClosed(object sender, BreadcrumbBarItemDropDownFlyoutEventArgs e) + { + e.Flyout.Items.Clear(); + } + + private void Omnibar1_QuerySubmitted(Omnibar sender, OmnibarQuerySubmittedEventArgs args) + { + Omnibar1_ChosenSuggestionIndex = args.Item is OmnibarPaletteSuggestionItem item ? Omnibar1_PaletteSuggestions.IndexOf(item) : -1; + Omnibar1_SubmittedQuery = args.Mode.Text ?? string.Empty; + } + + private void Omnibar1_TextChanged(Omnibar sender, OmnibarTextChangedEventArgs args) + { + if (args.Reason is not OmnibarTextChangeReason.SuggestionChosen) + Omnibar1_ChosenSuggestionIndex = -1; + + Omnibar1_Text = args.Mode.Text ?? string.Empty; + Omnibar1_TextChangedReason = args.Reason.ToString(); + } + + private void Omnibar1_SuggestionChosen(Omnibar sender, OmnibarSuggestionChosenEventArgs args) + { + Omnibar1_ChosenSuggestionIndex = args.SelectedItem is OmnibarPaletteSuggestionItem item ? Omnibar1_PaletteSuggestions.IndexOf(item) : -1; + Omnibar1_SubmittedQuery = args.Mode.Text ?? string.Empty; } } }