From 9051817f2a7c36355c77749c03af961d95ec1e84 Mon Sep 17 00:00:00 2001 From: Marco Gavelli Date: Sat, 11 Sep 2021 11:31:05 +0200 Subject: [PATCH 1/3] Fix 2762828271u --- .../UserControls/Widgets/FolderWidget.xaml.cs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/Files/UserControls/Widgets/FolderWidget.xaml.cs b/Files/UserControls/Widgets/FolderWidget.xaml.cs index 9391d1f8d66a..63ff6bd45414 100644 --- a/Files/UserControls/Widgets/FolderWidget.xaml.cs +++ b/Files/UserControls/Widgets/FolderWidget.xaml.cs @@ -140,23 +140,18 @@ public void Dispose() private async Task GetItemsAddedIcon() { - try + foreach (var item in ItemsAdded.ToList()) // ToList() is necessary { - foreach (var item in ItemsAdded.ToList()) // ToList() is necessary - { - item.SelectCommand = LibraryCardClicked; - item.AutomationProperties = item.Text; - await this.LoadLibraryIcon(item); - } - } - catch - { - // Collection modified + item.SelectCommand = LibraryCardClicked; + item.AutomationProperties = item.Text; + await this.LoadLibraryIcon(item); } } private async void FolderWidget_Loaded(object sender, RoutedEventArgs e) { + Loaded -= FolderWidget_Loaded; + ItemsAdded.BeginBulkOperation(); ItemsAdded.Add(new LibraryCardItem { @@ -192,7 +187,6 @@ private async void FolderWidget_Loaded(object sender, RoutedEventArgs e) await GetItemsAddedIcon(); ItemsAdded.EndBulkOperation(); - Loaded -= FolderWidget_Loaded; } private void FolderWidget_Unloaded(object sender, RoutedEventArgs e) From d1157d1967be505292b9e37d04d580b068eebba7 Mon Sep 17 00:00:00 2001 From: Marco Gavelli Date: Sun, 12 Sep 2021 15:52:04 +0200 Subject: [PATCH 2/3] Fix copy/paste shortcuts (#6108) --- Files/Helpers/UIFilesystemHelpers.cs | 75 ++++++++----------- .../BaseLayoutCommandImplementationModel.cs | 6 +- Files/Views/ColumnShellPage.xaml.cs | 12 +-- Files/Views/ModernShellPage.xaml.cs | 12 +-- 4 files changed, 48 insertions(+), 57 deletions(-) diff --git a/Files/Helpers/UIFilesystemHelpers.cs b/Files/Helpers/UIFilesystemHelpers.cs index 480d9187e231..0cf1b772d2f1 100644 --- a/Files/Helpers/UIFilesystemHelpers.cs +++ b/Files/Helpers/UIFilesystemHelpers.cs @@ -39,11 +39,11 @@ public static async void CutItem(IShellPage associatedInstance) { await Task.WhenAll(associatedInstance.SlimContentPage.SelectedItems.ToList().Select(async listedItem => { - // FTP don't support cut, fallback to copy - if (listedItem is not FtpItem) + // FTP don't support cut, fallback to copy + if (listedItem is not FtpItem) { - // Dim opacities accordingly - listedItem.Opacity = Constants.UI.DimItemOpacity; + // Dim opacities accordingly + listedItem.Opacity = Constants.UI.DimItemOpacity; } if (listedItem is FtpItem ftpItem) @@ -80,31 +80,24 @@ await Task.WhenAll(associatedInstance.SlimContentPage.SelectedItems.ToList().Sel } catch { - return; - } - - if (result.ErrorCode == FileSystemStatusCode.NotFound) - { - associatedInstance.SlimContentPage.ItemManipulationModel.RefreshItemsOpacity(); - return; - } - else if (result.ErrorCode == FileSystemStatusCode.Unauthorized) - { - // Try again with fulltrust process - var connection = await AppServiceConnectionHelper.Instance; - if (connection != null) + if (result.ErrorCode == FileSystemStatusCode.Unauthorized) { - string filePaths = string.Join('|', associatedInstance.SlimContentPage.SelectedItems.Select(x => x.ItemPath)); - AppServiceResponseStatus status = await connection.SendMessageAsync(new ValueSet() - { - { "Arguments", "FileOperation" }, - { "fileop", "Clipboard" }, - { "filepath", filePaths }, - { "operation", (int)DataPackageOperation.Move } - }); - if (status == AppServiceResponseStatus.Success) + // Try again with fulltrust process + var connection = await AppServiceConnectionHelper.Instance; + if (connection != null) { - return; + string filePaths = string.Join('|', associatedInstance.SlimContentPage.SelectedItems.Select(x => x.ItemPath)); + AppServiceResponseStatus status = await connection.SendMessageAsync(new ValueSet() + { + { "Arguments", "FileOperation" }, + { "fileop", "Clipboard" }, + { "filepath", filePaths }, + { "operation", (int)DataPackageOperation.Move } + }); + if (status == AppServiceResponseStatus.Success) + { + return; + } } } associatedInstance.SlimContentPage.ItemManipulationModel.RefreshItemsOpacity(); @@ -188,23 +181,21 @@ await Task.WhenAll(associatedInstance.SlimContentPage.SelectedItems.ToList().Sel } catch { - return; - } - - if (result.ErrorCode == FileSystemStatusCode.Unauthorized) - { - // Try again with fulltrust process - var connection = await AppServiceConnectionHelper.Instance; - if (connection != null) + if (result.ErrorCode == FileSystemStatusCode.Unauthorized) { - string filePaths = string.Join('|', associatedInstance.SlimContentPage.SelectedItems.Select(x => x.ItemPath)); - await connection.SendMessageAsync(new ValueSet() + // Try again with fulltrust process + var connection = await AppServiceConnectionHelper.Instance; + if (connection != null) { - { "Arguments", "FileOperation" }, - { "fileop", "Clipboard" }, - { "filepath", filePaths }, - { "operation", (int)DataPackageOperation.Copy } - }); + string filePaths = string.Join('|', associatedInstance.SlimContentPage.SelectedItems.Select(x => x.ItemPath)); + await connection.SendMessageAsync(new ValueSet() + { + { "Arguments", "FileOperation" }, + { "fileop", "Clipboard" }, + { "filepath", filePaths }, + { "operation", (int)DataPackageOperation.Copy } + }); + } } return; } diff --git a/Files/Interacts/BaseLayoutCommandImplementationModel.cs b/Files/Interacts/BaseLayoutCommandImplementationModel.cs index 2b1699bd1a3d..537350eee646 100644 --- a/Files/Interacts/BaseLayoutCommandImplementationModel.cs +++ b/Files/Interacts/BaseLayoutCommandImplementationModel.cs @@ -199,9 +199,9 @@ await FilesystemHelpers.RestoreFromTrashAsync(StorageItemHelpers.FromPathAndType public virtual async void DeleteItem(RoutedEventArgs e) { - var items = await Task.WhenAll(SlimContentPage.SelectedItems.Select((item) => Task.Run(() => StorageItemHelpers.FromPathAndType( - item.ItemPath, - item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory)))); + var items = await Task.Run(() => SlimContentPage.SelectedItems.ToList().Select((item) => StorageItemHelpers.FromPathAndType( + item.ItemPath, + item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory))); await FilesystemHelpers.DeleteItemsAsync(items, true, false, true); } diff --git a/Files/Views/ColumnShellPage.xaml.cs b/Files/Views/ColumnShellPage.xaml.cs index ebf9ee14431e..6e67d62403c6 100644 --- a/Files/Views/ColumnShellPage.xaml.cs +++ b/Files/Views/ColumnShellPage.xaml.cs @@ -616,9 +616,9 @@ private async void KeyboardAccelerator_Invoked(KeyboardAccelerator sender, Keybo case (false, true, false, true, VirtualKey.Delete): // shift + delete, PermanentDelete if (ContentPage.IsItemSelected && !NavToolbarViewModel.IsEditModeEnabled && !InstanceViewModel.IsPageTypeSearchResults) { - var items = await Task.WhenAll(ContentPage.SelectedItems.Select((item) => Task.Run(() => StorageItemHelpers.FromPathAndType( - item.ItemPath, - item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory)))); + var items = await Task.Run(() => SlimContentPage.SelectedItems.ToList().Select((item) => StorageItemHelpers.FromPathAndType( + item.ItemPath, + item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory))); await FilesystemHelpers.DeleteItemsAsync(items, true, true, true); } @@ -660,9 +660,9 @@ private async void KeyboardAccelerator_Invoked(KeyboardAccelerator sender, Keybo case (false, false, false, true, VirtualKey.Delete): // delete, delete item if (ContentPage.IsItemSelected && !ContentPage.IsRenamingItem && !InstanceViewModel.IsPageTypeSearchResults) { - var items = await Task.WhenAll(ContentPage.SelectedItems.Select((item) => Task.Run(() => StorageItemHelpers.FromPathAndType( - item.ItemPath, - item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory)))); + var items = await Task.Run(() => SlimContentPage.SelectedItems.ToList().Select((item) => StorageItemHelpers.FromPathAndType( + item.ItemPath, + item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory))); await FilesystemHelpers.DeleteItemsAsync(items, true, false, true); } diff --git a/Files/Views/ModernShellPage.xaml.cs b/Files/Views/ModernShellPage.xaml.cs index 8e72123eefd3..f902c836cff6 100644 --- a/Files/Views/ModernShellPage.xaml.cs +++ b/Files/Views/ModernShellPage.xaml.cs @@ -661,9 +661,9 @@ private async void KeyboardAccelerator_Invoked(KeyboardAccelerator sender, Keybo case (false, true, false, true, VirtualKey.Delete): // shift + delete, PermanentDelete if (ContentPage.IsItemSelected && !NavToolbarViewModel.IsEditModeEnabled && !InstanceViewModel.IsPageTypeSearchResults) { - var items = await Task.WhenAll(ContentPage.SelectedItems.Select((item) => Task.Run(() => StorageItemHelpers.FromPathAndType( - item.ItemPath, - item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory)))); + var items = await Task.Run(() => SlimContentPage.SelectedItems.ToList().Select((item) => StorageItemHelpers.FromPathAndType( + item.ItemPath, + item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory))); await FilesystemHelpers.DeleteItemsAsync(items, true, true, true); } @@ -705,9 +705,9 @@ private async void KeyboardAccelerator_Invoked(KeyboardAccelerator sender, Keybo case (false, false, false, true, VirtualKey.Delete): // delete, delete item if (ContentPage.IsItemSelected && !ContentPage.IsRenamingItem && !InstanceViewModel.IsPageTypeSearchResults) { - var items = await Task.WhenAll(ContentPage.SelectedItems.Select((item) => Task.Run(() => StorageItemHelpers.FromPathAndType( - item.ItemPath, - item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory)))); + var items = await Task.Run(() => SlimContentPage.SelectedItems.ToList().Select((item) => StorageItemHelpers.FromPathAndType( + item.ItemPath, + item.PrimaryItemAttribute == StorageItemTypes.File ? FilesystemItemType.File : FilesystemItemType.Directory))); await FilesystemHelpers.DeleteItemsAsync(items, true, false, true); } From 96fbe2c5b2792725184f9feccc3c8f5468f15381 Mon Sep 17 00:00:00 2001 From: Marco Gavelli Date: Sun, 12 Sep 2021 16:47:42 +0200 Subject: [PATCH 3/3] Avoid freezing when opening conflicts dialog --- .../FilesystemItemsOperationDataModel.cs | 28 ++++++------------- .../Helpers/FilesystemHelpers.cs | 6 ++-- .../FilesystemOperationDialogViewModel.cs | 27 ++++++++++++++++-- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/Files/DataModels/FilesystemItemsOperationDataModel.cs b/Files/DataModels/FilesystemItemsOperationDataModel.cs index 58be5f0e7b7e..cc6c761b1c7d 100644 --- a/Files/DataModels/FilesystemItemsOperationDataModel.cs +++ b/Files/DataModels/FilesystemItemsOperationDataModel.cs @@ -1,6 +1,7 @@ using Files.Enums; using Files.Helpers; using Files.ViewModels.Dialogs; +using Microsoft.Toolkit.Uwp; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -58,21 +59,16 @@ public FilesystemItemsOperationDataModel(FilesystemOperationType operationType, this.ConflictingItems = conflictingItems; } - public async Task> ToItems(Action updatePrimaryButtonEnabled, Action optionGenerateNewName, Action optionReplaceExisting, Action optionSkip) + public List ToItems(Action updatePrimaryButtonEnabled, Action optionGenerateNewName, Action optionReplaceExisting, Action optionSkip) { - ConcurrentBag<(int Index, FilesystemOperationItemViewModel Model)> items = new ConcurrentBag<(int Index, FilesystemOperationItemViewModel Model)>(); - + List items = new List(); List nonConflictingItems = IncomingItems.Except(ConflictingItems).ToList(); // Add conflicting items first - await Task.WhenAll(ConflictingItems.Select(async (item, index) => - { - var iconData = await FileThumbnailHelper.LoadIconFromPathAsync(item.SourcePath, 64u, Windows.Storage.FileProperties.ThumbnailMode.ListView); - - items.Add((index, new FilesystemOperationItemViewModel(updatePrimaryButtonEnabled, optionGenerateNewName, optionReplaceExisting, optionSkip) + items.AddRange(ConflictingItems.Select((item, index) => + new FilesystemOperationItemViewModel(updatePrimaryButtonEnabled, optionGenerateNewName, optionReplaceExisting, optionSkip) { IsConflict = true, - ItemIcon = iconData != null ? await iconData.ToBitmapAsync() : null, SourcePath = item.SourcePath, DestinationPath = item.DestinationPath, DisplayFileName = item.DisplayFileName, @@ -80,19 +76,12 @@ await Task.WhenAll(ConflictingItems.Select(async (item, index) => ItemOperation = item.OperationType, ActionTaken = false })); - })); - - var baseIndex = ConflictingItems.Count; // Then add non-conflicting items - await Task.WhenAll(nonConflictingItems.Select(async (item, index) => - { - var iconData = await FileThumbnailHelper.LoadIconFromPathAsync(item.SourcePath, 64u, Windows.Storage.FileProperties.ThumbnailMode.ListView); - - items.Add((baseIndex + index, new FilesystemOperationItemViewModel(updatePrimaryButtonEnabled, optionGenerateNewName, optionReplaceExisting, optionSkip) + items.AddRange(nonConflictingItems.Select((item, index) => + new FilesystemOperationItemViewModel(updatePrimaryButtonEnabled, optionGenerateNewName, optionReplaceExisting, optionSkip) { IsConflict = false, - ItemIcon = iconData != null ? await iconData.ToBitmapAsync() : null, SourcePath = item.SourcePath, DestinationPath = item.DestinationPath, DisplayFileName = item.DisplayFileName, @@ -100,9 +89,8 @@ await Task.WhenAll(nonConflictingItems.Select(async (item, index) => ItemOperation = item.OperationType, ActionTaken = true })); - })); - return items.OrderBy(i => i.Index).Select(i => i.Model).ToList(); + return items; } private string GetOperationIconGlyph(FilesystemOperationType operationType) diff --git a/Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs b/Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs index 1613d876d146..55b8dcbb5c62 100644 --- a/Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs +++ b/Files/Filesystem/FilesystemOperations/Helpers/FilesystemHelpers.cs @@ -126,7 +126,7 @@ public async Task DeleteItemsAsync(IEnumerable DeleteItemAsync(IStorageItemWithPath source, boo incomingItems.Add(new FilesystemItemsOperationItemModel(FilesystemOperationType.Delete, srcPath, null)); } - FilesystemOperationDialog dialog = await FilesystemOperationDialogViewModel.GetDialog(new FilesystemItemsOperationDataModel( + FilesystemOperationDialog dialog = FilesystemOperationDialogViewModel.GetDialog(new FilesystemItemsOperationDataModel( FilesystemOperationType.Delete, false, canBeSentToBin ? permanently : true, @@ -1005,7 +1005,7 @@ public async Task RecycleItemsFromClipboard(DataPackageView packag if (mustResolveConflicts || forceDialog) { - FilesystemOperationDialog dialog = await FilesystemOperationDialogViewModel.GetDialog(new FilesystemItemsOperationDataModel( + FilesystemOperationDialog dialog = FilesystemOperationDialogViewModel.GetDialog(new FilesystemItemsOperationDataModel( operationType, mustResolveConflicts, false, diff --git a/Files/ViewModels/Dialogs/FilesystemOperationDialogViewModel.cs b/Files/ViewModels/Dialogs/FilesystemOperationDialogViewModel.cs index 725ab0f4595e..c6e927148ad1 100644 --- a/Files/ViewModels/Dialogs/FilesystemOperationDialogViewModel.cs +++ b/Files/ViewModels/Dialogs/FilesystemOperationDialogViewModel.cs @@ -1,9 +1,11 @@ using Files.DataModels; using Files.Dialogs; using Files.Enums; +using Files.Helpers; using Microsoft.Toolkit.Mvvm.ComponentModel; using Microsoft.Toolkit.Mvvm.Input; using Microsoft.Toolkit.Uwp; +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -191,7 +193,7 @@ public List GetResult() return Items.Cast().ToList(); } - public static async Task GetDialog(FilesystemItemsOperationDataModel itemsData) + public static FilesystemOperationDialog GetDialog(FilesystemItemsOperationDataModel itemsData) { string titleText = null; string subtitleText = null; @@ -280,12 +282,31 @@ public static async Task GetDialog(FilesystemItemsOpe PermanentlyDeleteEnabled = itemsData.PermanentlyDeleteEnabled, MustResolveConflicts = itemsData.MustResolveConflicts }; - viewModel.Items = new ObservableCollection(await itemsData.ToItems( + viewModel.Items = new ObservableCollection(itemsData.ToItems( viewModel.UpdatePrimaryButtonEnabled, viewModel.OptionGenerateNewName, viewModel.OptionReplaceExisting, viewModel.OptionSkip)); - + _ = LoadItemsIcon(viewModel.Items); FilesystemOperationDialog dialog = new FilesystemOperationDialog(viewModel); return dialog; } + + private static async Task LoadItemsIcon(IEnumerable items) + { + await Task.Run(() => Task.WhenAll(items.ToList().Select(async (item) => + { + try + { + var iconData = await FileThumbnailHelper.LoadIconFromPathAsync(item.SourcePath, 64u, Windows.Storage.FileProperties.ThumbnailMode.ListView); + if (iconData != null) + { + await Windows.ApplicationModel.Core.CoreApplication.MainView.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, async () => + { + item.ItemIcon = await iconData.ToBitmapAsync(); + }); + } + } + catch { } + }))); + } } } \ No newline at end of file