From ecb3ceaf3a12f2e23af8460cb83fb2e3cfee1260 Mon Sep 17 00:00:00 2001 From: 0x5BFA <62196528+0x5bfa@users.noreply.github.com> Date: Sat, 9 Mar 2024 02:09:22 +0900 Subject: [PATCH] Initial commit --- .../Data/Contexts/HomePage/HomePageContext.cs | 4 +- .../Contexts/HomePage/IHomePageContext.cs | 2 +- .../Data/Contracts/IWidgetViewModel.cs | 2 +- .../QuickAccessCardEventArgs.cs | 10 - .../Data/Items/WidgetContainerItem.cs | 9 +- .../Data/Items/WidgetFileTagCardItem.cs | 13 +- .../Data/Items/WidgetFileTagsContainerItem.cs | 10 +- src/Files.App/Strings/en-US/Resources.resw | 6 - .../UserControls/Widgets/DrivesWidget.xaml | 11 +- .../UserControls/Widgets/DrivesWidget.xaml.cs | 269 ++------------ .../UserControls/Widgets/FileTagsWidget.xaml | 27 +- .../Widgets/FileTagsWidget.xaml.cs | 226 +----------- .../Widgets/QuickAccessWidget.xaml | 10 +- .../Widgets/QuickAccessWidget.xaml.cs | 328 +---------------- .../Widgets/RecentFilesWidget.xaml | 20 +- .../Widgets/RecentFilesWidget.xaml.cs | 340 +----------------- src/Files.App/Utils/Widgets/WidgetsHelpers.cs | 34 +- src/Files.App/ViewModels/HomeViewModel.cs | 83 ++++- .../Widgets/BaseWidgetViewModel.cs | 53 +-- .../Widgets/DrivesWidgetViewModel.cs | 271 ++++++++++++++ .../Widgets/FileTagsWidgetViewModel.cs | 210 ++++++++++- .../Widgets/QuickAccessWidgetViewModel.cs | 316 ++++++++++++++++ .../Widgets/RecentFilesWidgetViewModel.cs | 340 ++++++++++++++++++ src/Files.App/Views/HomePage.xaml.cs | 208 +---------- .../Views/Shells/ModernShellPage.xaml.cs | 2 +- 25 files changed, 1354 insertions(+), 1450 deletions(-) diff --git a/src/Files.App/Data/Contexts/HomePage/HomePageContext.cs b/src/Files.App/Data/Contexts/HomePage/HomePageContext.cs index bf671697dd4c..e8d0085dcee9 100644 --- a/src/Files.App/Data/Contexts/HomePage/HomePageContext.cs +++ b/src/Files.App/Data/Contexts/HomePage/HomePageContext.cs @@ -7,7 +7,7 @@ namespace Files.App.Data.Contexts { - internal class HomePageContext : ObservableObject, IHomePageContext + public class HomePageContext : ObservableObject, IHomePageContext { private static readonly IImmutableList emptyTaggedItems = Enumerable.Empty().ToImmutableList(); @@ -29,7 +29,7 @@ public IReadOnlyList SelectedTaggedItems public HomePageContext() { BaseWidgetViewModel.RightClickedItemChanged += HomePageWidget_RightClickedItemChanged; - FileTagsWidget.SelectedTaggedItemsChanged += FileTagsWidget_SelectedTaggedItemsChanged; + FileTagsWidgetViewModel.SelectedTaggedItemsChanged += FileTagsWidget_SelectedTaggedItemsChanged; } private void FileTagsWidget_SelectedTaggedItemsChanged(object? sender, IEnumerable e) diff --git a/src/Files.App/Data/Contexts/HomePage/IHomePageContext.cs b/src/Files.App/Data/Contexts/HomePage/IHomePageContext.cs index ccf515e49ded..345e162ac20c 100644 --- a/src/Files.App/Data/Contexts/HomePage/IHomePageContext.cs +++ b/src/Files.App/Data/Contexts/HomePage/IHomePageContext.cs @@ -5,7 +5,7 @@ namespace Files.App.Data.Contexts { - internal interface IHomePageContext + public interface IHomePageContext { /// /// The last right clicked item diff --git a/src/Files.App/Data/Contracts/IWidgetViewModel.cs b/src/Files.App/Data/Contracts/IWidgetViewModel.cs index f890b1fb45dc..051c815dd474 100644 --- a/src/Files.App/Data/Contracts/IWidgetViewModel.cs +++ b/src/Files.App/Data/Contracts/IWidgetViewModel.cs @@ -17,7 +17,7 @@ public interface IWidgetViewModel : IDisposable bool ShowMenuFlyout { get; } - MenuFlyoutItem MenuFlyoutItem { get; } + MenuFlyoutItem? MenuFlyoutItem { get; } Task RefreshWidgetAsync(); } diff --git a/src/Files.App/Data/EventArguments/QuickAccessCardEventArgs.cs b/src/Files.App/Data/EventArguments/QuickAccessCardEventArgs.cs index 672221b4c0c2..086b7d533148 100644 --- a/src/Files.App/Data/EventArguments/QuickAccessCardEventArgs.cs +++ b/src/Files.App/Data/EventArguments/QuickAccessCardEventArgs.cs @@ -3,16 +3,6 @@ namespace Files.App.Data.EventArguments { - public class QuickAccessCardEventArgs : EventArgs - { - public LocationItem? Item { get; set; } - } - - public class QuickAccessCardInvokedEventArgs : EventArgs - { - public string? Path { get; set; } - } - public class ModifyQuickAccessEventArgs : EventArgs { public string[]? Paths { get; set; } diff --git a/src/Files.App/Data/Items/WidgetContainerItem.cs b/src/Files.App/Data/Items/WidgetContainerItem.cs index 116250ba829e..3ae262abc7c7 100644 --- a/src/Files.App/Data/Items/WidgetContainerItem.cs +++ b/src/Files.App/Data/Items/WidgetContainerItem.cs @@ -17,8 +17,12 @@ public class WidgetContainerItem : ObservableObject, IDisposable // Properties + public IWidgetViewModel _WidgetItemModel; public IWidgetViewModel WidgetItemModel - => WidgetControl as IWidgetViewModel; + { + get => _WidgetItemModel; + set => SetProperty(ref _WidgetItemModel, value); + } public string WidgetAutomationProperties => WidgetItemModel.AutomationProperties; @@ -48,11 +52,12 @@ public bool IsExpanded // Constructor - public WidgetContainerItem(object widgetControl, Action expanderValueChangedCallback, Func expanderValueRequestedCallback) + public WidgetContainerItem(object widgetControl, IWidgetViewModel widgetItemModel, Action expanderValueChangedCallback, Func expanderValueRequestedCallback) { _expanderValueChangedCallback = expanderValueChangedCallback; _expanderValueRequestedCallback = expanderValueRequestedCallback; + WidgetItemModel = widgetItemModel; WidgetControl = widgetControl; } diff --git a/src/Files.App/Data/Items/WidgetFileTagCardItem.cs b/src/Files.App/Data/Items/WidgetFileTagCardItem.cs index b81e9f9a6bd8..d7ca78e81796 100644 --- a/src/Files.App/Data/Items/WidgetFileTagCardItem.cs +++ b/src/Files.App/Data/Items/WidgetFileTagCardItem.cs @@ -9,14 +9,14 @@ namespace Files.App.Data.Items { public sealed partial class WidgetFileTagCardItem : WidgetCardItem { + // Dependency injections + + private IContentPageContext ContentPageContext { get; } = Ioc.Default.GetRequiredService(); + // Fields private readonly IStorable _associatedStorable; - // A workaround for lack of MVVM-compliant navigation support. - // This workaround must be kept until further refactor of navigation code is completed. - private readonly Func _openAction; - // Properties public bool IsFolder @@ -47,10 +47,9 @@ public override string Path public ICommand ClickCommand { get; } - public WidgetFileTagCardItem(IStorable associatedStorable, Func openAction, IImage? icon) + public WidgetFileTagCardItem(IStorable associatedStorable, IImage? icon) { _associatedStorable = associatedStorable; - _openAction = openAction; _Icon = icon; _Name = associatedStorable.Name; _Path = associatedStorable.TryGetPath(); @@ -61,7 +60,7 @@ public WidgetFileTagCardItem(IStorable associatedStorable, Func op private Task ClickAsync() { - return _openAction(_associatedStorable.Id); + return NavigationHelpers.OpenPath(_associatedStorable.Id, ContentPageContext.ShellPage!); } } } diff --git a/src/Files.App/Data/Items/WidgetFileTagsContainerItem.cs b/src/Files.App/Data/Items/WidgetFileTagsContainerItem.cs index e99674c30fe3..08928f4ff05e 100644 --- a/src/Files.App/Data/Items/WidgetFileTagsContainerItem.cs +++ b/src/Files.App/Data/Items/WidgetFileTagsContainerItem.cs @@ -13,11 +13,10 @@ public sealed partial class WidgetFileTagsContainerItem : ObservableObject, IAsy private readonly IFileTagsService FileTagsService = Ioc.Default.GetRequiredService(); private readonly IImageService ImageService = Ioc.Default.GetRequiredService(); private readonly ICommandManager Commands = Ioc.Default.GetRequiredService(); + private IContentPageContext ContentPageContext { get; } = Ioc.Default.GetRequiredService(); private readonly string _tagUid; - private readonly Func _openAction; - // Properties public ObservableCollection Tags { get; } @@ -46,10 +45,9 @@ public sealed partial class WidgetFileTagsContainerItem : ObservableObject, IAsy public ICommand ViewMoreCommand { get; } public ICommand OpenAllCommand { get; } - public WidgetFileTagsContainerItem(string tagUid, Func openAction) + public WidgetFileTagsContainerItem(string tagUid) { _tagUid = tagUid; - _openAction = openAction; Tags = new(); ViewMoreCommand = new AsyncRelayCommand(ViewMore); @@ -62,13 +60,13 @@ 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)); + Tags.Add(new(item.Storable, icon)); } } private Task ViewMore(CancellationToken cancellationToken) { - return _openAction($"tag:{Name}"); + return NavigationHelpers.OpenPath($"tag:{Name}", ContentPageContext.ShellPage!); } private Task OpenAll(CancellationToken cancellationToken) diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw index 27c3707e11cc..9864e3067e33 100644 --- a/src/Files.App/Strings/en-US/Resources.resw +++ b/src/Files.App/Strings/en-US/Resources.resw @@ -1698,12 +1698,6 @@ UserName - - Drives widget - - - Recent Files widget - No items found diff --git a/src/Files.App/UserControls/Widgets/DrivesWidget.xaml b/src/Files.App/UserControls/Widgets/DrivesWidget.xaml index 74aa5f71355f..d9b305da6b92 100644 --- a/src/Files.App/UserControls/Widgets/DrivesWidget.xaml +++ b/src/Files.App/UserControls/Widgets/DrivesWidget.xaml @@ -1,22 +1,17 @@ - - + - + diff --git a/src/Files.App/UserControls/Widgets/DrivesWidget.xaml.cs b/src/Files.App/UserControls/Widgets/DrivesWidget.xaml.cs index 129a962a4618..1070eba867f9 100644 --- a/src/Files.App/UserControls/Widgets/DrivesWidget.xaml.cs +++ b/src/Files.App/UserControls/Widgets/DrivesWidget.xaml.cs @@ -1,23 +1,19 @@ // Copyright (c) 2023 Files Community // Licensed under the MIT License. See the LICENSE. -using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Input; -using System.Collections.Specialized; -using System.Runtime.CompilerServices; -using System.Windows.Input; -using Windows.System; -using Windows.UI.Core; namespace Files.App.UserControls.Widgets { /// /// Represents group of control displays a list of . /// - public sealed partial class DrivesWidget : BaseWidgetViewModel, IWidgetViewModel, INotifyPropertyChanged + public sealed partial class DrivesWidget : UserControl { +<<<<<<< HEAD +<<<<<<< HEAD private DrivesWidgetViewModel ViewModel { get; set; } public IUserSettingsService userSettingsService { get; } = Ioc.Default.GetRequiredService(); @@ -66,272 +62,53 @@ public IShellPage AppInstance }; public AsyncRelayCommand MapNetworkDriveCommand { get; } +======= + private DrivesWidgetViewModel ViewModel { get; set; } = new(); +>>>>>>> 70e2ff662 (Initial commit) +======= + public DrivesWidgetViewModel ViewModel { get; set; } = new(); +>>>>>>> 145267b14 (Fix) public DrivesWidget() { InitializeComponent(); - - Drives_CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - - drivesViewModel.Drives.CollectionChanged += Drives_CollectionChanged; - - FormatDriveCommand = new RelayCommand(FormatDrive); - EjectDeviceCommand = new AsyncRelayCommand(EjectDeviceAsync); - OpenInNewTabCommand = new AsyncRelayCommand(OpenInNewTabAsync); - OpenInNewWindowCommand = new AsyncRelayCommand(OpenInNewWindowAsync); - OpenInNewPaneCommand = new AsyncRelayCommand(OpenInNewPaneAsync); - OpenPropertiesCommand = new RelayCommand(OpenProperties); - PinToSidebarCommand = new AsyncRelayCommand(PinToSidebarAsync); - UnpinFromSidebarCommand = new AsyncRelayCommand(UnpinFromSidebarAsync); - MapNetworkDriveCommand = new AsyncRelayCommand(DoNetworkMapDriveAsync); - DisconnectNetworkDriveCommand = new RelayCommand(DisconnectNetworkDrive); - } - - private async void Drives_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) - { - await DispatcherQueue.EnqueueOrInvokeAsync(async () => - { - foreach (DriveItem drive in drivesViewModel.Drives.ToList()) - { - if (!ItemsAdded.Any(x => x.Item == drive) && drive.Type != DriveType.VirtualDrive) - { - var cardItem = new WidgetDriveCardItem(drive); - ItemsAdded.AddSorted(cardItem); - await cardItem.LoadCardThumbnailAsync(); // After add - } - } - - foreach (WidgetDriveCardItem driveCard in ItemsAdded.ToList()) - { - if (!drivesViewModel.Drives.Contains(driveCard.Item)) - ItemsAdded.Remove(driveCard); - } - }); - } - - 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; - - return new List() - { - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenInNewTab".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "ColorIconOpenInNewTab", - }, - Command = OpenInNewTabCommand, - CommandParameter = item, - ShowItem = userSettingsService.GeneralSettingsService.ShowOpenInNewTab - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenInNewWindow".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "ColorIconOpenInNewWindow", - }, - Command = OpenInNewWindowCommand, - CommandParameter = item, - ShowItem = userSettingsService.GeneralSettingsService.ShowOpenInNewWindow - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenInNewPane".GetLocalizedResource(), - Command = OpenInNewPaneCommand, - CommandParameter = item, - ShowItem = userSettingsService.GeneralSettingsService.ShowOpenInNewPane - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "PinFolderToSidebar".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "Icons.Pin.16x16", - }, - Command = PinToSidebarCommand, - CommandParameter = item, - ShowItem = !isPinned - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "UnpinFolderFromSidebar".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "Icons.Unpin.16x16", - }, - Command = UnpinFromSidebarCommand, - CommandParameter = item, - ShowItem = isPinned - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "Eject".GetLocalizedResource(), - Command = EjectDeviceCommand, - CommandParameter = item, - ShowItem = options?.ShowEjectDevice ?? false - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "FormatDriveText".GetLocalizedResource(), - Command = FormatDriveCommand, - CommandParameter = item, - ShowItem = options?.ShowFormatDrive ?? false - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "Properties".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "ColorIconProperties", - }, - Command = OpenPropertiesCommand, - CommandParameter = item - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "TurnOnBitLocker".GetLocalizedResource(), - Tag = "TurnOnBitLockerPlaceholder", - IsEnabled = false - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "ManageBitLocker".GetLocalizedResource(), - Tag = "ManageBitLockerPlaceholder", - IsEnabled = false - }, - new ContextMenuFlyoutItemViewModel() - { - ItemType = ContextMenuFlyoutItemType.Separator, - Tag = "OverflowSeparator", - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "Loading".GetLocalizedResource(), - Glyph = "\xE712", - Items = new List(), - ID = "ItemOverflow", - Tag = "ItemOverflow", - IsEnabled = false, - } - }.Where(x => x.ShowItem).ToList(); - } - - private Task DoNetworkMapDriveAsync() - { - return networkDrivesViewModel.OpenMapNetworkDriveDialogAsync(); - } - - private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - private async Task EjectDeviceAsync(WidgetDriveCardItem item) - { - var result = await DriveHelpers.EjectDeviceAsync(item.Item.Path); - await UIHelpers.ShowDeviceEjectResultAsync(item.Item.Type, result); - } - - private void FormatDrive(WidgetDriveCardItem? item) - { - Win32API.OpenFormatDriveDialog(item?.Path ?? string.Empty); - } - - private void OpenProperties(WidgetDriveCardItem item) - { - if (!HomePageContext.IsAnyItemRightClicked) - return; - - var flyout = HomePageContext.ItemContextFlyoutMenu; - EventHandler flyoutClosed = null!; - flyoutClosed = (s, e) => - { - flyout!.Closed -= flyoutClosed; - FilePropertiesHelpers.OpenPropertiesWindow(item.Item, associatedInstance); - }; - - flyout!.Closed += flyoutClosed; } private async void Button_Click(object sender, RoutedEventArgs e) { - string ClickedCard = (sender as Button).Tag.ToString(); - string NavigationPath = ClickedCard; // path to navigate - - if (await DriveHelpers.CheckEmptyDrive(NavigationPath)) + if (sender is not Button button) return; - var ctrlPressed = Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down); - if (ctrlPressed) - { - await NavigationHelpers.OpenPathInNewTab(NavigationPath, false); - return; - } + var path = button.Tag.ToString() ?? string.Empty; - DrivesWidgetInvoked?.Invoke(this, new DrivesWidgetInvokedEventArgs() - { - Path = NavigationPath - }); + await ViewModel.NavigateToPath(path); } private async void Button_PointerPressed(object sender, PointerRoutedEventArgs e) { - if (!e.GetCurrentPoint(null).Properties.IsMiddleButtonPressed) // check middle click - return; - string navigationPath = (sender as Button).Tag.ToString(); - if (await DriveHelpers.CheckEmptyDrive(navigationPath)) + if (!e.GetCurrentPoint(null).Properties.IsMiddleButtonPressed || sender is not Button button) return; - await NavigationHelpers.OpenPathInNewTab(navigationPath, false); - } - public class DrivesWidgetInvokedEventArgs : EventArgs - { - public string Path { get; set; } - } + var path = button.Tag.ToString() ?? string.Empty; - private async Task OpenInNewPaneAsync(WidgetDriveCardItem item) - { - if (await DriveHelpers.CheckEmptyDrive(item.Item.Path)) + if (await DriveHelpers.CheckEmptyDrive(path)) return; - DrivesWidgetNewPaneInvoked?.Invoke(this, new DrivesWidgetInvokedEventArgs() - { - Path = item.Item.Path - }); - } - private void MenuFlyout_Opening(object sender, object e) - { - var pinToSidebarItem = (sender as MenuFlyout).Items.Single(x => x.Name == "PinToSidebar"); - pinToSidebarItem.Visibility = (pinToSidebarItem.DataContext as DriveItem).IsPinned ? Visibility.Collapsed : Visibility.Visible; - - var unpinFromSidebarItem = (sender as MenuFlyout).Items.Single(x => x.Name == "UnpinFromSidebar"); - unpinFromSidebarItem.Visibility = (unpinFromSidebarItem.DataContext as DriveItem).IsPinned ? Visibility.Visible : Visibility.Collapsed; - } - - private void DisconnectNetworkDrive(WidgetDriveCardItem item) - { - networkDrivesViewModel.DisconnectNetworkDrive(item.Item); + await NavigationHelpers.OpenPathInNewTab(path, false); } - private void GoToStorageSense_Click(object sender, RoutedEventArgs e) + private void Button_RightTapped(object sender, RightTappedRoutedEventArgs e) { - string clickedCard = (sender as Button).Tag.ToString(); - StorageSenseHelper.OpenStorageSenseAsync(clickedCard); + ViewModel.BuildItemContextMenu(sender, e); } - public async Task RefreshWidgetAsync() - { - var updateTasks = ItemsAdded.Select(item => item.Item.UpdatePropertiesAsync()); - await Task.WhenAll(updateTasks); - } - - public void Dispose() + private async void GoToStorageSense_Click(object sender, RoutedEventArgs e) { + if (sender is not Button button) + return; + string path = button.Tag.ToString() ?? string.Empty; + await StorageSenseHelper.OpenStorageSenseAsync(path); } } } diff --git a/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml b/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml index 1b128f13099d..a165770b6170 100644 --- a/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml +++ b/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml @@ -1,15 +1,17 @@  ->>>>>> 70e2ff662 (Initial commit) DataContext="{x:Bind ViewModel, Mode=OneWay}" mc:Ignorable="d"> @@ -19,7 +21,7 @@ - + - - @@ -112,7 +112,7 @@ - - + + - + - + - - + + - + diff --git a/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml.cs b/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml.cs index 4f793c9cffbd..c7db3b1d692a 100644 --- a/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml.cs +++ b/src/Files.App/UserControls/Widgets/FileTagsWidget.xaml.cs @@ -1,14 +1,8 @@ // Copyright (c) 2023 Files Community // Licensed under the MIT License. See the LICENSE. -using Files.App.Helpers.ContextFlyouts; -using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Controls.Primitives; using Microsoft.UI.Xaml.Input; -using System.IO; -using System.Windows.Input; -using Windows.Storage; namespace Files.App.UserControls.Widgets { @@ -16,8 +10,9 @@ namespace Files.App.UserControls.Widgets /// Represents group of control displays a list of /// and its inner items with . /// - public sealed partial class FileTagsWidget : BaseWidgetViewModel, IWidgetViewModel + public sealed partial class FileTagsWidget : UserControl { +<<<<<<< HEAD public FileTagsWidgetViewModel ViewModel { get; set; } private readonly IUserSettingsService userSettingsService; @@ -41,229 +36,24 @@ public sealed partial class FileTagsWidget : BaseWidgetViewModel, IWidgetViewMod public MenuFlyoutItem? MenuFlyoutItem => null; private ICommand OpenInNewPaneCommand; +======= + public FileTagsWidgetViewModel ViewModel { get; set; } = new(); +>>>>>>> 70e2ff662 (Initial commit) public FileTagsWidget() { - userSettingsService = Ioc.Default.GetRequiredService(); - InitializeComponent(); - - // 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 AsyncRelayCommand(OpenInNewTabAsync); - OpenInNewWindowCommand = new AsyncRelayCommand(OpenInNewWindowAsync); - OpenFileLocationCommand = new RelayCommand(OpenFileLocation); - OpenInNewPaneCommand = new RelayCommand(OpenInNewPane); - PinToSidebarCommand = new AsyncRelayCommand(PinToSidebarAsync); - UnpinFromSidebarCommand = new AsyncRelayCommand(UnpinFromSidebarAsync); - OpenPropertiesCommand = new RelayCommand(OpenProperties); - } - - private void OpenProperties(WidgetCardItem? item) - { - if (!HomePageContext.IsAnyItemRightClicked) - return; - - var flyout = HomePageContext.ItemContextFlyoutMenu; - EventHandler flyoutClosed = null!; - flyoutClosed = (s, e) => - { - flyout!.Closed -= flyoutClosed; - - ListedItem listedItem = new(null!) - { - ItemPath = (item.Item as WidgetFileTagCardItem)?.Path ?? string.Empty, - ItemNameRaw = (item.Item as WidgetFileTagCardItem)?.Name ?? string.Empty, - PrimaryItemAttribute = StorageItemTypes.Folder, - ItemType = "Folder".GetLocalizedResource(), - }; - FilePropertiesHelpers.OpenPropertiesWindow(listedItem, AppInstance); - }; - - flyout!.Closed += flyoutClosed; - } - - private void OpenInNewPane(WidgetCardItem? item) - { - FileTagsNewPaneInvoked?.Invoke(this, new QuickAccessCardInvokedEventArgs() - { - Path = item?.Path ?? string.Empty - }); } private void FileTagItem_ItemClick(object sender, ItemClickEventArgs e) { - if (e.ClickedItem is WidgetFileTagCardItem itemViewModel) - itemViewModel.ClickCommand.Execute(null); + if (e.ClickedItem is WidgetFileTagCardItem item) + item.ClickCommand.Execute(null); } private void AdaptiveGridView_RightTapped(object sender, RightTappedRoutedEventArgs e) { - // Ensure values are not null - if (e.OriginalSource is not FrameworkElement element || - element.DataContext is not WidgetFileTagCardItem item) - return; - - // Create a new Flyout - var itemContextMenuFlyout = new CommandBarFlyout() - { - Placement = FlyoutPlacementMode.Full - }; - - // Hook events - itemContextMenuFlyout.Opening += (sender, e) => App.LastOpenedFlyout = sender as CommandBarFlyout; - itemContextMenuFlyout.Closed += (sender, e) => OnRightClickedItemChanged(null, null); - - _flyoutItemPath = item.Path; - - // Notify of the change on right clicked item - OnRightClickedItemChanged(item, itemContextMenuFlyout); - - // Get items for the flyout - var menuItems = GetItemMenuItems(item, QuickAccessService.IsItemPinned(item.Path), item.IsFolder); - var (_, secondaryElements) = ContextFlyoutModelToElementHelper.GetAppBarItemsFromModel(menuItems); - - // Set max width of the flyout - secondaryElements - .OfType() - .ForEach(i => i.MinWidth = Constants.UI.ContextMenuItemsMaxWidth); - - // Add menu items to the secondary flyout - secondaryElements.ForEach(itemContextMenuFlyout.SecondaryCommands.Add); - - // Show the flyout - itemContextMenuFlyout.ShowAt(element, new() { Position = e.GetPosition(element) }); - - // Load shell menu items - _ = ShellContextFlyoutFactory.LoadShellMenuItemsAsync(_flyoutItemPath, itemContextMenuFlyout, null, true, true); - - e.Handled = true; - } - - public override List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false) - { - return new List() - { - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenWith".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "ColorIconOpenWith", - }, - Tag = "OpenWithPlaceholder", - ShowItem = !isFolder - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "SendTo".GetLocalizedResource(), - Tag = "SendToPlaceholder", - ShowItem = !isFolder && userSettingsService.GeneralSettingsService.ShowSendToMenu - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenInNewTab".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "ColorIconOpenInNewTab", - }, - Command = OpenInNewTabCommand, - CommandParameter = item, - ShowItem = isFolder - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenInNewWindow".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "ColorIconOpenInNewWindow", - }, - Command = OpenInNewWindowCommand, - CommandParameter = item, - ShowItem = isFolder - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenFileLocation".GetLocalizedResource(), - Glyph = "\uED25", - Command = OpenFileLocationCommand, - CommandParameter = item, - ShowItem = !isFolder - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenInNewPane".GetLocalizedResource(), - Command = OpenInNewPaneCommand, - CommandParameter = item, - ShowItem = userSettingsService.GeneralSettingsService.ShowOpenInNewPane && isFolder - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "PinFolderToSidebar".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "Icons.Pin.16x16", - }, - Command = PinToSidebarCommand, - CommandParameter = item, - ShowItem = !isPinned && isFolder - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "UnpinFolderFromSidebar".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "Icons.Unpin.16x16", - }, - Command = UnpinFromSidebarCommand, - CommandParameter = item, - ShowItem = isPinned && isFolder - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "Properties".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "ColorIconProperties", - }, - Command = OpenPropertiesCommand, - CommandParameter = item, - ShowItem = isFolder - }, - new ContextMenuFlyoutItemViewModel() - { - ItemType = ContextMenuFlyoutItemType.Separator, - Tag = "OverflowSeparator", - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "Loading".GetLocalizedResource(), - Glyph = "\xE712", - Items = new List(), - ID = "ItemOverflow", - Tag = "ItemOverflow", - IsEnabled = false, - } - }.Where(x => x.ShowItem).ToList(); - } - - public void OpenFileLocation(WidgetCardItem? item) - { - FileTagsOpenLocationInvoked?.Invoke(this, new PathNavigationEventArgs() - { - ItemPath = Directory.GetParent(item?.Path ?? string.Empty)?.FullName ?? string.Empty, - ItemName = Path.GetFileName(item?.Path ?? string.Empty), - }); - } - - public Task RefreshWidgetAsync() - { - return Task.CompletedTask; - } - - public void Dispose() - { + ViewModel.BuildItemContextMenu(e.OriginalSource, e); } } } diff --git a/src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml b/src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml index 40321096abf3..376e5c132750 100644 --- a/src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml +++ b/src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml @@ -1,20 +1,16 @@  - - + - + diff --git a/src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml.cs b/src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml.cs index 71d98d0e3a5e..efc4466a01f8 100644 --- a/src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml.cs +++ b/src/Files.App/UserControls/Widgets/QuickAccessWidget.xaml.cs @@ -4,20 +4,16 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Input; -using System.Collections.Specialized; -using System.IO; -using System.Runtime.CompilerServices; -using System.Windows.Input; -using Windows.System; -using Windows.UI.Core; namespace Files.App.UserControls.Widgets { /// /// Represents group of control displays a list of quick access folders with . /// - public sealed partial class QuickAccessWidget : BaseWidgetViewModel, IWidgetViewModel, INotifyPropertyChanged + public sealed partial class QuickAccessWidget : UserControl { +<<<<<<< HEAD +<<<<<<< HEAD private QuickAccessWidgetViewModel ViewModel { get; set; } public IUserSettingsService userSettingsService { get; } = Ioc.Default.GetRequiredService(); @@ -29,330 +25,38 @@ static QuickAccessWidget() { ItemsAdded.CollectionChanged += ItemsAdded_CollectionChanged; } +======= + private QuickAccessWidgetViewModel ViewModel { get; set; } = new(); +>>>>>>> 70e2ff662 (Initial commit) +======= + public QuickAccessWidgetViewModel ViewModel { get; set; } = new(); +>>>>>>> 145267b14 (Fix) public QuickAccessWidget() { InitializeComponent(); - - Loaded += QuickAccessWidget_Loaded; - Unloaded += QuickAccessWidget_Unloaded; - - OpenInNewTabCommand = new AsyncRelayCommand(OpenInNewTabAsync); - OpenInNewWindowCommand = new AsyncRelayCommand(OpenInNewWindowAsync); - OpenInNewPaneCommand = new RelayCommand(OpenInNewPane); - OpenPropertiesCommand = new RelayCommand(OpenProperties); - PinToSidebarCommand = new AsyncRelayCommand(PinToSidebarAsync); - UnpinFromSidebarCommand = new AsyncRelayCommand(UnpinFromSidebarAsync); - } - - public delegate void QuickAccessCardInvokedEventHandler(object sender, QuickAccessCardInvokedEventArgs e); - public delegate void QuickAccessCardNewPaneInvokedEventHandler(object sender, QuickAccessCardInvokedEventArgs e); - public delegate void QuickAccessCardPropertiesInvokedEventHandler(object sender, QuickAccessCardEventArgs e); - public event QuickAccessCardInvokedEventHandler CardInvoked; - public event QuickAccessCardNewPaneInvokedEventHandler CardNewPaneInvoked; - public event QuickAccessCardPropertiesInvokedEventHandler CardPropertiesInvoked; - public event EventHandler QuickAccessWidgetShowMultiPaneControlsInvoked; - public event PropertyChangedEventHandler PropertyChanged; - - public bool IsWidgetSettingEnabled => UserSettingsService.GeneralSettingsService.ShowQuickAccessWidget; - public bool ShowMenuFlyout => false; - public MenuFlyoutItem? MenuFlyoutItem => null; - - public ICommand OpenPropertiesCommand; - public ICommand OpenInNewPaneCommand; - - public string WidgetName => nameof(QuickAccessWidget); - public string AutomationProperties => "QuickAccess".GetLocalizedResource(); - public string WidgetHeader => "QuickAccess".GetLocalizedResource(); - - public override List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false) - { - return new List() - { - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenInNewTab".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "ColorIconOpenInNewTab", - }, - Command = OpenInNewTabCommand, - CommandParameter = item, - ShowItem = userSettingsService.GeneralSettingsService.ShowOpenInNewTab - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenInNewWindow".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "ColorIconOpenInNewWindow", - }, - Command = OpenInNewWindowCommand, - CommandParameter = item, - ShowItem = userSettingsService.GeneralSettingsService.ShowOpenInNewWindow - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenInNewPane".GetLocalizedResource(), - Command = OpenInNewPaneCommand, - CommandParameter = item, - ShowItem = userSettingsService.GeneralSettingsService.ShowOpenInNewPane - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "PinFolderToSidebar".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "Icons.Pin.16x16", - }, - Command = PinToSidebarCommand, - CommandParameter = item, - ShowItem = !isPinned - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "UnpinFolderFromSidebar".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "Icons.Unpin.16x16", - }, - Command = UnpinFromSidebarCommand, - CommandParameter = item, - ShowItem = isPinned - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "Properties".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "ColorIconProperties", - }, - Command = OpenPropertiesCommand, - CommandParameter = item - }, - new ContextMenuFlyoutItemViewModel() - { - ItemType = ContextMenuFlyoutItemType.Separator, - Tag = "OverflowSeparator", - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "Loading".GetLocalizedResource(), - Glyph = "\xE712", - Items = new List(), - ID = "ItemOverflow", - Tag = "ItemOverflow", - IsEnabled = false, - } - }.Where(x => x.ShowItem).ToList(); - } - - private async void ModifyItemAsync(object? sender, ModifyQuickAccessEventArgs? e) - { - if (e is null) - return; - - await DispatcherQueue.EnqueueOrInvokeAsync(async () => - { - if (e.Reset) - { - // Find the intersection between the two lists and determine whether to remove or add - var originalItemsAdded = ItemsAdded.ToList(); - var itemsToRemove = originalItemsAdded.Where(x => !e.Paths.Contains(x.Path)); - var itemsToAdd = e.Paths.Where(x => !originalItemsAdded.Any(y => y.Path == x)); - - // Remove items - foreach (var itemToRemove in itemsToRemove) - ItemsAdded.Remove(itemToRemove); - - // Add items - foreach (var itemToAdd in itemsToAdd) - { - var interimItemsAdded = ItemsAdded.ToList(); - var item = await App.QuickAccessManager.Model.CreateLocationItemFromPathAsync(itemToAdd); - var lastIndex = ItemsAdded.IndexOf(interimItemsAdded.FirstOrDefault(x => !x.IsPinned)); - var isPinned = (bool?)e.Items.Where(x => x.FilePath == itemToAdd).FirstOrDefault()?.Properties["System.Home.IsPinned"] ?? false; - if (interimItemsAdded.Any(x => x.Path == itemToAdd)) - continue; - - ItemsAdded.Insert(isPinned && lastIndex >= 0 ? Math.Min(lastIndex, ItemsAdded.Count) : ItemsAdded.Count, new WidgetFolderCardItem(item, Path.GetFileName(item.Text), isPinned) - { - Path = item.Path, - }); - } - - return; - } - if (e.Reorder) - { - // Remove pinned items - foreach (var itemToRemove in ItemsAdded.ToList().Where(x => x.IsPinned)) - ItemsAdded.Remove(itemToRemove); - - // Add pinned items in the new order - foreach (var itemToAdd in e.Paths) - { - var interimItemsAdded = ItemsAdded.ToList(); - var item = await App.QuickAccessManager.Model.CreateLocationItemFromPathAsync(itemToAdd); - var lastIndex = ItemsAdded.IndexOf(interimItemsAdded.FirstOrDefault(x => !x.IsPinned)); - if (interimItemsAdded.Any(x => x.Path == itemToAdd)) - continue; - - ItemsAdded.Insert(lastIndex >= 0 ? Math.Min(lastIndex, ItemsAdded.Count) : ItemsAdded.Count, new WidgetFolderCardItem(item, Path.GetFileName(item.Text), true) - { - Path = item.Path, - }); - } - - return; - } - if (e.Add) - { - foreach (var itemToAdd in e.Paths) - { - var interimItemsAdded = ItemsAdded.ToList(); - var item = await App.QuickAccessManager.Model.CreateLocationItemFromPathAsync(itemToAdd); - var lastIndex = ItemsAdded.IndexOf(interimItemsAdded.FirstOrDefault(x => !x.IsPinned)); - if (interimItemsAdded.Any(x => x.Path == itemToAdd)) - continue; - ItemsAdded.Insert(e.Pin && lastIndex >= 0 ? Math.Min(lastIndex, ItemsAdded.Count) : ItemsAdded.Count, new WidgetFolderCardItem(item, Path.GetFileName(item.Text), e.Pin) // Add just after the Recent Folders - { - Path = item.Path, - }); - } - } - else - foreach (var itemToRemove in ItemsAdded.ToList().Where(x => e.Paths.Contains(x.Path))) - ItemsAdded.Remove(itemToRemove); - }); - } - - private async void QuickAccessWidget_Loaded(object sender, RoutedEventArgs e) - { - Loaded -= QuickAccessWidget_Loaded; - - var itemsToAdd = await QuickAccessService.GetPinnedFoldersAsync(); - ModifyItemAsync(this, new ModifyQuickAccessEventArgs(itemsToAdd.ToArray(), false) - { - Reset = true - }); - - App.QuickAccessManager.UpdateQuickAccessWidget += ModifyItemAsync; - } - - private void QuickAccessWidget_Unloaded(object sender, RoutedEventArgs e) - { - Unloaded -= QuickAccessWidget_Unloaded; - App.QuickAccessManager.UpdateQuickAccessWidget -= ModifyItemAsync; - } - - private static async void ItemsAdded_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) - { - if (e.Action is NotifyCollectionChangedAction.Add) - { - foreach (WidgetFolderCardItem cardItem in e.NewItems!) - await cardItem.LoadCardThumbnailAsync(); - } - } - - private void MenuFlyout_Opening(object sender) - { - var pinToSidebarItem = (sender as MenuFlyout)?.Items.SingleOrDefault(x => x.Name == "PinToSidebar"); - if (pinToSidebarItem is not null) - pinToSidebarItem.Visibility = (pinToSidebarItem.DataContext as WidgetFolderCardItem)?.IsPinned ?? false ? Visibility.Collapsed : Visibility.Visible; - - var unpinFromSidebarItem = (sender as MenuFlyout)?.Items.SingleOrDefault(x => x.Name == "UnpinFromSidebar"); - if (unpinFromSidebarItem is not null) - unpinFromSidebarItem.Visibility = (unpinFromSidebarItem.DataContext as WidgetFolderCardItem)?.IsPinned ?? false ? Visibility.Visible : Visibility.Collapsed; - } - - private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - private void OpenInNewPane(WidgetFolderCardItem item) - { - CardNewPaneInvoked?.Invoke(this, new QuickAccessCardInvokedEventArgs { Path = item.Path }); } private async void Button_PointerPressed(object sender, PointerRoutedEventArgs e) { - if (e.GetCurrentPoint(null).Properties.IsMiddleButtonPressed) // check middle click - { - string navigationPath = ((Button)sender).Tag.ToString()!; - await NavigationHelpers.OpenPathInNewTab(navigationPath, false); - } - } - - private void OpenProperties(WidgetFolderCardItem item) - { - if (!HomePageContext.IsAnyItemRightClicked) + if (!e.GetCurrentPoint(null).Properties.IsMiddleButtonPressed || sender is not Button button) return; - var flyout = HomePageContext.ItemContextFlyoutMenu; - EventHandler flyoutClosed = null!; - - flyoutClosed = (s, e) => - { - flyout!.Closed -= flyoutClosed; - CardPropertiesInvoked?.Invoke(this, new QuickAccessCardEventArgs { Item = item.Item }); - }; - - flyout!.Closed += flyoutClosed; - } - - public override async Task PinToSidebarAsync(WidgetCardItem item) - { - await QuickAccessService.PinToSidebarAsync(item.Path); - - ModifyItemAsync(this, new ModifyQuickAccessEventArgs(new[] { item.Path }, false)); - - var items = (await QuickAccessService.GetPinnedFoldersAsync()) - .Where(link => !((bool?)link.Properties["System.Home.IsPinned"] ?? false)); - - var recentItem = items.Where(x => !ItemsAdded.ToList().Select(y => y.Path).Contains(x.FilePath)).FirstOrDefault(); - if (recentItem is not null) - { - ModifyItemAsync(this, new ModifyQuickAccessEventArgs(new[] { recentItem.FilePath }, true) - { - Pin = false - }); - } - } - - public override async Task UnpinFromSidebarAsync(WidgetCardItem item) - { - await QuickAccessService.UnpinFromSidebarAsync(item.Path); - - ModifyItemAsync(this, new ModifyQuickAccessEventArgs(new[] { item.Path }, false)); + string path = button.Tag.ToString()!; + await NavigationHelpers.OpenPathInNewTab(path, false); } private async void Button_Click(object sender, RoutedEventArgs e) { - string ClickedCard = (sender as Button).Tag.ToString(); - string NavigationPath = ClickedCard; // path to navigate - - if (string.IsNullOrEmpty(NavigationPath)) - return; - - var ctrlPressed = Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down); - if (ctrlPressed) - { - await NavigationHelpers.OpenPathInNewTab(NavigationPath, false); + if (sender is not Button button || button.Tag.ToString() is not string path) return; - } - CardInvoked?.Invoke(this, new QuickAccessCardInvokedEventArgs { Path = NavigationPath }); - } - - public Task RefreshWidgetAsync() - { - return Task.CompletedTask; + await ViewModel.NavigateToPath(path); } - public void Dispose() + private void Button_RightTapped(object sender, RightTappedRoutedEventArgs e) { + ViewModel.BuildItemContextMenu(sender, e); } } } diff --git a/src/Files.App/UserControls/Widgets/RecentFilesWidget.xaml b/src/Files.App/UserControls/Widgets/RecentFilesWidget.xaml index 99954af4b46b..0d822fca475f 100644 --- a/src/Files.App/UserControls/Widgets/RecentFilesWidget.xaml +++ b/src/Files.App/UserControls/Widgets/RecentFilesWidget.xaml @@ -1,23 +1,21 @@ - - + - @@ -93,4 +91,4 @@ - \ No newline at end of file + diff --git a/src/Files.App/UserControls/Widgets/RecentFilesWidget.xaml.cs b/src/Files.App/UserControls/Widgets/RecentFilesWidget.xaml.cs index 6b82822e1cd4..9bddebcabf8d 100644 --- a/src/Files.App/UserControls/Widgets/RecentFilesWidget.xaml.cs +++ b/src/Files.App/UserControls/Widgets/RecentFilesWidget.xaml.cs @@ -1,25 +1,18 @@ // Copyright (c) 2023 Files Community // Licensed under the MIT License. See the LICENSE. -using Files.App.Helpers.ContextFlyouts; -using Microsoft.Extensions.Logging; -using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Controls.Primitives; using Microsoft.UI.Xaml.Input; -using System.Collections.Specialized; -using System.IO; -using System.Runtime.CompilerServices; -using Windows.Foundation.Metadata; -using Windows.System; namespace Files.App.UserControls.Widgets { /// /// Represents group of control displays a list of recent folders with . /// - public sealed partial class RecentFilesWidget : BaseWidgetViewModel, IWidgetViewModel, INotifyPropertyChanged + public sealed partial class RecentFilesWidget : UserControl { +<<<<<<< HEAD +<<<<<<< HEAD private RecentFilesWidgetViewModel ViewModel { get; set; } private IHomePageContext HomePageContext { get; } = Ioc.Default.GetRequiredService(); @@ -87,334 +80,29 @@ public IShellPage AppInstance } } } +======= + private RecentFilesWidgetViewModel ViewModel { get; set; } = new(); +>>>>>>> 70e2ff662 (Initial commit) +======= + public RecentFilesWidgetViewModel ViewModel { get; set; } = new(); +>>>>>>> 145267b14 (Fix) public RecentFilesWidget() { InitializeComponent(); - - refreshRecentsSemaphore = new SemaphoreSlim(1, 1); - refreshRecentsCTS = new CancellationTokenSource(); - - // recent files could have changed while widget wasn't loaded - _ = RefreshWidgetAsync(); - - App.RecentItemsManager.RecentFilesChanged += Manager_RecentFilesChanged; - - RemoveRecentItemCommand = new AsyncRelayCommand(RemoveRecentItemAsync); - ClearAllItemsCommand = new AsyncRelayCommand(ClearRecentItemsAsync); - OpenFileLocationCommand = new RelayCommand(OpenFileLocation); - OpenPropertiesCommand = new RelayCommand(OpenProperties); - } - - private void ListView_RightTapped(object sender, RightTappedRoutedEventArgs e) - { - // Ensure values are not null - if (e.OriginalSource is not FrameworkElement element || - element.DataContext is not RecentItem item) - return; - - // Create a new Flyout - var itemContextMenuFlyout = new CommandBarFlyout() - { - Placement = FlyoutPlacementMode.Full - }; - - // Hook events - itemContextMenuFlyout.Opening += (sender, e) => App.LastOpenedFlyout = sender as CommandBarFlyout; - itemContextMenuFlyout.Closed += (sender, e) => OnRightClickedItemChanged(null, null); - - _flyoutItemPath = item.Path; - - // Notify of the change on right clicked item - OnRightClickedItemChanged(item, itemContextMenuFlyout); - - // Get items for the flyout - var menuItems = GetItemMenuItems(item, QuickAccessService.IsItemPinned(item.Path)); - var (_, secondaryElements) = ContextFlyoutModelToElementHelper.GetAppBarItemsFromModel(menuItems); - - // Set max width of the flyout - secondaryElements - .OfType() - .ForEach(i => i.MinWidth = Constants.UI.ContextMenuItemsMaxWidth); - - // Add menu items to the secondary flyout - secondaryElements.ForEach(itemContextMenuFlyout.SecondaryCommands.Add); - - // Show the flyout - itemContextMenuFlyout.ShowAt(element, new() { Position = e.GetPosition(element) }); - - // Load shell menu items - _ = ShellContextFlyoutFactory.LoadShellMenuItemsAsync(_flyoutItemPath, itemContextMenuFlyout, null, true, true); - } - - public override List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false) - { - return new List() - { - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenWith".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "ColorIconOpenWith", - }, - Tag = "OpenWithPlaceholder", - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "SendTo".GetLocalizedResource(), - Tag = "SendToPlaceholder", - ShowItem = userSettingsService.GeneralSettingsService.ShowSendToMenu - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "RecentItemRemove/Text".GetLocalizedResource(), - Glyph = "\uE738", - Command = RemoveRecentItemCommand, - CommandParameter = item - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "RecentItemClearAll/Text".GetLocalizedResource(), - Glyph = "\uE74D", - Command = ClearAllItemsCommand - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "OpenFileLocation".GetLocalizedResource(), - Glyph = "\uED25", - Command = OpenFileLocationCommand, - CommandParameter = item - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "Properties".GetLocalizedResource(), - OpacityIcon = new OpacityIconModel() - { - OpacityIconStyle = "ColorIconProperties", - }, - Command = OpenPropertiesCommand, - CommandParameter = item - }, - new ContextMenuFlyoutItemViewModel() - { - ItemType = ContextMenuFlyoutItemType.Separator, - Tag = "OverflowSeparator", - }, - new ContextMenuFlyoutItemViewModel() - { - Text = "Loading".GetLocalizedResource(), - Glyph = "\xE712", - Items = new List(), - ID = "ItemOverflow", - Tag = "ItemOverflow", - IsEnabled = false, - } - }.Where(x => x.ShowItem).ToList(); - } - - public async Task RefreshWidgetAsync() - { - IsRecentFilesDisabledInWindows = App.RecentItemsManager.CheckIsRecentFilesEnabled() is false; - await App.RecentItemsManager.UpdateRecentFilesAsync(); - } - - private async void Manager_RecentFilesChanged(object sender, NotifyCollectionChangedEventArgs e) - { - await DispatcherQueue.EnqueueOrInvokeAsync(async () => - { - // e.Action can only be Reset right now; naively refresh everything for simplicity - await UpdateRecentsListAsync(e); - }); - } - - private void OpenFileLocation(RecentItem item) - { - RecentFilesOpenLocationInvoked?.Invoke(this, new PathNavigationEventArgs() - { - ItemPath = Directory.GetParent(item.RecentPath).FullName, // parent directory - ItemName = Path.GetFileName(item.RecentPath), // file name w extension - }); - } - - private void OpenProperties(RecentItem item) - { - var flyout = HomePageContext.ItemContextFlyoutMenu; - - if (item is null || flyout is null) - return; - - EventHandler flyoutClosed = null!; - flyoutClosed = async (s, e) => - { - flyout!.Closed -= flyoutClosed; - - BaseStorageFile file = await FilesystemTasks.Wrap(() => StorageFileExtensions.DangerousGetFileFromPathAsync(item.Path)); - if (file is null) - { - ContentDialog dialog = new() - { - Title = "CannotAccessPropertiesTitle".GetLocalizedResource(), - Content = "CannotAccessPropertiesContent".GetLocalizedResource(), - PrimaryButtonText = "Ok".GetLocalizedResource() - }; - - if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8)) - dialog.XamlRoot = MainWindow.Instance.Content.XamlRoot; - - await dialog.TryShowAsync(); - } - else - { - var listedItem = await UniversalStorageEnumerator.AddFileAsync(file, null, default); - FilePropertiesHelpers.OpenPropertiesWindow(listedItem, associatedInstance); - } - }; - flyout!.Closed += flyoutClosed; } - private async Task UpdateRecentsListAsync(NotifyCollectionChangedEventArgs e) + private void RecentFilesView_ItemClick(object sender, ItemClickEventArgs e) { - try - { - await refreshRecentsSemaphore.WaitAsync(refreshRecentsCTS.Token); - } - catch (OperationCanceledException) - { + if (e.ClickedItem is not RecentItem item) return; - } - - try - { - // drop other waiting instances - refreshRecentsCTS.Cancel(); - refreshRecentsCTS = new CancellationTokenSource(); - - IsEmptyRecentsTextVisible = false; - - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - if (e.NewItems is not null) - { - var addedItem = e.NewItems.Cast().Single(); - AddItemToRecentList(addedItem, 0); - } - break; - - case NotifyCollectionChangedAction.Move: - if (e.OldItems is not null) - { - var movedItem = e.OldItems.Cast().Single(); - recentItemsCollection.RemoveAt(e.OldStartingIndex); - AddItemToRecentList(movedItem, 0); - } - break; - - case NotifyCollectionChangedAction.Remove: - if (e.OldItems is not null) - { - var removedItem = e.OldItems.Cast().Single(); - recentItemsCollection.RemoveAt(e.OldStartingIndex); - } - break; - - // case NotifyCollectionChangedAction.Reset: - default: - var recentFiles = App.RecentItemsManager.RecentFiles; // already sorted, add all in order - if (!recentFiles.SequenceEqual(recentItemsCollection)) - { - recentItemsCollection.Clear(); - foreach (var item in recentFiles) - { - AddItemToRecentList(item); - } - } - break; - } - - // update chevron if there aren't any items - if (recentItemsCollection.Count == 0 && !IsRecentFilesDisabledInWindows) - { - IsEmptyRecentsTextVisible = true; - } - } - catch (Exception ex) - { - App.Logger.LogInformation(ex, "Could not populate recent files"); - } - finally - { - refreshRecentsSemaphore.Release(); - } - } - - /// - /// Add the RecentItem to the ObservableCollection for the UI to render. - /// - /// The recent item to be added - private bool AddItemToRecentList(RecentItem recentItem, int index = -1) - { - if (!recentItemsCollection.Any(x => x.Equals(recentItem))) - { - recentItemsCollection.Insert(index < 0 ? recentItemsCollection.Count : Math.Min(index, recentItemsCollection.Count), recentItem); - _ = recentItem.LoadRecentItemIconAsync() - .ContinueWith(t => App.Logger.LogWarning(t.Exception, null), TaskContinuationOptions.OnlyOnFaulted); - return true; - } - return false; - } - - private void RecentsView_ItemClick(object sender, ItemClickEventArgs e) - { - var recentItem = e.ClickedItem as RecentItem; - RecentFileInvoked?.Invoke(this, new PathNavigationEventArgs() - { - ItemPath = recentItem.RecentPath, - }); - } - private async Task RemoveRecentItemAsync(RecentItem item) - { - await refreshRecentsSemaphore.WaitAsync(); - - try - { - await App.RecentItemsManager.UnpinFromRecentFiles(item); - } - finally - { - refreshRecentsSemaphore.Release(); - } + ViewModel.NavigateToPath(item.RecentPath); } - private async Task ClearRecentItemsAsync() - { - await refreshRecentsSemaphore.WaitAsync(); - try - { - recentItemsCollection.Clear(); - bool success = App.RecentItemsManager.ClearRecentItems(); - - if (success) - { - IsEmptyRecentsTextVisible = true; - } - } - finally - { - refreshRecentsSemaphore.Release(); - } - } - - private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - public void Dispose() + private void ListView_RightTapped(object sender, RightTappedRoutedEventArgs e) { - App.RecentItemsManager.RecentFilesChanged -= Manager_RecentFilesChanged; + ViewModel.BuildItemContextMenu(e.OriginalSource, e); } } } diff --git a/src/Files.App/Utils/Widgets/WidgetsHelpers.cs b/src/Files.App/Utils/Widgets/WidgetsHelpers.cs index 1ff02cec1011..0da8260d7687 100644 --- a/src/Files.App/Utils/Widgets/WidgetsHelpers.cs +++ b/src/Files.App/Utils/Widgets/WidgetsHelpers.cs @@ -1,55 +1,51 @@ // Copyright (c) 2023 Files Community // Licensed under the MIT License. See the LICENSE. -using Files.App.UserControls.Widgets; - namespace Files.App.Helpers { public static class WidgetsHelpers { - public static TWidget? TryGetWidget(IGeneralSettingsService generalSettingsService, HomeViewModel widgetsViewModel, out bool shouldReload, TWidget? defaultValue = default) where TWidget : IWidgetViewModel, new() + public static bool TryGetWidget(HomeViewModel widgetsViewModel) where TWidget : IWidgetViewModel, new() { bool canAddWidget = widgetsViewModel.CanAddWidget(typeof(TWidget).Name); - bool isWidgetSettingEnabled = TryGetIsWidgetSettingEnabled(generalSettingsService); + bool isWidgetSettingEnabled = TryGetIsWidgetSettingEnabled(); if (canAddWidget && isWidgetSettingEnabled) { - shouldReload = true; - return new TWidget(); + return true; } - else if (!canAddWidget && !isWidgetSettingEnabled) // The widgets exists but the setting has been disabled for it + // The widgets exists but the setting has been disabled for it + else if (!canAddWidget && !isWidgetSettingEnabled) { // Remove the widget widgetsViewModel.RemoveWidget(); - shouldReload = false; - return default; + return false; } else if (!isWidgetSettingEnabled) { - shouldReload = false; - return default; + return false; } - shouldReload = EqualityComparer.Default.Equals(defaultValue, default); - - return (defaultValue); + return true; } - public static bool TryGetIsWidgetSettingEnabled(IGeneralSettingsService generalSettingsService) where TWidget : IWidgetViewModel + public static bool TryGetIsWidgetSettingEnabled() where TWidget : IWidgetViewModel { - if (typeof(TWidget) == typeof(QuickAccessWidget)) + IGeneralSettingsService generalSettingsService = Ioc.Default.GetRequiredService(); + + if (typeof(TWidget) == typeof(QuickAccessWidgetViewModel)) { return generalSettingsService.ShowQuickAccessWidget; } - if (typeof(TWidget) == typeof(DrivesWidget)) + if (typeof(TWidget) == typeof(DrivesWidgetViewModel)) { return generalSettingsService.ShowDrivesWidget; } - if (typeof(TWidget) == typeof(FileTagsWidget)) + if (typeof(TWidget) == typeof(FileTagsWidgetViewModel)) { return generalSettingsService.ShowFileTagsWidget; } - if (typeof(TWidget) == typeof(RecentFilesWidget)) + if (typeof(TWidget) == typeof(RecentFilesWidgetViewModel)) { return generalSettingsService.ShowRecentFilesWidget; } diff --git a/src/Files.App/ViewModels/HomeViewModel.cs b/src/Files.App/ViewModels/HomeViewModel.cs index e4c3afb05c59..50b38c59604c 100644 --- a/src/Files.App/ViewModels/HomeViewModel.cs +++ b/src/Files.App/ViewModels/HomeViewModel.cs @@ -8,21 +8,81 @@ namespace Files.App.ViewModels { public class HomeViewModel : ObservableObject, IDisposable { - public ObservableCollection WidgetItems { get; } = new(); + // Dependency injections + + private IUserSettingsService UserSettingsService { get; } = Ioc.Default.GetRequiredService(); + + // Properties + + public ObservableCollection WidgetItems { get; } = []; + + // Commands public ICommand HomePageLoadedCommand { get; } - public event EventHandler? HomePageLoadedInvoked; - public event EventHandler? WidgetListRefreshRequestedInvoked; + // Constructor public HomeViewModel() { HomePageLoadedCommand = new RelayCommand(ExecuteHomePageLoadedCommand); } - private void ExecuteHomePageLoadedCommand(RoutedEventArgs? e) + // Methods + + public void ReloadWidgets() { - HomePageLoadedInvoked?.Invoke(this, e!); + var reloadQuickAccessWidget = WidgetsHelpers.TryGetWidget(this); + var reloadDrivesWidget = WidgetsHelpers.TryGetWidget(this); + var reloadFileTagsWidget = WidgetsHelpers.TryGetWidget(this); + var reloadRecentFilesWidget = WidgetsHelpers.TryGetWidget(this); + + if (reloadQuickAccessWidget) + { + var quickAccessWidget = new QuickAccessWidget(); + + AddWidget( + new( + quickAccessWidget, + quickAccessWidget.ViewModel, + (value) => UserSettingsService.GeneralSettingsService.FoldersWidgetExpanded = value, + () => UserSettingsService.GeneralSettingsService.FoldersWidgetExpanded)); + } + + if (reloadDrivesWidget) + { + var drivesWidget = new DrivesWidget(); + + AddWidget( + new( + drivesWidget, + drivesWidget.ViewModel, + (value) => UserSettingsService.GeneralSettingsService.DrivesWidgetExpanded = value, + () => UserSettingsService.GeneralSettingsService.DrivesWidgetExpanded)); + } + + if (reloadFileTagsWidget) + { + var fileTagsWidget = new FileTagsWidget(); + + AddWidget( + new( + fileTagsWidget, + fileTagsWidget.ViewModel, + (value) => UserSettingsService.GeneralSettingsService.FileTagsWidgetExpanded = value, + () => UserSettingsService.GeneralSettingsService.FileTagsWidgetExpanded)); + } + + if (reloadRecentFilesWidget) + { + var recentFilesWidget = new RecentFilesWidget(); + + AddWidget( + new( + recentFilesWidget, + recentFilesWidget.ViewModel, + (value) => UserSettingsService.GeneralSettingsService.RecentFilesWidgetExpanded = value, + () => UserSettingsService.GeneralSettingsService.RecentFilesWidgetExpanded)); + } } public void RefreshWidgetList() @@ -30,12 +90,10 @@ public void RefreshWidgetList() for (int i = 0; i < WidgetItems.Count; i++) { if (!WidgetItems[i].WidgetItemModel.IsWidgetSettingEnabled) - { RemoveWidgetAt(i); - } } - WidgetListRefreshRequestedInvoked?.Invoke(this, EventArgs.Empty); + ReloadWidgets(); } public bool AddWidget(WidgetContainerItem widgetModel) @@ -102,12 +160,15 @@ public void RemoveWidgetAt(int index) RemoveWidgetAt(indexToRemove); } - public void ReorderWidget(WidgetContainerItem widgetModel, int place) + // Command methods + + private void ExecuteHomePageLoadedCommand(RoutedEventArgs? e) { - int widgetIndex = WidgetItems.IndexOf(widgetModel); - WidgetItems.Move(widgetIndex, place); + ReloadWidgets(); } + // Disposer + public void Dispose() { for (int i = 0; i < WidgetItems.Count; i++) diff --git a/src/Files.App/ViewModels/UserControls/Widgets/BaseWidgetViewModel.cs b/src/Files.App/ViewModels/UserControls/Widgets/BaseWidgetViewModel.cs index 1ce7cbcf4f91..ab6485370e69 100644 --- a/src/Files.App/ViewModels/UserControls/Widgets/BaseWidgetViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/Widgets/BaseWidgetViewModel.cs @@ -13,13 +13,18 @@ namespace Files.App.UserControls.Widgets /// /// Represents base ViewModel for widget ViewModels. /// - public abstract class BaseWidgetViewModel : UserControl + public abstract class BaseWidgetViewModel : ObservableObject { // Dependency injections - public IUserSettingsService UserSettingsService { get; } = Ioc.Default.GetRequiredService(); - public IQuickAccessService QuickAccessService { get; } = Ioc.Default.GetRequiredService(); - public IStorageService StorageService { get; } = Ioc.Default.GetRequiredService(); + protected IUserSettingsService UserSettingsService { get; } = Ioc.Default.GetRequiredService(); + protected IQuickAccessService QuickAccessService { get; } = Ioc.Default.GetRequiredService(); + protected IStorageService StorageService { get; } = Ioc.Default.GetRequiredService(); + protected IHomePageContext HomePageContext { get; } = Ioc.Default.GetRequiredService(); + protected IContentPageContext ContentPageContext { get; } = Ioc.Default.GetRequiredService(); + protected IFileTagsService FileTagsService { get; } = Ioc.Default.GetRequiredService(); + protected DrivesViewModel DrivesViewModel = Ioc.Default.GetRequiredService(); + protected NetworkDrivesViewModel NetworkDrivesViewModel = Ioc.Default.GetRequiredService(); // Fields @@ -27,29 +32,27 @@ public abstract class BaseWidgetViewModel : UserControl // Commands - protected ICommand? RemoveRecentItemCommand { get; set; } - protected ICommand? ClearAllItemsCommand { get; set; } - protected ICommand? OpenFileLocationCommand { get; set; } - protected ICommand? OpenInNewTabCommand { get; set; } - protected ICommand? OpenInNewWindowCommand { get; set; } - protected ICommand? OpenPropertiesCommand { get; set; } - protected ICommand? PinToSidebarCommand { get; set; } - protected ICommand? UnpinFromSidebarCommand { get; set; } + protected ICommand RemoveRecentItemCommand { get; set; } = null!; + protected ICommand ClearAllItemsCommand { get; set; } = null!; + protected ICommand OpenFileLocationCommand { get; set; } = null!; + protected ICommand OpenInNewTabCommand { get; set; } = null!; + protected ICommand OpenInNewWindowCommand { get; set; } = null!; + protected ICommand OpenPropertiesCommand { get; set; } = null!; + protected ICommand PinToSidebarCommand { get; set; } = null!; + protected ICommand UnpinFromSidebarCommand { get; set; } = null!; // Events public static event EventHandler? RightClickedItemChanged; - // Abstract methods + // Methods public abstract List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false); - // Event methods - - public void Button_RightTapped(object sender, RightTappedRoutedEventArgs e) + public void BuildItemContextMenu(object sender, RightTappedRoutedEventArgs e) { // Ensure values are not null - if (sender is not Button widgetCardItem || + if (sender is not FrameworkElement widgetCardItem || widgetCardItem.DataContext is not WidgetCardItem item) return; @@ -91,24 +94,24 @@ public void Button_RightTapped(object sender, RightTappedRoutedEventArgs e) // Command methods - public async Task OpenInNewTabAsync(WidgetCardItem item) + public async Task ExecuteOpenInNewTabCommand(WidgetCardItem? item) { - await NavigationHelpers.OpenPathInNewTab(item.Path, false); + await NavigationHelpers.OpenPathInNewTab(item?.Path ?? string.Empty, false); } - public async Task OpenInNewWindowAsync(WidgetCardItem item) + public async Task ExecuteOpenInNewWindowCommand(WidgetCardItem? item) { - await NavigationHelpers.OpenPathInNewWindowAsync(item.Path); + await NavigationHelpers.OpenPathInNewWindowAsync(item?.Path ?? string.Empty); } - public virtual async Task PinToSidebarAsync(WidgetCardItem item) + public virtual async Task ExecutePinToSidebarCommand(WidgetCardItem? item) { - await QuickAccessService.PinToSidebarAsync(item.Path); + await QuickAccessService.PinToSidebarAsync(item?.Path ?? string.Empty); } - public virtual async Task UnpinFromSidebarAsync(WidgetCardItem item) + public virtual async Task ExecuteUnpinFromSidebarCommand(WidgetCardItem? item) { - await QuickAccessService.UnpinFromSidebarAsync(item.Path); + await QuickAccessService.UnpinFromSidebarAsync(item?.Path ?? string.Empty); } protected void OnRightClickedItemChanged(WidgetCardItem? item, CommandBarFlyout? flyout) diff --git a/src/Files.App/ViewModels/UserControls/Widgets/DrivesWidgetViewModel.cs b/src/Files.App/ViewModels/UserControls/Widgets/DrivesWidgetViewModel.cs index 2947e1e74a01..df9ff9f76a51 100644 --- a/src/Files.App/ViewModels/UserControls/Widgets/DrivesWidgetViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/Widgets/DrivesWidgetViewModel.cs @@ -1,13 +1,284 @@ // Copyright (c) 2023 Files Community // Licensed under the MIT License. See the LICENSE. +<<<<<<< HEAD +======= +using Microsoft.UI.Input; +using Microsoft.UI.Xaml.Controls; +using System.Collections.Specialized; +using System.Windows.Input; +using Windows.System; +using Windows.UI.Core; + +>>>>>>> 70e2ff662 (Initial commit) namespace Files.App.ViewModels.UserControls.Widgets { /// /// Represents view model of . /// +<<<<<<< HEAD public class DrivesWidgetViewModel { public ObservableCollection Items { get; } = []; +======= + public class DrivesWidgetViewModel : BaseWidgetViewModel, IWidgetViewModel + { + // Properties + + public ObservableCollection Items { get; } = []; + + public string WidgetName => nameof(DrivesWidget); + public string AutomationProperties => "Drives".GetLocalizedResource(); + public string WidgetHeader => "Drives".GetLocalizedResource(); + public bool IsWidgetSettingEnabled => UserSettingsService.GeneralSettingsService.ShowDrivesWidget; + public bool ShowMenuFlyout => true; + public MenuFlyoutItem? MenuFlyoutItem => new() + { + Icon = new FontIcon() { Glyph = "\uE710" }, + Text = "DrivesWidgetOptionsFlyoutMapNetDriveMenuItem/Text".GetLocalizedResource(), + Command = MapNetworkDriveCommand + }; + + // Commands + + private ICommand FormatDriveCommand { get; } = null!; + private ICommand EjectDeviceCommand { get; } = null!; + private ICommand OpenInNewPaneCommand { get; } = null!; + private ICommand MapNetworkDriveCommand { get; } = null!; + private ICommand DisconnectNetworkDriveCommand { get; } = null!; + + // Constructor + + public DrivesWidgetViewModel() + { + Drives_CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + + DrivesViewModel.Drives.CollectionChanged += Drives_CollectionChanged; + + OpenInNewTabCommand = new AsyncRelayCommand(ExecuteOpenInNewTabCommand); + OpenInNewWindowCommand = new AsyncRelayCommand(ExecuteOpenInNewWindowCommand); + PinToSidebarCommand = new AsyncRelayCommand(ExecutePinToSidebarCommand); + UnpinFromSidebarCommand = new AsyncRelayCommand(ExecuteUnpinFromSidebarCommand); + FormatDriveCommand = new RelayCommand(ExecuteFormatDriveCommand); + EjectDeviceCommand = new AsyncRelayCommand(ExecuteEjectDeviceCommand); + OpenInNewPaneCommand = new AsyncRelayCommand(ExecuteOpenInNewPaneCommand); + OpenPropertiesCommand = new RelayCommand(ExecuteOpenPropertiesCommand); + DisconnectNetworkDriveCommand = new RelayCommand(ExecuteDisconnectNetworkDriveCommand); + MapNetworkDriveCommand = new AsyncRelayCommand(ExecuteMapNetworkDriveCommand); + } + + // Methods + + public async Task RefreshWidgetAsync() + { + var updateTasks = Items.Select(item => item.Item.UpdatePropertiesAsync()); + await Task.WhenAll(updateTasks); + } + + public async Task NavigateToPath(string path) + { + if (await DriveHelpers.CheckEmptyDrive(path)) + return; + + var ctrlPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down); + if (ctrlPressed) + { + await NavigationHelpers.OpenPathInNewTab(path, false); + return; + } + + ContentPageContext.ShellPage!.NavigateWithArguments( + ContentPageContext.ShellPage!.InstanceViewModel.FolderSettings.GetLayoutType(path), + new() { NavPathParam = path }); + } + + public override List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false) + { + var drive = + Items.Where(x => + string.Equals( + PathNormalization.NormalizePath(x.Path!), + PathNormalization.NormalizePath(item.Path!), + StringComparison.OrdinalIgnoreCase)) + .FirstOrDefault(); + + var options = drive?.Item.MenuOptions; + + return new List() + { + new() + { + Text = "OpenInNewTab".GetLocalizedResource(), + OpacityIcon = new OpacityIconModel() { OpacityIconStyle = "ColorIconOpenInNewTab" }, + Command = OpenInNewTabCommand, + CommandParameter = item, + ShowItem = UserSettingsService.GeneralSettingsService.ShowOpenInNewTab + }, + new() + { + Text = "OpenInNewWindow".GetLocalizedResource(), + OpacityIcon = new OpacityIconModel() { OpacityIconStyle = "ColorIconOpenInNewWindow" }, + Command = OpenInNewWindowCommand, + CommandParameter = item, + ShowItem = UserSettingsService.GeneralSettingsService.ShowOpenInNewWindow + }, + new() + { + Text = "OpenInNewPane".GetLocalizedResource(), + Command = OpenInNewPaneCommand, + CommandParameter = item, + ShowItem = UserSettingsService.GeneralSettingsService.ShowOpenInNewPane + }, + new() + { + Text = "PinFolderToSidebar".GetLocalizedResource(), + OpacityIcon = new OpacityIconModel() { OpacityIconStyle = "Icons.Pin.16x16" }, + Command = PinToSidebarCommand, + CommandParameter = item, + ShowItem = !isPinned + }, + new() + { + Text = "UnpinFolderFromSidebar".GetLocalizedResource(), + OpacityIcon = new OpacityIconModel() { OpacityIconStyle = "Icons.Unpin.16x16" }, + Command = UnpinFromSidebarCommand, + CommandParameter = item, + ShowItem = isPinned + }, + new() + { + Text = "Eject".GetLocalizedResource(), + Command = EjectDeviceCommand, + CommandParameter = item, + ShowItem = options?.ShowEjectDevice ?? false + }, + new() + { + Text = "FormatDriveText".GetLocalizedResource(), + Command = FormatDriveCommand, + CommandParameter = item, + ShowItem = options?.ShowFormatDrive ?? false + }, + new() + { + Text = "Properties".GetLocalizedResource(), + OpacityIcon = new OpacityIconModel() { OpacityIconStyle = "ColorIconProperties" }, + Command = OpenPropertiesCommand, + CommandParameter = item + }, + new() + { + Text = "TurnOnBitLocker".GetLocalizedResource(), + Tag = "TurnOnBitLockerPlaceholder", + IsEnabled = false + }, + new() + { + Text = "ManageBitLocker".GetLocalizedResource(), + Tag = "ManageBitLockerPlaceholder", + IsEnabled = false + }, + new() + { + ItemType = ContextMenuFlyoutItemType.Separator, + Tag = "OverflowSeparator", + }, + new() + { + Text = "Loading".GetLocalizedResource(), + Glyph = "\xE712", + Items = [], + ID = "ItemOverflow", + Tag = "ItemOverflow", + IsEnabled = false, + } + }.Where(x => x.ShowItem).ToList(); + } + + // Command methods + + private async Task ExecuteEjectDeviceCommand(WidgetDriveCardItem? item) + { + if (item is null) + return; + + var result = await DriveHelpers.EjectDeviceAsync(item.Item.Path); + await UIHelpers.ShowDeviceEjectResultAsync(item.Item.Type, result); + } + + private async Task ExecuteOpenInNewPaneCommand(WidgetDriveCardItem? item) + { + if (item is null || await DriveHelpers.CheckEmptyDrive(item.Item.Path)) + return; + + ContentPageContext.ShellPage!.PaneHolder?.OpenPathInNewPane(item.Item.Path); + } + + private Task ExecuteMapNetworkDriveCommand() + { + return NetworkDrivesViewModel.OpenMapNetworkDriveDialogAsync(); + } + + private void ExecuteFormatDriveCommand(WidgetDriveCardItem? item) + { + Win32API.OpenFormatDriveDialog(item?.Path ?? string.Empty); + } + + private void ExecuteOpenPropertiesCommand(WidgetDriveCardItem? item) + { + if (!HomePageContext.IsAnyItemRightClicked || item is null) + return; + + var flyout = HomePageContext.ItemContextFlyoutMenu; + + EventHandler flyoutClosed = null!; + flyoutClosed = (s, e) => + { + flyout!.Closed -= flyoutClosed; + FilePropertiesHelpers.OpenPropertiesWindow(item.Item, ContentPageContext.ShellPage!); + }; + + flyout!.Closed += flyoutClosed; + } + + private void ExecuteDisconnectNetworkDriveCommand(WidgetDriveCardItem? item) + { + if (item is null) + return; + + NetworkDrivesViewModel.DisconnectNetworkDrive(item.Item); + } + + // Event methods + + private async void Drives_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(async () => + { + foreach (DriveItem drive in DrivesViewModel.Drives.ToList().Cast()) + { + if (!Items.Any(x => x.Item == drive) && drive.Type != DriveType.VirtualDrive) + { + var cardItem = new WidgetDriveCardItem(drive); + Items.AddSorted(cardItem); + + await cardItem.LoadCardThumbnailAsync(); + } + } + + foreach (WidgetDriveCardItem driveCard in Items.ToList()) + { + if (!DrivesViewModel.Drives.Contains(driveCard.Item)) + Items.Remove(driveCard); + } + }); + } + + // Disposer + + public void Dispose() + { + } +>>>>>>> 70e2ff662 (Initial commit) } } diff --git a/src/Files.App/ViewModels/UserControls/Widgets/FileTagsWidgetViewModel.cs b/src/Files.App/ViewModels/UserControls/Widgets/FileTagsWidgetViewModel.cs index 54115d890003..7adf32490eca 100644 --- a/src/Files.App/ViewModels/UserControls/Widgets/FileTagsWidgetViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/Widgets/FileTagsWidgetViewModel.cs @@ -1,50 +1,232 @@ // Copyright (c) 2023 Files Community // Licensed under the MIT License. See the LICENSE. -using Files.Shared.Utils; +using Microsoft.UI.Xaml.Controls; +using System.IO; +using System.Windows.Input; +using Windows.Storage; namespace Files.App.ViewModels.UserControls.Widgets { /// /// Represents view model of . /// +<<<<<<< HEAD public sealed partial class FileTagsWidgetViewModel : ObservableObject, IAsyncInitialize +======= + public sealed partial class FileTagsWidgetViewModel : BaseWidgetViewModel, IWidgetViewModel +>>>>>>> 70e2ff662 (Initial commit) { - // Dependency injections + // Properties - private IFileTagsService FileTagsService { get; } = Ioc.Default.GetRequiredService(); + public ObservableCollection Containers { get; } = []; +<<<<<<< HEAD +======= - // Fields + public string WidgetName => nameof(FileTagsWidget); + public string WidgetHeader => "FileTags".GetLocalizedResource(); + public string AutomationProperties => "FileTags".GetLocalizedResource(); + public bool IsWidgetSettingEnabled => UserSettingsService.GeneralSettingsService.ShowFileTagsWidget; + public bool ShowMenuFlyout => false; + public MenuFlyoutItem? MenuFlyoutItem => null; - private readonly Func _openAction; + // Events - // Properties + public static event EventHandler>? SelectedTaggedItemsChanged; - public ObservableCollection Containers { get; } = []; + // Commands + + private ICommand OpenInNewPaneCommand { get; set; } = null!; +>>>>>>> 70e2ff662 (Initial commit) // Constructor - public FileTagsWidgetViewModel(Func openAction) + public FileTagsWidgetViewModel() { +<<<<<<< HEAD +<<<<<<< HEAD _openAction = openAction; +======= +======= +>>>>>>> 9de88d1c4 (Fix) + _ = InitializeWidget(); + + OpenInNewTabCommand = new AsyncRelayCommand(ExecuteOpenInNewTabCommand); + OpenInNewWindowCommand = new AsyncRelayCommand(ExecuteOpenInNewWindowCommand); + PinToSidebarCommand = new AsyncRelayCommand(ExecutePinToSidebarCommand); + UnpinFromSidebarCommand = new AsyncRelayCommand(ExecuteUnpinFromSidebarCommand); + OpenFileLocationCommand = new RelayCommand(ExecuteOpenFileLocationCommand); + OpenInNewPaneCommand = new RelayCommand(ExecuteOpenInNewPaneCommand); + OpenPropertiesCommand = new RelayCommand(ExecuteOpenPropertiesCommand); +<<<<<<< HEAD +>>>>>>> 70e2ff662 (Initial commit) +======= +>>>>>>> 9de88d1c4 (Fix) } // Methods - /// - public async Task InitAsync(CancellationToken cancellationToken = default) + public async Task InitializeWidget() { - await foreach (var item in FileTagsService.GetTagsAsync(cancellationToken)) + await foreach (var item in FileTagsService.GetTagsAsync()) { - var container = new WidgetFileTagsContainerItem(item.Uid, _openAction) + var container = new WidgetFileTagsContainerItem(item.Uid) { Name = item.Name, Color = item.Color }; - Containers.Add(container); - _ = container.InitAsync(cancellationToken); + Containers.Add(container); + _ = container.InitAsync(); } } + + public Task RefreshWidgetAsync() + { + return Task.CompletedTask; + } + + public override List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false) + { + return new List() + { + new() + { + Text = "OpenWith".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "ColorIconOpenWith" }, + Tag = "OpenWithPlaceholder", + ShowItem = !isFolder + }, + new() + { + Text = "SendTo".GetLocalizedResource(), + Tag = "SendToPlaceholder", + ShowItem = !isFolder && UserSettingsService.GeneralSettingsService.ShowSendToMenu + }, + new() + { + Text = "OpenInNewTab".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "ColorIconOpenInNewTab" }, + Command = OpenInNewTabCommand, + CommandParameter = item, + ShowItem = isFolder + }, + new() + { + Text = "OpenInNewWindow".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "ColorIconOpenInNewWindow" }, + Command = OpenInNewWindowCommand, + CommandParameter = item, + ShowItem = isFolder + }, + new() + { + Text = "OpenFileLocation".GetLocalizedResource(), + Glyph = "\uED25", + Command = OpenFileLocationCommand, + CommandParameter = item, + ShowItem = !isFolder + }, + new() + { + Text = "OpenInNewPane".GetLocalizedResource(), + Command = OpenInNewPaneCommand, + CommandParameter = item, + ShowItem = UserSettingsService.GeneralSettingsService.ShowOpenInNewPane && isFolder + }, + new() + { + Text = "PinFolderToSidebar".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "Icons.Pin.16x16" }, + Command = PinToSidebarCommand, + CommandParameter = item, + ShowItem = !isPinned && isFolder + }, + new() + { + Text = "UnpinFolderFromSidebar".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "Icons.Unpin.16x16" }, + Command = UnpinFromSidebarCommand, + CommandParameter = item, + ShowItem = isPinned && isFolder + }, + new() + { + Text = "Properties".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "ColorIconProperties" }, + Command = OpenPropertiesCommand, + CommandParameter = item, + ShowItem = isFolder + }, + new() + { + ItemType = ContextMenuFlyoutItemType.Separator, + Tag = "OverflowSeparator", + }, + new() + { + Text = "Loading".GetLocalizedResource(), + Glyph = "\xE712", + Items = [], + ID = "ItemOverflow", + Tag = "ItemOverflow", + IsEnabled = false, + } + }.Where(x => x.ShowItem).ToList(); + } + + // Command methods + + private void ExecuteOpenPropertiesCommand(WidgetCardItem? item) + { + if (!HomePageContext.IsAnyItemRightClicked || item is null) + return; + + var flyout = HomePageContext.ItemContextFlyoutMenu; + + EventHandler flyoutClosed = null!; + flyoutClosed = (s, e) => + { + flyout!.Closed -= flyoutClosed; + + ListedItem listedItem = new(null!) + { + ItemPath = (item.Item as WidgetFileTagCardItem)?.Path ?? string.Empty, + ItemNameRaw = (item.Item as WidgetFileTagCardItem)?.Name ?? string.Empty, + PrimaryItemAttribute = StorageItemTypes.Folder, + ItemType = "Folder".GetLocalizedResource(), + }; + + FilePropertiesHelpers.OpenPropertiesWindow(listedItem, ContentPageContext.ShellPage!); + }; + + flyout!.Closed += flyoutClosed; + } + + private void ExecuteOpenInNewPaneCommand(WidgetCardItem? item) + { + ContentPageContext.ShellPage!.PaneHolder?.OpenPathInNewPane(item?.Path ?? string.Empty); + } + + public void ExecuteOpenFileLocationCommand(WidgetCardItem? item) + { + var itemPath = Directory.GetParent(item?.Path ?? string.Empty)?.FullName ?? string.Empty; + var itemName = Path.GetFileName(item?.Path ?? string.Empty); + + ContentPageContext.ShellPage!.NavigateWithArguments( + ContentPageContext.ShellPage!.InstanceViewModel.FolderSettings.GetLayoutType(itemPath), + new NavigationArguments() + { + NavPathParam = itemPath, + SelectItems = new[] { itemName }, + AssociatedTabInstance = ContentPageContext.ShellPage! + }); + } + + // Disposer + + public void Dispose() + { + } } } diff --git a/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs b/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs index 6c173d7889bf..26ff9c21750c 100644 --- a/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/Widgets/QuickAccessWidgetViewModel.cs @@ -1,13 +1,329 @@ // Copyright (c) 2023 Files Community // Licensed under the MIT License. See the LICENSE. +<<<<<<< HEAD +======= +using Microsoft.UI.Input; +using Microsoft.UI.Xaml.Controls; +using System.Collections.Specialized; +using System.IO; +using System.Windows.Input; +using Windows.Storage; +using Windows.System; +using Windows.UI.Core; + +>>>>>>> 70e2ff662 (Initial commit) namespace Files.App.ViewModels.UserControls.Widgets { /// /// Represents view model of . /// +<<<<<<< HEAD public class QuickAccessWidgetViewModel { public ObservableCollection Items { get; } = []; +======= + public class QuickAccessWidgetViewModel : BaseWidgetViewModel, IWidgetViewModel + { + // Properties + + public ObservableCollection Items { get; } = []; + + public string WidgetName => nameof(QuickAccessWidget); + public string AutomationProperties => "QuickAccess".GetLocalizedResource(); + public string WidgetHeader => "QuickAccess".GetLocalizedResource(); + public bool IsWidgetSettingEnabled => UserSettingsService.GeneralSettingsService.ShowQuickAccessWidget; + public bool ShowMenuFlyout => false; + public MenuFlyoutItem? MenuFlyoutItem => null; + + // Commands + + public ICommand OpenInNewPaneCommand { get; set; } = null!; + + // Constructor + + public QuickAccessWidgetViewModel() + { + _ = InitializeWidget(); + + Items.CollectionChanged += Items_CollectionChanged; + + OpenInNewTabCommand = new AsyncRelayCommand(ExecuteOpenInNewTabCommand); + OpenInNewWindowCommand = new AsyncRelayCommand(ExecuteOpenInNewWindowCommand); + OpenInNewPaneCommand = new RelayCommand(ExecuteOpenInNewPaneCommand); + OpenPropertiesCommand = new RelayCommand(ExecuteOpenPropertiesCommand); + PinToSidebarCommand = new AsyncRelayCommand(ExecutePinToSidebarCommand); + UnpinFromSidebarCommand = new AsyncRelayCommand(ExecuteUnpinFromSidebarCommand); + } + + // Methods + + public override List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false) + { + return new List() + { + new() + { + Text = "OpenInNewTab".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "ColorIconOpenInNewTab" }, + Command = OpenInNewTabCommand, + CommandParameter = item, + ShowItem = UserSettingsService.GeneralSettingsService.ShowOpenInNewTab + }, + new() + { + Text = "OpenInNewWindow".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "ColorIconOpenInNewWindow" }, + Command = OpenInNewWindowCommand, + CommandParameter = item, + ShowItem = UserSettingsService.GeneralSettingsService.ShowOpenInNewWindow + }, + new() + { + Text = "OpenInNewPane".GetLocalizedResource(), + Command = OpenInNewPaneCommand, + CommandParameter = item, + ShowItem = UserSettingsService.GeneralSettingsService.ShowOpenInNewPane + }, + new() + { + Text = "PinFolderToSidebar".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "Icons.Pin.16x16" }, + Command = PinToSidebarCommand, + CommandParameter = item, + ShowItem = !isPinned + }, + new() + { + Text = "UnpinFolderFromSidebar".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "Icons.Unpin.16x16" }, + Command = UnpinFromSidebarCommand, + CommandParameter = item, + ShowItem = isPinned + }, + new() + { + Text = "Properties".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "ColorIconProperties" }, + Command = OpenPropertiesCommand, + CommandParameter = item + }, + new() + { + ItemType = ContextMenuFlyoutItemType.Separator, + Tag = "OverflowSeparator", + }, + new() + { + Text = "Loading".GetLocalizedResource(), + Glyph = "\xE712", + Items = [], + ID = "ItemOverflow", + Tag = "ItemOverflow", + IsEnabled = false, + } + }.Where(x => x.ShowItem).ToList(); + } + + private async void ModifyItemAsync(object? sender, ModifyQuickAccessEventArgs? e) + { + if (e is null) + return; + + await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(async () => + { + if (e.Reset) + { + // Find the intersection between the two lists and determine whether to remove or add + var originalItems = Items.ToList(); + var itemsToRemove = originalItems.Where(x => !e.Paths.Contains(x.Path)); + var itemsToAdd = e.Paths.Where(x => !originalItems.Any(y => y.Path == x)); + + // Remove items + foreach (var itemToRemove in itemsToRemove) + Items.Remove(itemToRemove); + + // Add items + foreach (var itemToAdd in itemsToAdd) + { + var interimItems = Items.ToList(); + var item = await App.QuickAccessManager.Model.CreateLocationItemFromPathAsync(itemToAdd); + var lastIndex = Items.IndexOf(interimItems.FirstOrDefault(x => !x.IsPinned)); + var isPinned = (bool?)e.Items.Where(x => x.FilePath == itemToAdd).FirstOrDefault()?.Properties["System.Home.IsPinned"] ?? false; + if (interimItems.Any(x => x.Path == itemToAdd)) + continue; + + Items.Insert(isPinned && lastIndex >= 0 ? Math.Min(lastIndex, Items.Count) : Items.Count, new WidgetFolderCardItem(item, Path.GetFileName(item.Text), isPinned) + { + Path = item.Path, + }); + } + + return; + } + if (e.Reorder) + { + // Remove pinned items + foreach (var itemToRemove in Items.ToList().Where(x => x.IsPinned)) + Items.Remove(itemToRemove); + + // Add pinned items in the new order + foreach (var itemToAdd in e.Paths) + { + var interimItems = Items.ToList(); + var item = await App.QuickAccessManager.Model.CreateLocationItemFromPathAsync(itemToAdd); + var lastIndex = Items.IndexOf(interimItems.FirstOrDefault(x => !x.IsPinned)); + if (interimItems.Any(x => x.Path == itemToAdd)) + continue; + + Items.Insert(lastIndex >= 0 ? Math.Min(lastIndex, Items.Count) : Items.Count, new WidgetFolderCardItem(item, Path.GetFileName(item.Text), true) + { + Path = item.Path, + }); + } + + return; + } + if (e.Add) + { + foreach (var itemToAdd in e.Paths) + { + var interimItems = Items.ToList(); + var item = await App.QuickAccessManager.Model.CreateLocationItemFromPathAsync(itemToAdd); + var lastIndex = Items.IndexOf(interimItems.FirstOrDefault(x => !x.IsPinned)); + if (interimItems.Any(x => x.Path == itemToAdd)) + continue; + Items.Insert(e.Pin && lastIndex >= 0 ? Math.Min(lastIndex, Items.Count) : Items.Count, new WidgetFolderCardItem(item, Path.GetFileName(item.Text), e.Pin) // Add just after the Recent Folders + { + Path = item.Path, + }); + } + } + else + foreach (var itemToRemove in Items.ToList().Where(x => e.Paths.Contains(x.Path))) + Items.Remove(itemToRemove); + }); + } + + public Task RefreshWidgetAsync() + { + return Task.CompletedTask; + } + + public async Task NavigateToPath(string path) + { + var ctrlPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down); + if (ctrlPressed) + { + await NavigationHelpers.OpenPathInNewTab(path, false); + return; + } + + ContentPageContext.ShellPage!.NavigateWithArguments( + ContentPageContext.ShellPage!.InstanceViewModel.FolderSettings.GetLayoutType(path), + new() { NavPathParam = path }); + } + + // Event methods + + private async Task InitializeWidget() + { + var itemsToAdd = await QuickAccessService.GetPinnedFoldersAsync(); + ModifyItemAsync(this, new(itemsToAdd.ToArray(), false) { Reset = true }); + + App.QuickAccessManager.UpdateQuickAccessWidget += ModifyItemAsync; + } + + private async void Items_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + if (e.Action is NotifyCollectionChangedAction.Add) + { + foreach (WidgetFolderCardItem cardItem in e.NewItems!) + await cardItem.LoadCardThumbnailAsync(); + } + } + + // Command methods + + public override async Task ExecutePinToSidebarCommand(WidgetCardItem? item) + { + if (item is null || item.Path is null) + return; + + await QuickAccessService.PinToSidebarAsync(item.Path); + + ModifyItemAsync(this, new(new[] { item.Path }, false)); + + var items = (await QuickAccessService.GetPinnedFoldersAsync()) + .Where(link => !((bool?)link.Properties["System.Home.IsPinned"] ?? false)); + + var recentItem = items.Where(x => !Items.ToList().Select(y => y.Path).Contains(x.FilePath)).FirstOrDefault(); + if (recentItem is not null) + { + ModifyItemAsync(this, new(new[] { recentItem.FilePath }, true) { Pin = false }); + } + } + + public override async Task ExecuteUnpinFromSidebarCommand(WidgetCardItem? item) + { + if (item is null || item.Path is null) + return; + + await QuickAccessService.UnpinFromSidebarAsync(item.Path); + + ModifyItemAsync(this, new(new[] { item.Path }, false)); + } + + private void ExecuteOpenInNewPaneCommand(WidgetFolderCardItem? item) + { + if (item is null || item.Path is null) + return; + + ContentPageContext.ShellPage!.PaneHolder?.OpenPathInNewPane(item.Path); + } + + private void ExecuteOpenPropertiesCommand(WidgetFolderCardItem? item) + { + if (!HomePageContext.IsAnyItemRightClicked || item is null || item.Item is null) + return; + + var flyout = HomePageContext.ItemContextFlyoutMenu; + EventHandler flyoutClosed = null!; + + flyoutClosed = async (s, e) => + { + flyout!.Closed -= flyoutClosed; + + ListedItem listedItem = new(null!) + { + ItemPath = item.Item.Path, + ItemNameRaw = item.Item.Text, + PrimaryItemAttribute = StorageItemTypes.Folder, + ItemType = "Folder".GetLocalizedResource(), + }; + + if (!string.Equals(item.Item.Path, Constants.UserEnvironmentPaths.RecycleBinPath, StringComparison.OrdinalIgnoreCase)) + { + BaseStorageFolder matchingStorageFolder = await ContentPageContext.ShellPage!.FilesystemViewModel.GetFolderFromPathAsync(item.Item.Path); + if (matchingStorageFolder is not null) + { + var syncStatus = await ContentPageContext.ShellPage!.FilesystemViewModel.CheckCloudDriveSyncStatusAsync(matchingStorageFolder); + listedItem.SyncStatusUI = CloudDriveSyncStatusUI.FromCloudDriveSyncStatus(syncStatus); + } + } + + FilePropertiesHelpers.OpenPropertiesWindow(listedItem, ContentPageContext.ShellPage!); + }; + + flyout!.Closed += flyoutClosed; + } + + // Disposer + + public void Dispose() + { + App.QuickAccessManager.UpdateQuickAccessWidget -= ModifyItemAsync; + } +>>>>>>> 70e2ff662 (Initial commit) } } diff --git a/src/Files.App/ViewModels/UserControls/Widgets/RecentFilesWidgetViewModel.cs b/src/Files.App/ViewModels/UserControls/Widgets/RecentFilesWidgetViewModel.cs index 11257d0cba6d..4952bd002dbd 100644 --- a/src/Files.App/ViewModels/UserControls/Widgets/RecentFilesWidgetViewModel.cs +++ b/src/Files.App/ViewModels/UserControls/Widgets/RecentFilesWidgetViewModel.cs @@ -1,13 +1,353 @@ // Copyright (c) 2023 Files Community // Licensed under the MIT License. See the LICENSE. +<<<<<<< HEAD +======= +using Microsoft.Extensions.Logging; +using Microsoft.UI.Xaml.Controls; +using System.Collections.Specialized; +using System.IO; +using Windows.Foundation.Metadata; + +>>>>>>> 70e2ff662 (Initial commit) namespace Files.App.ViewModels.UserControls.Widgets { /// /// Represents view model of . /// +<<<<<<< HEAD public class RecentFilesWidgetViewModel { public ObservableCollection Items { get; } = []; +======= + public class RecentFilesWidgetViewModel : BaseWidgetViewModel, IWidgetViewModel + { + // Fields + + private readonly SemaphoreSlim _refreshRecentFilesSemaphore; + private CancellationTokenSource _refreshRecentFilesCTS; + + // Properties + + public ObservableCollection Items { get; } = []; + + public string WidgetName => nameof(RecentFilesWidget); + public string AutomationProperties => "RecentFiles".GetLocalizedResource(); + public string WidgetHeader => "RecentFiles".GetLocalizedResource(); + public bool IsWidgetSettingEnabled => UserSettingsService.GeneralSettingsService.ShowRecentFilesWidget; + public bool ShowMenuFlyout => false; + public MenuFlyoutItem? MenuFlyoutItem => null; + + private bool _IsEmptyRecentFilesTextVisible; + public bool IsEmptyRecentFilesTextVisible + { + get => _IsEmptyRecentFilesTextVisible; + set => SetProperty(ref _IsEmptyRecentFilesTextVisible, value); + } + + private bool _IsRecentFilesDisabledInWindows; + public bool IsRecentFilesDisabledInWindows + { + get => _IsRecentFilesDisabledInWindows; + set => SetProperty(ref _IsRecentFilesDisabledInWindows, value); + } + + // Constructor + + public RecentFilesWidgetViewModel() + { + _refreshRecentFilesSemaphore = new SemaphoreSlim(1, 1); + _refreshRecentFilesCTS = new CancellationTokenSource(); + + // recent files could have changed while widget wasn't loaded + _ = RefreshWidgetAsync(); + + App.RecentItemsManager.RecentFilesChanged += Manager_RecentFilesChanged; + + RemoveRecentItemCommand = new AsyncRelayCommand(ExecuteRemoveRecentItemCommand); + ClearAllItemsCommand = new AsyncRelayCommand(ExecuteClearRecentItemsCommand); + OpenFileLocationCommand = new RelayCommand(ExecuteOpenFileLocationCommand); + OpenPropertiesCommand = new RelayCommand(ExecuteOpenPropertiesCommand); + } + + // Methods + + public async Task RefreshWidgetAsync() + { + IsRecentFilesDisabledInWindows = App.RecentItemsManager.CheckIsRecentFilesEnabled() is false; + await App.RecentItemsManager.UpdateRecentFilesAsync(); + } + + public override List GetItemMenuItems(WidgetCardItem item, bool isPinned, bool isFolder = false) + { + return new List() + { + new() + { + Text = "OpenWith".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "ColorIconOpenWith" }, + Tag = "OpenWithPlaceholder", + }, + new() + { + Text = "SendTo".GetLocalizedResource(), + Tag = "SendToPlaceholder", + ShowItem = UserSettingsService.GeneralSettingsService.ShowSendToMenu + }, + new() + { + Text = "RecentItemRemove/Text".GetLocalizedResource(), + Glyph = "\uE738", + Command = RemoveRecentItemCommand, + CommandParameter = item + }, + new() + { + Text = "RecentItemClearAll/Text".GetLocalizedResource(), + Glyph = "\uE74D", + Command = ClearAllItemsCommand + }, + new() + { + Text = "OpenFileLocation".GetLocalizedResource(), + Glyph = "\uED25", + Command = OpenFileLocationCommand, + CommandParameter = item + }, + new() + { + Text = "Properties".GetLocalizedResource(), + OpacityIcon = new() { OpacityIconStyle = "ColorIconProperties" }, + Command = OpenPropertiesCommand, + CommandParameter = item + }, + new() + { + ItemType = ContextMenuFlyoutItemType.Separator, + Tag = "OverflowSeparator", + }, + new() + { + Text = "Loading".GetLocalizedResource(), + Glyph = "\xE712", + Items = [], + ID = "ItemOverflow", + Tag = "ItemOverflow", + IsEnabled = false, + } + }.Where(x => x.ShowItem).ToList(); + } + + private async Task UpdateRecentFilesListAsync(NotifyCollectionChangedEventArgs e) + { + try + { + await _refreshRecentFilesSemaphore.WaitAsync(_refreshRecentFilesCTS.Token); + } + catch (OperationCanceledException) + { + return; + } + + try + { + // drop other waiting instances + _refreshRecentFilesCTS.Cancel(); + _refreshRecentFilesCTS = new CancellationTokenSource(); + + IsEmptyRecentFilesTextVisible = false; + + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + if (e.NewItems is not null) + { + var addedItem = e.NewItems.Cast().Single(); + AddItemToRecentList(addedItem, 0); + } + break; + + case NotifyCollectionChangedAction.Move: + if (e.OldItems is not null) + { + var movedItem = e.OldItems.Cast().Single(); + Items.RemoveAt(e.OldStartingIndex); + AddItemToRecentList(movedItem, 0); + } + break; + + case NotifyCollectionChangedAction.Remove: + if (e.OldItems is not null) + { + var removedItem = e.OldItems.Cast().Single(); + Items.RemoveAt(e.OldStartingIndex); + } + break; + + // case NotifyCollectionChangedAction.Reset: + default: + var recentFiles = App.RecentItemsManager.RecentFiles; // already sorted, add all in order + if (!recentFiles.SequenceEqual(Items)) + { + Items.Clear(); + foreach (var item in recentFiles) + { + AddItemToRecentList(item); + } + } + break; + } + + // update chevron if there aren't any items + if (Items.Count == 0 && !IsRecentFilesDisabledInWindows) + { + IsEmptyRecentFilesTextVisible = true; + } + } + catch (Exception ex) + { + App.Logger.LogInformation(ex, "Could not populate recent files"); + } + finally + { + _refreshRecentFilesSemaphore.Release(); + } + } + + private bool AddItemToRecentList(RecentItem? recentItem, int index = -1) + { + if (recentItem is null) + return false; + + if (!Items.Any(x => x.Equals(recentItem))) + { + Items.Insert(index < 0 ? Items.Count : Math.Min(index, Items.Count), recentItem); + _ = recentItem.LoadRecentItemIconAsync() + .ContinueWith(t => App.Logger.LogWarning(t.Exception, null), TaskContinuationOptions.OnlyOnFaulted); + return true; + } + return false; + } + + public void NavigateToPath(string path) + { + try + { + var directoryName = Path.GetDirectoryName(path); + + _ = Win32Helpers.InvokeWin32ComponentAsync(path, ContentPageContext.ShellPage!, workingDirectory: directoryName ?? string.Empty); + } + catch (Exception) { } + } + + // Event methods + + private async void Manager_RecentFilesChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(async () => + { + // e.Action can only be Reset right now; naively refresh everything for simplicity + await UpdateRecentFilesListAsync(e); + }); + } + + // Command methods + + private async Task ExecuteRemoveRecentItemCommand(RecentItem? item) + { + if (item is null) + return; + + await _refreshRecentFilesSemaphore.WaitAsync(); + + try + { + await App.RecentItemsManager.UnpinFromRecentFiles(item); + } + finally + { + _refreshRecentFilesSemaphore.Release(); + } + } + + private async Task ExecuteClearRecentItemsCommand() + { + await _refreshRecentFilesSemaphore.WaitAsync(); + try + { + Items.Clear(); + bool success = App.RecentItemsManager.ClearRecentItems(); + + if (success) + IsEmptyRecentFilesTextVisible = true; + } + finally + { + _refreshRecentFilesSemaphore.Release(); + } + } + + private void ExecuteOpenFileLocationCommand(RecentItem? item) + { + if (item is null) + return; + + var itemPath = Directory.GetParent(item.RecentPath)?.FullName ?? string.Empty; + var itemName = Path.GetFileName(item.RecentPath); + + ContentPageContext.ShellPage!.NavigateWithArguments( + ContentPageContext.ShellPage!.InstanceViewModel.FolderSettings.GetLayoutType(itemPath), + new NavigationArguments() + { + NavPathParam = itemPath, + SelectItems = new[] { itemName }, + AssociatedTabInstance = ContentPageContext.ShellPage! + }); + } + + private void ExecuteOpenPropertiesCommand(RecentItem? item) + { + var flyout = HomePageContext.ItemContextFlyoutMenu; + + if (item is null || flyout is null) + return; + + EventHandler flyoutClosed = null!; + flyoutClosed = async (s, e) => + { + flyout!.Closed -= flyoutClosed; + + BaseStorageFile file = await FilesystemTasks.Wrap(() => StorageFileExtensions.DangerousGetFileFromPathAsync(item.Path)); + if (file is null) + { + ContentDialog dialog = new() + { + Title = "CannotAccessPropertiesTitle".GetLocalizedResource(), + Content = "CannotAccessPropertiesContent".GetLocalizedResource(), + PrimaryButtonText = "Ok".GetLocalizedResource() + }; + + if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8)) + dialog.XamlRoot = MainWindow.Instance.Content.XamlRoot; + + await dialog.TryShowAsync(); + } + else + { + var listedItem = await UniversalStorageEnumerator.AddFileAsync(file, null!, default); + FilePropertiesHelpers.OpenPropertiesWindow(listedItem, ContentPageContext.ShellPage!); + } + }; + + flyout!.Closed += flyoutClosed; + } + + // Disposer + + public void Dispose() + { + App.RecentItemsManager.RecentFilesChanged -= Manager_RecentFilesChanged; + } +>>>>>>> 70e2ff662 (Initial commit) } } diff --git a/src/Files.App/Views/HomePage.xaml.cs b/src/Files.App/Views/HomePage.xaml.cs index a6f3c1e90155..f293fc6ad918 100644 --- a/src/Files.App/Views/HomePage.xaml.cs +++ b/src/Files.App/Views/HomePage.xaml.cs @@ -1,13 +1,8 @@ // Copyright (c) 2023 Files Community // Licensed under the MIT License. See the LICENSE. -using Files.App.UserControls.Widgets; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Navigation; -using System.IO; -using System.Runtime.InteropServices; -using Windows.Foundation.Metadata; -using Windows.Storage; namespace Files.App.Views { @@ -15,32 +10,20 @@ public sealed partial class HomePage : Page, IDisposable { // Dependency injections - private IUserSettingsService UserSettingsService { get; } = Ioc.Default.GetRequiredService(); - private HomeViewModel ViewModel { get; } = Ioc.Default.GetRequiredService(); + public HomeViewModel ViewModel { get; } = Ioc.Default.GetRequiredService(); // Properties private IShellPage AppInstance { get; set; } = null!; - public LayoutPreferencesManager FolderSettings - => AppInstance?.InstanceViewModel.FolderSettings!; - - private QuickAccessWidget? quickAccessWidget; - private DrivesWidget? drivesWidget; - private FileTagsWidget? fileTagsWidget; - private RecentFilesWidget? recentFilesWidget; - // Constructor public HomePage() { InitializeComponent(); - - ViewModel.HomePageLoadedInvoked += ViewModel_HomePageLoadedInvoked; - ViewModel.WidgetListRefreshRequestedInvoked += ViewModel_WidgetListRefreshRequestedInvoked; } - // Overridden methods + // Methods protected override async void OnNavigatedTo(NavigationEventArgs e) { @@ -92,198 +75,17 @@ protected override async void OnNavigatedTo(NavigationEventArgs e) base.OnNavigatedTo(e); } - protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) - { - base.OnNavigatingFrom(e); - - AppInstance.ToolbarViewModel.RefreshRequested -= ToolbarViewModel_RefreshRequested; - } - protected override void OnNavigatedFrom(NavigationEventArgs e) { Dispose(); - - base.OnNavigatedFrom(e); - } - - // Methods - - public void RefreshWidgetList() - { - ViewModel.RefreshWidgetList(); - } - - public void ReloadWidgets() - { - quickAccessWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.GeneralSettingsService, ViewModel, out bool shouldReloadQuickAccessWidget, quickAccessWidget); - drivesWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.GeneralSettingsService, ViewModel, out bool shouldReloadDrivesWidget, drivesWidget); - fileTagsWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.GeneralSettingsService, ViewModel, out bool shouldReloadFileTags, fileTagsWidget); - recentFilesWidget = WidgetsHelpers.TryGetWidget(UserSettingsService.GeneralSettingsService, ViewModel, out bool shouldReloadRecentFiles, recentFilesWidget); - - // Reload QuickAccessWidget - if (shouldReloadQuickAccessWidget && quickAccessWidget is not null) - { - ViewModel.InsertWidget( - new( - quickAccessWidget, - (value) => UserSettingsService.GeneralSettingsService.FoldersWidgetExpanded = value, - () => UserSettingsService.GeneralSettingsService.FoldersWidgetExpanded), - 0); - - quickAccessWidget.CardInvoked -= QuickAccessWidget_CardInvoked; - quickAccessWidget.CardNewPaneInvoked -= WidgetCardNewPaneInvoked; - quickAccessWidget.CardPropertiesInvoked -= QuickAccessWidget_CardPropertiesInvoked; - quickAccessWidget.CardInvoked += QuickAccessWidget_CardInvoked; - quickAccessWidget.CardNewPaneInvoked += WidgetCardNewPaneInvoked; - quickAccessWidget.CardPropertiesInvoked += QuickAccessWidget_CardPropertiesInvoked; - } - - // Reload DrivesWidget - if (shouldReloadDrivesWidget && drivesWidget is not null) - { - ViewModel.InsertWidget(new(drivesWidget, (value) => UserSettingsService.GeneralSettingsService.DrivesWidgetExpanded = value, () => UserSettingsService.GeneralSettingsService.DrivesWidgetExpanded), 1); - - drivesWidget.AppInstance = AppInstance; - drivesWidget.DrivesWidgetInvoked -= DrivesWidget_DrivesWidgetInvoked; - drivesWidget.DrivesWidgetNewPaneInvoked -= DrivesWidget_DrivesWidgetNewPaneInvoked; - drivesWidget.DrivesWidgetInvoked += DrivesWidget_DrivesWidgetInvoked; - drivesWidget.DrivesWidgetNewPaneInvoked += DrivesWidget_DrivesWidgetNewPaneInvoked; - } - - // Reload FileTags - if (shouldReloadFileTags && fileTagsWidget is not null) - { - ViewModel.InsertWidget(new(fileTagsWidget, (value) => UserSettingsService.GeneralSettingsService.FileTagsWidgetExpanded = value, () => UserSettingsService.GeneralSettingsService.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(); - } - - // Reload RecentFilesWidget - if (shouldReloadRecentFiles && recentFilesWidget is not null) - { - ViewModel.InsertWidget(new(recentFilesWidget, (value) => UserSettingsService.GeneralSettingsService.RecentFilesWidgetExpanded = value, () => UserSettingsService.GeneralSettingsService.RecentFilesWidgetExpanded), 4); - - recentFilesWidget.AppInstance = AppInstance; - recentFilesWidget.RecentFilesOpenLocationInvoked -= WidgetOpenLocationInvoked; - recentFilesWidget.RecentFileInvoked -= RecentFilesWidget_RecentFileInvoked; - recentFilesWidget.RecentFilesOpenLocationInvoked += WidgetOpenLocationInvoked; - recentFilesWidget.RecentFileInvoked += RecentFilesWidget_RecentFileInvoked; - } - } - - // Event methods - - private void ViewModel_WidgetListRefreshRequestedInvoked(object? sender, EventArgs e) - { - ReloadWidgets(); - } - - private void ViewModel_HomePageLoadedInvoked(object? sender, Microsoft.UI.Xaml.RoutedEventArgs e) - { - ReloadWidgets(); - } - - private async void RecentFilesWidget_RecentFileInvoked(object sender, PathNavigationEventArgs e) - { - try - { - if (e.IsFile) - { - var directoryName = Path.GetDirectoryName(e.ItemPath); - await Win32Helpers.InvokeWin32ComponentAsync(e.ItemPath, AppInstance, workingDirectory: directoryName ?? string.Empty); - } - else - { - AppInstance.NavigateWithArguments( - FolderSettings.GetLayoutType(e.ItemPath), - new() - { - NavPathParam = e.ItemPath - }); - } - } - catch (UnauthorizedAccessException) - { - var dialog = DynamicDialogFactory.GetFor_ConsentDialog(); - - if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8)) - dialog.XamlRoot = MainWindow.Instance.Content.XamlRoot; - - await dialog.TryShowAsync(); - } - catch (COMException) { } - catch (ArgumentException) { } - } - - private void WidgetOpenLocationInvoked(object sender, PathNavigationEventArgs e) - { - AppInstance.NavigateWithArguments(FolderSettings.GetLayoutType(e.ItemPath), new NavigationArguments() - { - NavPathParam = e.ItemPath, - SelectItems = new[] { e.ItemName }, - AssociatedTabInstance = AppInstance - }); - } - - private void QuickAccessWidget_CardInvoked(object sender, QuickAccessCardInvokedEventArgs e) - { - AppInstance.NavigateWithArguments(FolderSettings.GetLayoutType(e.Path), new NavigationArguments() - { - NavPathParam = e.Path - }); - } - - private void WidgetCardNewPaneInvoked(object sender, QuickAccessCardInvokedEventArgs e) - { - AppInstance.PaneHolder?.OpenPathInNewPane(e.Path); - } - - private async void QuickAccessWidget_CardPropertiesInvoked(object sender, QuickAccessCardEventArgs e) - { - ListedItem listedItem = new(null!) - { - ItemPath = e.Item.Path, - ItemNameRaw = e.Item.Text, - PrimaryItemAttribute = StorageItemTypes.Folder, - ItemType = "Folder".GetLocalizedResource(), - }; - - if (!string.Equals(e.Item.Path, Constants.UserEnvironmentPaths.RecycleBinPath, StringComparison.OrdinalIgnoreCase)) - { - BaseStorageFolder matchingStorageFolder = await AppInstance.FilesystemViewModel.GetFolderFromPathAsync(e.Item.Path); - if (matchingStorageFolder is not null) - { - var syncStatus = await AppInstance.FilesystemViewModel.CheckCloudDriveSyncStatusAsync(matchingStorageFolder); - listedItem.SyncStatusUI = CloudDriveSyncStatusUI.FromCloudDriveSyncStatus(syncStatus); - } - } - - FilePropertiesHelpers.OpenPropertiesWindow(listedItem, AppInstance); - } - - private void DrivesWidget_DrivesWidgetNewPaneInvoked(object sender, DrivesWidget.DrivesWidgetInvokedEventArgs e) - { - AppInstance.PaneHolder?.OpenPathInNewPane(e.Path); - } - - private void DrivesWidget_DrivesWidgetInvoked(object sender, DrivesWidget.DrivesWidgetInvokedEventArgs e) - { - AppInstance.NavigateWithArguments(FolderSettings.GetLayoutType(e.Path), new NavigationArguments() - { - NavPathParam = e.Path - }); } private async void ToolbarViewModel_RefreshRequested(object? sender, EventArgs e) { AppInstance.ToolbarViewModel.CanRefresh = false; + await Task.WhenAll(ViewModel.WidgetItems.Select(w => w.WidgetItemModel.RefreshWidgetAsync())); + AppInstance.ToolbarViewModel.CanRefresh = true; } @@ -291,8 +93,6 @@ private async void ToolbarViewModel_RefreshRequested(object? sender, EventArgs e public void Dispose() { - ViewModel.HomePageLoadedInvoked -= ViewModel_HomePageLoadedInvoked; - ViewModel.WidgetListRefreshRequestedInvoked -= ViewModel_WidgetListRefreshRequestedInvoked; AppInstance.ToolbarViewModel.RefreshRequested -= ToolbarViewModel_RefreshRequested; ViewModel?.Dispose(); } diff --git a/src/Files.App/Views/Shells/ModernShellPage.xaml.cs b/src/Files.App/Views/Shells/ModernShellPage.xaml.cs index 68f13b136f29..5a165a2a3f7a 100644 --- a/src/Files.App/Views/Shells/ModernShellPage.xaml.cs +++ b/src/Files.App/Views/Shells/ModernShellPage.xaml.cs @@ -75,7 +75,7 @@ public ModernShellPage() : base(new CurrentInstanceViewModel()) private void ModernShellPage_RefreshWidgetsRequested(object sender, EventArgs e) { if (ItemDisplayFrame?.Content is HomePage currentPage) - currentPage.RefreshWidgetList(); + currentPage.ViewModel.RefreshWidgetList(); } protected override void FolderSettings_LayoutPreferencesUpdateRequired(object sender, LayoutPreferenceEventArgs e)