diff --git a/src/Files.App/Helpers/ContextFlyoutItemHelper.cs b/src/Files.App/Helpers/ContextFlyoutItemHelper.cs index 6730216e3909..de017f7b2204 100644 --- a/src/Files.App/Helpers/ContextFlyoutItemHelper.cs +++ b/src/Files.App/Helpers/ContextFlyoutItemHelper.cs @@ -218,10 +218,9 @@ public static List GetBaseItemMenuItems( new ContextMenuFlyoutItemViewModel() { Text = "SortBy".GetLocalizedResource(), - ColoredIcon = new ColoredIconModel() + OpacityIcon = new OpacityIconModel() { - BaseLayerGlyph = "\uF029", - OverlayLayerGlyph = "\uF02A", + OpacityIconStyle = "ColorIconSort", }, ShowInRecycleBin = true, ShowInSearchPage = true, diff --git a/src/Files.App/Helpers/ShellContextMenuHelper.cs b/src/Files.App/Helpers/ShellContextMenuHelper.cs index 24e6977dc661..024d5d550aa9 100644 --- a/src/Files.App/Helpers/ShellContextMenuHelper.cs +++ b/src/Files.App/Helpers/ShellContextMenuHelper.cs @@ -272,10 +272,9 @@ public static async Task LoadShellMenuItems( var openWithItem = shellMenuItems.Where(x => (x.Tag as Win32ContextMenuItem)?.CommandString == "openas").ToList().FirstOrDefault(); if (openWithItem is not null) { - openWithItem.ColoredIcon = new ColoredIconModel() + openWithItem.OpacityIcon = new OpacityIconModel() { - BaseLayerGlyph = "\uF049", - OverlayLayerGlyph = "\uF04A", + OpacityIconStyle = "ColorIconOpenWith", }; var (_, openWithItems) = ItemModelListToContextFlyoutHelper.GetAppBarItemsFromModel(new List() { openWithItem }); var placeholder = itemContextMenuFlyout.SecondaryCommands.Where(x => Equals((x as AppBarButton)?.Tag, "OpenWithPlaceholder")).FirstOrDefault() as AppBarButton; diff --git a/src/Files.App/UserControls/SidebarControl.xaml.cs b/src/Files.App/UserControls/SidebarControl.xaml.cs index a76c02674cda..0d6e3c2a84ce 100644 --- a/src/Files.App/UserControls/SidebarControl.xaml.cs +++ b/src/Files.App/UserControls/SidebarControl.xaml.cs @@ -213,26 +213,29 @@ private List GetLocationItemMenuItems(INavigatio new ContextMenuFlyoutItemViewModel() { Text = "OpenInNewTab".GetLocalizedResource(), - Glyph = "\uF113", - GlyphFontFamilyName = "CustomGlyph", + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconOpenInNewTab", + }, Command = OpenInNewTabCommand, ShowItem = options.IsLocationItem && userSettingsService.PreferencesSettingsService.ShowOpenInNewTab }, new ContextMenuFlyoutItemViewModel() { Text = "OpenInNewWindow".GetLocalizedResource(), - Glyph = "\uE737", + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconOpenInNewWindow", + }, Command = OpenInNewWindowCommand, ShowItem = options.IsLocationItem && userSettingsService.PreferencesSettingsService.ShowOpenInNewTab }, new ContextMenuFlyoutItemViewModel() { Text = "OpenInNewPane".GetLocalizedResource(), - ColoredIcon = new ColoredIconModel() + OpacityIcon = new OpacityIconModel() { - BaseBackdropGlyph = "\uF056", - BaseLayerGlyph = "\uF03B", - OverlayLayerGlyph = "\uF03C", + OpacityIconStyle = "ColorIconRightPane", }, Command = OpenInNewPaneCommand, ShowItem = options.IsLocationItem && userSettingsService.PreferencesSettingsService.ShowOpenInNewPane @@ -276,7 +279,10 @@ private List GetLocationItemMenuItems(INavigatio new ContextMenuFlyoutItemViewModel() { Text = "Properties".GetLocalizedResource(), - Glyph = "\uE946", + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconProperties", + }, Command = OpenPropertiesCommand, CommandParameter = menu, ShowItem = options.ShowProperties diff --git a/src/Files.App/UserControls/Widgets/DrivesWidget.xaml.cs b/src/Files.App/UserControls/Widgets/DrivesWidget.xaml.cs index 4e38611f31c0..3504076f0462 100644 --- a/src/Files.App/UserControls/Widgets/DrivesWidget.xaml.cs +++ b/src/Files.App/UserControls/Widgets/DrivesWidget.xaml.cs @@ -140,8 +140,8 @@ public DrivesWidget() MapNetworkDriveCommand = new AsyncRelayCommand(DoNetworkMapDrive); DisconnectNetworkDriveCommand = new RelayCommand(DisconnectNetworkDrive); } - - public override List GetItemMenuItems(WidgetCardItem item, bool isPinned) + + public override List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false) { var drive = ItemsAdded.Where(x => string.Equals(PathNormalization.NormalizePath(x.Path), PathNormalization.NormalizePath(item.Path), StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); var options = drive?.Item.MenuOptions; @@ -151,7 +151,10 @@ public override List GetItemMenuItems(WidgetCard new ContextMenuFlyoutItemViewModel() { Text = "OpenInNewTab".GetLocalizedResource(), - Glyph = "\uF113", + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconOpenInNewTab", + }, GlyphFontFamilyName = "CustomGlyph", Command = OpenInNewTabCommand, CommandParameter = item, @@ -160,7 +163,10 @@ public override List GetItemMenuItems(WidgetCard new ContextMenuFlyoutItemViewModel() { Text = "OpenInNewWindow".GetLocalizedResource(), - Glyph = "\uE737", + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconOpenInNewWindow", + }, Command = OpenInNewWindowCommand, CommandParameter = item, ShowItem = userSettingsService.PreferencesSettingsService.ShowOpenInNewWindow @@ -168,11 +174,9 @@ public override List GetItemMenuItems(WidgetCard new ContextMenuFlyoutItemViewModel() { Text = "OpenInNewPane".GetLocalizedResource(), - ColoredIcon = new ColoredIconModel() + OpacityIcon = new OpacityIconModel() { - BaseBackdropGlyph = "\uF056", - BaseLayerGlyph = "\uF03B", - OverlayLayerGlyph = "\uF03C", + OpacityIconStyle = "ColorIconRightPane", }, Command = OpenInNewPaneCommand, CommandParameter = item, @@ -213,7 +217,10 @@ public override List GetItemMenuItems(WidgetCard new ContextMenuFlyoutItemViewModel() { Text = "Properties".GetLocalizedResource(), - Glyph = "\uE946", + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconProperties", + }, Command = OpenPropertiesCommand, CommandParameter = item }, diff --git a/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml b/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml index 40a7381a2779..c80a733022cd 100644 --- a/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml +++ b/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml @@ -8,7 +8,7 @@ xmlns:local="using:Files.App.UserControls.Widgets" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vc="using:Files.App.ValueConverters" - xmlns:vm="using:Files.Backend.ViewModels.Widgets.FileTagsWidget" + xmlns:vm="using:Files.App.ViewModels.Widgets" d:DesignHeight="300" d:DesignWidth="400" mc:Ignorable="d"> diff --git a/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml.cs b/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml.cs index 23acf1fc2e5e..b7f3f4f8f7f3 100644 --- a/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml.cs +++ b/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml.cs @@ -1,11 +1,14 @@ -using CommunityToolkit.WinUI.UI; +using CommunityToolkit.Mvvm.DependencyInjection; +using CommunityToolkit.Mvvm.Input; +using CommunityToolkit.WinUI.UI; using Files.App.Extensions; using Files.App.Filesystem; using Files.App.Helpers; using Files.App.Helpers.ContextFlyouts; using Files.App.ViewModels; using Files.App.ViewModels.Widgets; -using Files.Backend.ViewModels.Widgets.FileTagsWidget; +using Files.App.Views; +using Files.Backend.Services.Settings; using Files.Shared.Extensions; using Microsoft.UI.Input; using Microsoft.UI.Xaml; @@ -14,8 +17,11 @@ using Microsoft.UI.Xaml.Input; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; +using System.Windows.Input; +using Windows.Storage; using Windows.System; using Windows.UI.Core; @@ -31,8 +37,17 @@ public FileTagsWidgetViewModel ViewModel set => DataContext = value; } + private readonly IUserSettingsService userSettingsService = Ioc.Default.GetRequiredService(); + + public IShellPage AppInstance; public Func? OpenAction { get; set; } + public delegate void FileTagsOpenLocationInvokedEventHandler(object sender, PathNavigationEventArgs e); + public delegate void FileTagsNewPaneInvokedEventHandler(object sender, QuickAccessCardInvokedEventArgs e); + + public event FileTagsOpenLocationInvokedEventHandler FileTagsOpenLocationInvoked; + public event FileTagsNewPaneInvokedEventHandler FileTagsNewPaneInvoked; + public string WidgetName => nameof(BundlesWidget); public string WidgetHeader => "FileTags".GetLocalizedResource(); @@ -45,6 +60,8 @@ public FileTagsWidgetViewModel ViewModel public MenuFlyoutItem? MenuFlyoutItem => null; + private ICommand OpenInNewPaneCommand; + public FileTagsWidget() { InitializeComponent(); @@ -52,6 +69,39 @@ public FileTagsWidget() // Second function is layered on top to ensure that OpenPath function is late initialized and a null reference is not passed-in // See FileTagItemViewModel._openAction for more information ViewModel = new(x => OpenAction!(x)); + OpenInNewTabCommand = new RelayCommand(OpenInNewTab); + OpenInNewWindowCommand = new RelayCommand(OpenInNewWindow); + OpenFileLocationCommand = new RelayCommand(OpenFileLocation); + OpenInNewPaneCommand = new RelayCommand(OpenInNewPane); + PinToFavoritesCommand = new RelayCommand(PinToFavorites); + UnpinFromFavoritesCommand = new RelayCommand(UnpinFromFavorites); + OpenPropertiesCommand = new RelayCommand(OpenProperties); + } + + private void OpenProperties(WidgetCardItem? item) + { + EventHandler flyoutClosed = null!; + flyoutClosed = async (s, e) => + { + ItemContextMenuFlyout.Closed -= flyoutClosed; + ListedItem listedItem = new(null!) + { + ItemPath = (item.Item as FileTagsItemViewModel).Path, + ItemNameRaw = (item.Item as FileTagsItemViewModel).Name, + PrimaryItemAttribute = StorageItemTypes.Folder, + ItemType = "Folder".GetLocalizedResource(), + }; + await FilePropertiesHelpers.OpenPropertiesWindowAsync(listedItem, AppInstance); + }; + ItemContextMenuFlyout.Closed += flyoutClosed; + } + + private void OpenInNewPane(WidgetCardItem? item) + { + FileTagsNewPaneInvoked?.Invoke(this, new QuickAccessCardInvokedEventArgs() + { + Path = item?.Path ?? string.Empty + }); } private async void FileTagItem_ItemClick(object sender, ItemClickEventArgs e) @@ -60,48 +110,141 @@ private async void FileTagItem_ItemClick(object sender, ItemClickEventArgs e) await itemViewModel.ClickCommand.ExecuteAsync(null); } - private void Item_RightTapped(object sender, RightTappedRoutedEventArgs e) + private async void Item_RightTapped(object sender, RightTappedRoutedEventArgs e) { + App.Logger.Warn("rightTapped"); var itemContextMenuFlyout = new CommandBarFlyout { Placement = FlyoutPlacementMode.Full }; itemContextMenuFlyout.Opening += (sender, e) => App.LastOpenedFlyout = sender as CommandBarFlyout; if (sender is not StackPanel tagsItemsStackPanel || tagsItemsStackPanel.DataContext is not FileTagsItemViewModel item) return; + + App.Logger.Warn("Item path: " + item.Path + " widgetcarditem.path = " + (item as WidgetCardItem)?.Path); + var menuItems = GetItemMenuItems(item, QuickAccessService.IsItemPinned(item.Path), item.IsFolder); + var (_, secondaryElements) = ItemModelListToContextFlyoutHelper.GetAppBarItemsFromModel(menuItems); + + if (!UserSettingsService.PreferencesSettingsService.MoveShellExtensionsToSubMenu) + secondaryElements.OfType() + .ForEach(i => i.MinWidth = Constants.UI.ContextMenuItemsMaxWidth); // Set menu min width if the overflow menu setting is disabled + + secondaryElements.ForEach(i => itemContextMenuFlyout.SecondaryCommands.Add(i)); + ItemContextMenuFlyout = itemContextMenuFlyout; itemContextMenuFlyout.ShowAt(tagsItemsStackPanel, new FlyoutShowOptions { Position = e.GetPosition(tagsItemsStackPanel) }); - LoadShellMenuItems(item.Path, itemContextMenuFlyout); + await ShellContextmenuHelper.LoadShellMenuItems(item.Path, itemContextMenuFlyout, showOpenWithMenu: true, showSendToMenu: true); e.Handled = true; } - public async void LoadShellMenuItems(string item, CommandBarFlyout itemContextMenuFlyout) + public override List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false) { - var shiftPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down); - var shellMenuItems = await ContextFlyoutItemHelper.GetItemContextShellCommandsAsync(workingDir: null, - new List() { new ListedItem(null!) { ItemPath = item } }, shiftPressed: shiftPressed, showOpenMenu: false, default); - try + return new List() { - var (_, secondaryElements) = ItemModelListToContextFlyoutHelper.GetAppBarItemsFromModel(shellMenuItems); - if (!secondaryElements.Any()) - return; - - var openedPopups = Microsoft.UI.Xaml.Media.VisualTreeHelper.GetOpenPopups(App.Window); - var secondaryMenu = openedPopups.FirstOrDefault(popup => popup.Name == "OverflowPopup"); - - var itemsControl = secondaryMenu?.Child.FindDescendant(); - if (itemsControl is not null) + new ContextMenuFlyoutItemViewModel() + { + Text = "OpenItemsWithCaptionText".GetLocalizedResource(), + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconOpenWith", + }, + Tag = "OpenWithPlaceholder", + IsEnabled = false, + ShowItem = !isFolder + }, + new ContextMenuFlyoutItemViewModel() + { + Text = "SendTo".GetLocalizedResource(), + Tag = "SendToPlaceholder", + IsEnabled = false, + ShowItem = !isFolder + }, + new ContextMenuFlyoutItemViewModel() + { + Text = "SideBarOpenInNewTab/Text".GetLocalizedResource(), + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconOpenInNewTab", + }, + Command = OpenInNewTabCommand, + CommandParameter = item, + ShowItem = isFolder + }, + new ContextMenuFlyoutItemViewModel() + { + Text = "SideBarOpenInNewWindow/Text".GetLocalizedResource(), + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconOpenInNewWindow", + }, + Command = OpenInNewWindowCommand, + CommandParameter = item, + ShowItem = isFolder + }, + new ContextMenuFlyoutItemViewModel() { - var maxWidth = itemsControl.ActualWidth - Constants.UI.ContextMenuLabelMargin; - secondaryElements.OfType() - .ForEach(x => x.MaxWidth = maxWidth); // Set items max width to current menu width (#5555) + Text = "OpenFileLocation".GetLocalizedResource(), + Glyph = "\uED25", + Command = OpenFileLocationCommand, + CommandParameter = item, + ShowItem = !isFolder + }, + new ContextMenuFlyoutItemViewModel() + { + Text = "OpenInNewPane".GetLocalizedResource(), + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconRightPane", + }, + Command = OpenInNewPaneCommand, + CommandParameter = item, + ShowItem = userSettingsService.PreferencesSettingsService.ShowOpenInNewPane && isFolder + }, + new ContextMenuFlyoutItemViewModel() + { + Text = "BaseLayoutItemContextFlyoutPinToFavorites/Text".GetLocalizedResource(), + Glyph = "\uE840", + Command = PinToFavoritesCommand, + CommandParameter = item, + ShowItem = !isPinned && isFolder + }, + new ContextMenuFlyoutItemViewModel() + { + Text = "SideBarUnpinFromFavorites/Text".GetLocalizedResource(), + Glyph = "\uE77A", + Command = UnpinFromFavoritesCommand, + CommandParameter = item, + ShowItem = isPinned && isFolder + }, + new ContextMenuFlyoutItemViewModel() + { + Text = "BaseLayoutContextFlyoutPropertiesFolder/Text".GetLocalizedResource(), + Glyph = "\uE946", + Command = OpenPropertiesCommand, + CommandParameter = item, + ShowItem = isFolder + }, + new ContextMenuFlyoutItemViewModel() + { + ItemType = ItemType.Separator, + Tag = "OverflowSeparator", + }, + new ContextMenuFlyoutItemViewModel() + { + Text = "Loading".GetLocalizedResource(), + Glyph = "\xE712", + Items = new List(), + ID = "ItemOverflow", + Tag = "ItemOverflow", + IsEnabled = false, } - - secondaryElements.ForEach(i => itemContextMenuFlyout.SecondaryCommands.Add(i)); - } - catch { } + }.Where(x => x.ShowItem).ToList(); } - public override List GetItemMenuItems(WidgetCardItem item, bool isPinned) + public void OpenFileLocation(WidgetCardItem? item) { - return new(); + FileTagsOpenLocationInvoked?.Invoke(this, new PathNavigationEventArgs() + { + ItemPath = Directory.GetParent(item?.Path ?? string.Empty)?.FullName ?? string.Empty, + ItemName = Path.GetFileName(item?.Path ?? string.Empty), + }); } public Task RefreshWidget() diff --git a/src/Files.App/UserControls/Widgets/HomePageWidget.cs b/src/Files.App/UserControls/Widgets/HomePageWidget.cs index a0d911fc9b05..a7124ada5910 100644 --- a/src/Files.App/UserControls/Widgets/HomePageWidget.cs +++ b/src/Files.App/UserControls/Widgets/HomePageWidget.cs @@ -33,7 +33,7 @@ public abstract class HomePageWidget : UserControl protected CommandBarFlyout ItemContextMenuFlyout; - public abstract List GetItemMenuItems(WidgetCardItem item, bool isPinned); + public abstract List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false); public void Button_RightTapped(object sender, RightTappedRoutedEventArgs e) { diff --git a/src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml.cs b/src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml.cs index 2301ab3d8ca7..bb34acab94e8 100644 --- a/src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml.cs +++ b/src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml.cs @@ -148,15 +148,17 @@ public QuickAccessWidget() public string WidgetHeader => "QuickAccess".GetLocalizedResource(); - public override List GetItemMenuItems(WidgetCardItem item, bool isPinned) + public override List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false) { return new List() { new ContextMenuFlyoutItemViewModel() { Text = "OpenInNewTab".GetLocalizedResource(), - Glyph = "\uF113", - GlyphFontFamilyName = "CustomGlyph", + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconOpenInNewTab", + }, Command = OpenInNewTabCommand, CommandParameter = item, ShowItem = userSettingsService.PreferencesSettingsService.ShowOpenInNewTab @@ -164,7 +166,10 @@ public override List GetItemMenuItems(WidgetCard new ContextMenuFlyoutItemViewModel() { Text = "OpenInNewWindow".GetLocalizedResource(), - Glyph = "\uE737", + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconOpenInNewWindow", + }, Command = OpenInNewWindowCommand, CommandParameter = item, ShowItem = userSettingsService.PreferencesSettingsService.ShowOpenInNewWindow @@ -172,11 +177,9 @@ public override List GetItemMenuItems(WidgetCard new ContextMenuFlyoutItemViewModel() { Text = "OpenInNewPane".GetLocalizedResource(), - ColoredIcon = new ColoredIconModel() + OpacityIcon = new OpacityIconModel() { - BaseBackdropGlyph = "\uF056", - BaseLayerGlyph = "\uF03B", - OverlayLayerGlyph = "\uF03C", + OpacityIconStyle = "ColorIconRightPane", }, Command = OpenInNewPaneCommand, CommandParameter = item, @@ -201,7 +204,10 @@ public override List GetItemMenuItems(WidgetCard new ContextMenuFlyoutItemViewModel() { Text = "Properties".GetLocalizedResource(), - Glyph = "\uE946", + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconProperties", + }, Command = OpenPropertiesCommand, CommandParameter = item }, diff --git a/src/Files.App/UserControls/Widgets/RecentFilesWidget.xaml.cs b/src/Files.App/UserControls/Widgets/RecentFilesWidget.xaml.cs index 029e0dd361bd..b38d208b992b 100644 --- a/src/Files.App/UserControls/Widgets/RecentFilesWidget.xaml.cs +++ b/src/Files.App/UserControls/Widgets/RecentFilesWidget.xaml.cs @@ -121,14 +121,17 @@ private void Grid_RightTapped(object sender, RightTappedRoutedEventArgs e) e.Handled = true; } - public override List GetItemMenuItems(WidgetCardItem item, bool isPinned) + public override List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false) { return new List() { new ContextMenuFlyoutItemViewModel() { Text = "OpenItemsWithCaptionText".GetLocalizedResource(), - Glyph = "\uE17D", + OpacityIcon = new OpacityIconModel() + { + OpacityIconStyle = "ColorIconOpenWith", + }, Tag = "OpenWithPlaceholder", IsEnabled = false }, diff --git a/src/Files.App/UserControls/Widgets/WidgetCardItem.cs b/src/Files.App/UserControls/Widgets/WidgetCardItem.cs index c124e0b8ba44..c44860bf2a22 100644 --- a/src/Files.App/UserControls/Widgets/WidgetCardItem.cs +++ b/src/Files.App/UserControls/Widgets/WidgetCardItem.cs @@ -4,7 +4,7 @@ namespace Files.App.UserControls.Widgets { public abstract class WidgetCardItem : ObservableObject { - public string Path; + public virtual string Path { get; set; } public virtual object Item { get; set; } } diff --git a/src/Files.App/ViewModels/Widgets/FileTagsContainerViewModel.cs b/src/Files.App/ViewModels/Widgets/FileTagsContainerViewModel.cs new file mode 100644 index 000000000000..4ced3c407170 --- /dev/null +++ b/src/Files.App/ViewModels/Widgets/FileTagsContainerViewModel.cs @@ -0,0 +1,54 @@ +using System; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.DependencyInjection; +using Files.Backend.Services; +using Files.Shared.Utils; +using System.Collections.ObjectModel; +using System.Threading; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.Input; +using Files.Sdk.Storage.LocatableStorage; + +namespace Files.App.ViewModels.Widgets +{ + public sealed partial class FileTagsContainerViewModel : ObservableObject, IAsyncInitialize + { + private readonly string _tagUid; + private readonly Func _openAction; + + private IFileTagsService FileTagsService { get; } = Ioc.Default.GetRequiredService(); + + private IImageService ImageService { get; } = Ioc.Default.GetRequiredService(); + + public ObservableCollection Tags { get; } + + [ObservableProperty] + private string _Color; + + [ObservableProperty] + private string _Name; + + public FileTagsContainerViewModel(string tagUid, Func openAction) + { + _tagUid = tagUid; + _openAction = openAction; + Tags = new(); + } + + /// + public async Task InitAsync(CancellationToken cancellationToken = default) + { + await foreach (var item in FileTagsService.GetItemsForTagAsync(_tagUid, cancellationToken)) + { + var icon = await ImageService.GetIconAsync(item.Storable, cancellationToken); + Tags.Add(new(item.Storable, _openAction, icon)); + } + } + + [RelayCommand] + private Task ViewMore(CancellationToken cancellationToken) + { + return _openAction($"tag:{Name}"); + } + } +} diff --git a/src/Files.App/ViewModels/Widgets/FileTagsItemViewModel.cs b/src/Files.App/ViewModels/Widgets/FileTagsItemViewModel.cs new file mode 100644 index 000000000000..b88f3bf96105 --- /dev/null +++ b/src/Files.App/ViewModels/Widgets/FileTagsItemViewModel.cs @@ -0,0 +1,51 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using Files.Backend.Models; +using Files.Sdk.Storage.Extensions; +using Files.Sdk.Storage.LocatableStorage; +using System; +using System.Threading; +using System.Threading.Tasks; +using Files.Backend.Helpers; +using Files.App.UserControls.Widgets; + +namespace Files.App.ViewModels.Widgets +{ + public sealed partial class FileTagsItemViewModel : WidgetCardItem + { + private readonly ILocatableStorable _associatedStorable; + private readonly Func _openAction; // A workaround for lack of MVVM-compliant navigation support. + // This workaround must be kept until further refactor of navigation code is completed + + [ObservableProperty] + private IImageModel? _Icon; + + [ObservableProperty] + private string _Name; + + private string path; + public override string Path + { + get => path; + set => SetProperty(ref path, value); + } + + public bool IsFolder => _associatedStorable is ILocatableFolder; + + public FileTagsItemViewModel(ILocatableStorable associatedStorable, Func openAction, IImageModel? icon) + { + _associatedStorable = associatedStorable; + _openAction = openAction; + _Icon = icon; + _Name = PathHelpers.FormatName(associatedStorable.Path); + Path = associatedStorable.TryGetPath(); + Item = this; + } + + [RelayCommand] + private Task ClickAsync(CancellationToken cancellationToken) + { + return _openAction(_associatedStorable.Path); + } + } +} diff --git a/src/Files.App/ViewModels/Widgets/FileTagsWidgetViewModel.cs b/src/Files.App/ViewModels/Widgets/FileTagsWidgetViewModel.cs new file mode 100644 index 000000000000..216b30e5feb6 --- /dev/null +++ b/src/Files.App/ViewModels/Widgets/FileTagsWidgetViewModel.cs @@ -0,0 +1,43 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.DependencyInjection; +using Files.Backend.Services; +using Files.Backend.ViewModels.Widgets.FileTagsWidget; +using Files.Shared.Utils; +using System; +using System.Collections.ObjectModel; +using System.Threading; +using System.Threading.Tasks; + +namespace Files.App.ViewModels.Widgets +{ + public sealed partial class FileTagsWidgetViewModel : ObservableObject, IAsyncInitialize + { + private readonly Func _openAction; + + private IFileTagsService FileTagsService { get; } = Ioc.Default.GetRequiredService(); + + public ObservableCollection Containers { get; } + + public FileTagsWidgetViewModel(Func openAction) + { + _openAction = openAction; + Containers = new(); + } + + /// + public async Task InitAsync(CancellationToken cancellationToken = default) + { + await foreach (var item in FileTagsService.GetTagsAsync(cancellationToken)) + { + var container = new FileTagsContainerViewModel(item.Uid, _openAction) + { + Name = item.Name, + Color = item.Color + }; + Containers.Add(container); + + _ = container.InitAsync(cancellationToken); + } + } + } +} diff --git a/src/Files.App/Views/WidgetsPage.xaml.cs b/src/Files.App/Views/WidgetsPage.xaml.cs index cbe1959f3180..c0a41713cd7f 100644 --- a/src/Files.App/Views/WidgetsPage.xaml.cs +++ b/src/Files.App/Views/WidgetsPage.xaml.cs @@ -72,10 +72,10 @@ public void ReloadWidgets() Widgets.ViewModel.InsertWidget(new(quickAccessWidget, (value) => UserSettingsService.PreferencesSettingsService.FoldersWidgetExpanded = value, () => UserSettingsService.PreferencesSettingsService.FoldersWidgetExpanded), 0); quickAccessWidget.CardInvoked -= QuickAccessWidget_CardInvoked; - quickAccessWidget.CardNewPaneInvoked -= QuickAccessWidget_CardNewPaneInvoked; + quickAccessWidget.CardNewPaneInvoked -= WidgetCardNewPaneInvoked; quickAccessWidget.CardPropertiesInvoked -= QuickAccessWidget_CardPropertiesInvoked; quickAccessWidget.CardInvoked += QuickAccessWidget_CardInvoked; - quickAccessWidget.CardNewPaneInvoked += QuickAccessWidget_CardNewPaneInvoked; + quickAccessWidget.CardNewPaneInvoked += WidgetCardNewPaneInvoked; quickAccessWidget.CardPropertiesInvoked += QuickAccessWidget_CardPropertiesInvoked; } if (shouldReloadDrivesWidget && drivesWidget is not null) @@ -91,7 +91,13 @@ public void ReloadWidgets() if (shouldReloadFileTags && fileTagsWidget is not null) { Widgets.ViewModel.InsertWidget(new(fileTagsWidget, (value) => UserSettingsService.PreferencesSettingsService.FileTagsWidgetExpanded = value, () => UserSettingsService.PreferencesSettingsService.FileTagsWidgetExpanded), 2); + + fileTagsWidget.AppInstance = AppInstance; fileTagsWidget.OpenAction = x => NavigationHelpers.OpenPath(x, AppInstance); + fileTagsWidget.FileTagsOpenLocationInvoked -= WidgetOpenLocationInvoked; + fileTagsWidget.FileTagsNewPaneInvoked -= WidgetCardNewPaneInvoked; + fileTagsWidget.FileTagsOpenLocationInvoked += WidgetOpenLocationInvoked; + fileTagsWidget.FileTagsNewPaneInvoked += WidgetCardNewPaneInvoked; _ = fileTagsWidget.ViewModel.InitAsync(); } if (shouldReloadBundles && bundlesWidget is not null) @@ -103,9 +109,9 @@ public void ReloadWidgets() { Widgets.ViewModel.InsertWidget(new(recentFilesWidget, (value) => UserSettingsService.PreferencesSettingsService.RecentFilesWidgetExpanded = value, () => UserSettingsService.PreferencesSettingsService.RecentFilesWidgetExpanded), 4); - recentFilesWidget.RecentFilesOpenLocationInvoked -= RecentFilesWidget_RecentFilesOpenLocationInvoked; + recentFilesWidget.RecentFilesOpenLocationInvoked -= WidgetOpenLocationInvoked; recentFilesWidget.RecentFileInvoked -= RecentFilesWidget_RecentFileInvoked; - recentFilesWidget.RecentFilesOpenLocationInvoked += RecentFilesWidget_RecentFilesOpenLocationInvoked; + recentFilesWidget.RecentFilesOpenLocationInvoked += WidgetOpenLocationInvoked; recentFilesWidget.RecentFileInvoked += RecentFilesWidget_RecentFileInvoked; } } @@ -157,7 +163,7 @@ await DialogDisplayHelper.ShowDialogAsync( } } - private void RecentFilesWidget_RecentFilesOpenLocationInvoked(object sender, UserControls.PathNavigationEventArgs e) + private void WidgetOpenLocationInvoked(object sender, UserControls.PathNavigationEventArgs e) { AppInstance.NavigateWithArguments(FolderSettings.GetLayoutType(e.ItemPath), new NavigationArguments() { @@ -176,7 +182,7 @@ private void QuickAccessWidget_CardInvoked(object sender, QuickAccessCardInvoked AppInstance.InstanceViewModel.IsPageTypeNotHome = true; // show controls that were hidden on the home page } - private void QuickAccessWidget_CardNewPaneInvoked(object sender, QuickAccessCardInvokedEventArgs e) + private void WidgetCardNewPaneInvoked(object sender, QuickAccessCardInvokedEventArgs e) { AppInstance.PaneHolder?.OpenPathInNewPane(e.Path); }