Skip to content

Commit d827a32

Browse files
authored
Move tags to a sub menu flyout (#9777)
1 parent f6db0c6 commit d827a32

File tree

9 files changed

+160
-200
lines changed

9 files changed

+160
-200
lines changed

src/Files.Uwp/BaseLayout.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -680,17 +680,16 @@ private async Task LoadMenuItemsAsync()
680680

681681
private void AddNewFileTagsToMenu(Microsoft.UI.Xaml.Controls.CommandBarFlyout contextMenu)
682682
{
683-
var fileTagsContextMenu = new FileTagsContextMenu()
684-
{
685-
SelectedListedItems = SelectedItems
686-
};
683+
var fileTagsContextMenu = new FileTagsContextMenu(SelectedItems);
687684
var overflowSeparator = contextMenu.SecondaryCommands.FirstOrDefault(x => x is FrameworkElement fe && fe.Tag as string == "OverflowSeparator") as AppBarSeparator;
688685
var index = contextMenu.SecondaryCommands.IndexOf(overflowSeparator);
689686
index = index >= 0 ? index : contextMenu.SecondaryCommands.Count;
690687
contextMenu.SecondaryCommands.Insert(index, new AppBarSeparator());
691-
contextMenu.SecondaryCommands.Insert(index + 1, new AppBarElementContainer()
688+
contextMenu.SecondaryCommands.Insert(index + 1, new AppBarButton()
692689
{
693-
Content = fileTagsContextMenu
690+
Label = "SettingsEditFileTagsExpander/Title".GetLocalized(),
691+
Icon = new FontIcon() { Glyph = "\uE1CB" },
692+
Flyout = fileTagsContextMenu
694693
});
695694
}
696695

src/Files.Uwp/Files.Uwp.csproj

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,7 @@
334334
<Compile Include="UserControls\InnerNavigationToolbar.xaml.cs">
335335
<DependentUpon>InnerNavigationToolbar.xaml</DependentUpon>
336336
</Compile>
337-
<Compile Include="UserControls\Menus\FileTagsContextMenu.xaml.cs">
338-
<DependentUpon>FileTagsContextMenu.xaml</DependentUpon>
339-
</Compile>
337+
<Compile Include="UserControls\Menus\FileTagsContextMenu.cs" />
340338
<Compile Include="UserControls\Pane\Pane.cs" />
341339
<Compile Include="UserControls\Pane\PaneControl.xaml.cs">
342340
<DependentUpon>PaneControl.xaml</DependentUpon>
@@ -507,7 +505,7 @@
507505
<Compile Include="UserControls\FileIcon.xaml.cs">
508506
<DependentUpon>FileIcon.xaml</DependentUpon>
509507
</Compile>
510-
<Compile Include="UserControls\MenuFlyoutItemWithImage.xaml.cs">
508+
<Compile Include="UserControls\Menus\MenuFlyoutItemWithImage.xaml.cs">
511509
<DependentUpon>MenuFlyoutItemWithImage.xaml</DependentUpon>
512510
</Compile>
513511
<Compile Include="UserControls\AddressToolbar.xaml.cs">
@@ -1270,10 +1268,6 @@
12701268
<SubType>Designer</SubType>
12711269
<Generator>MSBuild:Compile</Generator>
12721270
</Page>
1273-
<Page Include="UserControls\Menus\FileTagsContextMenu.xaml">
1274-
<SubType>Designer</SubType>
1275-
<Generator>MSBuild:Compile</Generator>
1276-
</Page>
12771271
<Page Include="UserControls\Pane\PaneControl.xaml">
12781272
<Generator>MSBuild:Compile</Generator>
12791273
<SubType>Designer</SubType>
@@ -1338,7 +1332,7 @@
13381332
<Generator>MSBuild:Compile</Generator>
13391333
<SubType>Designer</SubType>
13401334
</Page>
1341-
<Page Include="UserControls\MenuFlyoutItemWithImage.xaml">
1335+
<Page Include="UserControls\Menus\MenuFlyoutItemWithImage.xaml">
13421336
<SubType>Designer</SubType>
13431337
<Generator>MSBuild:Compile</Generator>
13441338
</Page>

src/Files.Uwp/Helpers/MenuFlyoutHelper.cs

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
using CommunityToolkit.Mvvm.Input;
2-
using System;
1+
using System;
32
using System.Collections.Generic;
3+
using System.Windows.Input;
44
using Windows.UI.Xaml;
55
using Windows.UI.Xaml.Controls;
66

@@ -10,50 +10,55 @@ public class MenuFlyoutHelper : DependencyObject
1010
{
1111
#region View Models
1212

13-
public interface IMenuFlyoutItem { }
13+
public interface IMenuFlyoutItemViewModel { }
1414

15-
public class MenuFlyoutSeparatorViewModel : IMenuFlyoutItem { }
15+
public class MenuFlyoutSeparatorViewModel : IMenuFlyoutItemViewModel { }
1616

17-
public abstract class MenuFlyoutItemBaseViewModel : IMenuFlyoutItem
17+
public class MenuFlyoutItemViewModel : IMenuFlyoutItemViewModel
1818
{
19-
public string Text { get; }
19+
public string Text { get; init; }
20+
21+
public ICommand Command { get; init; }
22+
23+
public object CommandParameter { get; init; }
24+
25+
public string Tooltip { get; init; }
2026

2127
public bool IsEnabled { get; set; } = true;
2228

23-
internal MenuFlyoutItemBaseViewModel(string text) => Text = text;
29+
public MenuFlyoutItemViewModel(string text)
30+
=> Text = text;
2431
}
2532

26-
public class MenuFlyoutItemViewModel : MenuFlyoutItemBaseViewModel
33+
public class MenuFlyoutSubItemViewModel : IMenuFlyoutItemViewModel
2734
{
28-
public string Path { get; }
35+
public string Text { get; }
2936

30-
public RelayCommand<string> OnSelect { get; }
37+
public bool IsEnabled { get; set; } = true;
3138

32-
internal MenuFlyoutItemViewModel(string text, string path, RelayCommand<string> onSelect) : base(text)
33-
{
34-
Path = path;
35-
OnSelect = onSelect;
36-
}
39+
public IList<IMenuFlyoutItemViewModel> Items { get; } = new List<IMenuFlyoutItemViewModel>();
40+
41+
public MenuFlyoutSubItemViewModel(string text)
42+
=> Text = text;
3743
}
3844

39-
public class MenuFlyoutSubItemViewModel : MenuFlyoutItemBaseViewModel
45+
public class MenuFlyoutFactoryItemViewModel : IMenuFlyoutItemViewModel
4046
{
41-
public IList<IMenuFlyoutItem> Items { get; } = new List<IMenuFlyoutItem>();
47+
public Func<MenuFlyoutItemBase> Build { get; }
4248

43-
internal MenuFlyoutSubItemViewModel(string text) : base(text)
44-
{
45-
}
49+
public MenuFlyoutFactoryItemViewModel(Func<MenuFlyoutItemBase> factoryFunc)
50+
=> Build = factoryFunc;
4651
}
4752

4853
#endregion View Models
4954

5055
#region ItemsSource
5156

52-
public static IEnumerable<IMenuFlyoutItem> GetItemsSource(DependencyObject obj) => obj.GetValue(ItemsSourceProperty) as IEnumerable<IMenuFlyoutItem>;
57+
public static IEnumerable<IMenuFlyoutItemViewModel> GetItemsSource(DependencyObject obj) => obj.GetValue(ItemsSourceProperty) as IEnumerable<IMenuFlyoutItemViewModel>;
5358

54-
public static void SetItemsSource(DependencyObject obj, IEnumerable<IMenuFlyoutItem> value) => obj.SetValue(ItemsSourceProperty, value);
59+
public static void SetItemsSource(DependencyObject obj, IEnumerable<IMenuFlyoutItemViewModel> value) => obj.SetValue(ItemsSourceProperty, value);
5560

56-
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.RegisterAttached("ItemsSource", typeof(IEnumerable<IMenuFlyoutItem>), typeof(MenuFlyoutHelper), new PropertyMetadata(null, ItemsSourceChanged));
61+
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.RegisterAttached("ItemsSource", typeof(IEnumerable<IMenuFlyoutItemViewModel>), typeof(MenuFlyoutHelper), new PropertyMetadata(null, ItemsSourceChanged));
5762

5863
private static void ItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => SetupItems(d as MenuFlyout);
5964

@@ -102,7 +107,7 @@ await menu.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, ()
102107
});
103108
}
104109

105-
private static void AddItems(IList<MenuFlyoutItemBase> menu, IEnumerable<IMenuFlyoutItem> items)
110+
private static void AddItems(IList<MenuFlyoutItemBase> menu, IEnumerable<IMenuFlyoutItemViewModel> items)
106111
{
107112
foreach (var item in items)
108113
{
@@ -115,13 +120,13 @@ private static void AddItems(IList<MenuFlyoutItemBase> menu, IEnumerable<IMenuFl
115120
var mfi = new MenuFlyoutItem
116121
{
117122
Text = vm.Text,
118-
Command = vm.OnSelect,
119-
CommandParameter = vm.Path,
123+
Command = vm.Command,
124+
CommandParameter = vm.CommandParameter,
120125
IsEnabled = vm.IsEnabled,
121126
};
122-
if (!string.IsNullOrEmpty(vm.Path))
127+
if (!string.IsNullOrEmpty(vm.Tooltip))
123128
{
124-
ToolTipService.SetToolTip(mfi, vm.Path);
129+
ToolTipService.SetToolTip(mfi, vm.Tooltip);
125130
}
126131
menu.Add(mfi);
127132
}
@@ -135,6 +140,10 @@ private static void AddItems(IList<MenuFlyoutItemBase> menu, IEnumerable<IMenuFl
135140
AddItems(mfsi.Items, svm.Items);
136141
menu.Add(mfsi);
137142
}
143+
else if (item is MenuFlyoutFactoryItemViewModel fvm)
144+
{
145+
menu.Add(fvm.Build());
146+
}
138147
}
139148
}
140149
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using CommunityToolkit.Mvvm.DependencyInjection;
2+
using Files.Backend.Services.Settings;
3+
using Files.Backend.ViewModels.FileTags;
4+
using Files.Uwp.Filesystem;
5+
using Files.Shared.Extensions;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using Windows.UI.Xaml.Controls;
10+
using Windows.UI.Xaml.Media;
11+
using Files.Uwp.Helpers;
12+
using static Files.Uwp.Helpers.MenuFlyoutHelper;
13+
14+
namespace Files.Uwp.UserControls.Menus
15+
{
16+
public class FileTagsContextMenu : MenuFlyout
17+
{
18+
private IFileTagsSettingsService FileTagsSettingsService { get; } =
19+
Ioc.Default.GetService<IFileTagsSettingsService>();
20+
21+
public IEnumerable<ListedItem> SelectedItems { get; }
22+
23+
public FileTagsContextMenu(IEnumerable<ListedItem> selectedItems)
24+
{
25+
SetValue(MenuFlyoutHelper.ItemsSourceProperty, FileTagsSettingsService.FileTagList
26+
.Select(tag => new MenuFlyoutFactoryItemViewModel(() =>
27+
{
28+
var tagItem = new ToggleMenuFlyoutItem()
29+
{
30+
Text = tag.TagName,
31+
Tag = tag
32+
};
33+
tagItem.Icon = new FontIcon()
34+
{
35+
Glyph = "\uEA3B",
36+
Foreground = new SolidColorBrush(ColorHelpers.FromHex(tag.ColorString))
37+
};
38+
tagItem.Click += TagItem_Click;
39+
return tagItem;
40+
})));
41+
42+
SelectedItems = selectedItems;
43+
44+
Opening += Item_Opening;
45+
}
46+
47+
private void TagItem_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
48+
{
49+
var tagItem = (ToggleMenuFlyoutItem)sender;
50+
if (tagItem.IsChecked)
51+
{
52+
AddFileTag(SelectedItems, (FileTagViewModel)tagItem.Tag);
53+
}
54+
else
55+
{
56+
RemoveFileTag(SelectedItems, (FileTagViewModel)tagItem.Tag);
57+
}
58+
}
59+
60+
private void Item_Opening(object sender, object e)
61+
{
62+
Opening -= Item_Opening;
63+
64+
// go through each tag and find the common one for all files
65+
var commonFileTags = SelectedItems
66+
.Select(x => x.FileTags ?? Enumerable.Empty<string>())
67+
.Aggregate((x, y) => x.Intersect(y))
68+
.Select(x => Items.FirstOrDefault(y => x == ((FileTagViewModel)y.Tag)?.Uid));
69+
70+
commonFileTags.OfType<ToggleMenuFlyoutItem>().ForEach(x => x.IsChecked = true);
71+
}
72+
73+
private void RemoveFileTag(IEnumerable<ListedItem> selectedListedItems, FileTagViewModel removed)
74+
{
75+
foreach (var selectedItem in selectedListedItems)
76+
{
77+
var existingTags = selectedItem.FileTags ?? Array.Empty<string>();
78+
if (existingTags.Contains(removed.Uid))
79+
{
80+
var tagList = existingTags.Except(new[] { removed.Uid }).ToArray();
81+
selectedItem.FileTags = tagList.Any() ? tagList : null;
82+
}
83+
}
84+
}
85+
86+
private void AddFileTag(IEnumerable<ListedItem> selectedListedItems, FileTagViewModel added)
87+
{
88+
foreach (var selectedItem in selectedListedItems)
89+
{
90+
var existingTags = selectedItem.FileTags ?? Array.Empty<string>();
91+
if (!existingTags.Contains(added.Uid))
92+
{
93+
selectedItem.FileTags = existingTags.Append(added.Uid).ToArray();
94+
}
95+
}
96+
}
97+
}
98+
}

src/Files.Uwp/UserControls/Menus/FileTagsContextMenu.xaml

Lines changed: 0 additions & 55 deletions
This file was deleted.

0 commit comments

Comments
 (0)