Skip to content

Commit aa05b1a

Browse files
authored
Code Quality: Simplify UI operation layer for Copy and Cut (#15724)
1 parent e0f5c48 commit aa05b1a

File tree

6 files changed

+196
-301
lines changed

6 files changed

+196
-301
lines changed

src/Files.App/Actions/FileSystem/CopyItemAction.cs

-46
This file was deleted.

src/Files.App/Actions/FileSystem/CutItemAction.cs

-45
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Copyright (c) 2024 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
4+
using Microsoft.Extensions.Logging;
5+
using System.Collections.Concurrent;
6+
using System.IO;
7+
using Windows.ApplicationModel.DataTransfer;
8+
using Windows.Storage;
9+
using Windows.System;
10+
11+
namespace Files.App.Actions
12+
{
13+
internal abstract class BaseTransferItemAction : ObservableObject
14+
{
15+
protected readonly IContentPageContext ContentPageContext = Ioc.Default.GetRequiredService<IContentPageContext>();
16+
protected readonly StatusCenterViewModel StatusCenterViewModel = Ioc.Default.GetRequiredService<StatusCenterViewModel>();
17+
18+
public bool IsExecutable
19+
=> ContentPageContext.HasSelection;
20+
21+
public BaseTransferItemAction()
22+
{
23+
ContentPageContext.PropertyChanged += ContentPageContext_PropertyChanged;
24+
}
25+
26+
public async Task ExecuteTransferAsync(DataPackageOperation type = DataPackageOperation.Copy)
27+
{
28+
if (ContentPageContext.ShellPage is null ||
29+
ContentPageContext.ShellPage.SlimContentPage.IsItemSelected is false)
30+
return;
31+
32+
// Reset cut mode
33+
ContentPageContext.ShellPage.SlimContentPage.ItemManipulationModel.RefreshItemsOpacity();
34+
35+
ConcurrentBag<IStorageItem> items = [];
36+
var itemsCount = ContentPageContext.SelectedItems.Count;
37+
var statusCenterItem = itemsCount > 50 ? StatusCenterHelper.AddCard_Prepare() : null;
38+
var dataPackage = new DataPackage() { RequestedOperation = type };
39+
40+
try
41+
{
42+
// Update the status to in-progress
43+
if (statusCenterItem is not null)
44+
{
45+
statusCenterItem.Progress.EnumerationCompleted = true;
46+
statusCenterItem.Progress.ItemsCount = items.Count;
47+
statusCenterItem.Progress.ReportStatus(FileSystemStatusCode.InProgress);
48+
}
49+
50+
await ContentPageContext.SelectedItems.ToList().ParallelForEachAsync(async listedItem =>
51+
{
52+
// Update the status to increase processed count by one
53+
if (statusCenterItem is not null)
54+
{
55+
statusCenterItem.Progress.AddProcessedItemsCount(1);
56+
statusCenterItem.Progress.Report();
57+
}
58+
59+
if (listedItem is FtpItem ftpItem)
60+
{
61+
// Don't dim selected items here since FTP doesn't support cut
62+
if (ftpItem.PrimaryItemAttribute is StorageItemTypes.File or StorageItemTypes.Folder)
63+
items.Add(await ftpItem.ToStorageItem());
64+
}
65+
else
66+
{
67+
if (type is DataPackageOperation.Move)
68+
{
69+
// Dim opacities accordingly
70+
await MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() =>
71+
{
72+
listedItem.Opacity = Constants.UI.DimItemOpacity;
73+
});
74+
}
75+
76+
FilesystemResult? result =
77+
listedItem.PrimaryItemAttribute == StorageItemTypes.File || listedItem is ZipItem
78+
? await ContentPageContext.ShellPage.ShellViewModel.GetFileFromPathAsync(listedItem.ItemPath).OnSuccess(t => items.Add(t))
79+
: await ContentPageContext.ShellPage.ShellViewModel.GetFolderFromPathAsync(listedItem.ItemPath).OnSuccess(t => items.Add(t));
80+
81+
if (!result)
82+
throw new IOException($"Failed to process {listedItem.ItemPath} in cutting/copying to the clipboard.", (int)result.ErrorCode);
83+
}
84+
},
85+
10,
86+
statusCenterItem?.CancellationToken ?? default);
87+
88+
var standardObjectsOnly = items.All(x => x is StorageFile or StorageFolder or SystemStorageFile or SystemStorageFolder);
89+
if (standardObjectsOnly)
90+
items = new ConcurrentBag<IStorageItem>(await items.ToStandardStorageItemsAsync());
91+
92+
if (items.IsEmpty)
93+
return;
94+
95+
dataPackage.Properties.PackageFamilyName = Windows.ApplicationModel.Package.Current.Id.FamilyName;
96+
dataPackage.SetStorageItems(items, false);
97+
98+
Clipboard.SetContent(dataPackage);
99+
}
100+
catch (Exception ex)
101+
{
102+
dataPackage = default;
103+
104+
if (ex is not IOException)
105+
App.Logger.LogWarning(ex, "Failed to process cutting/copying due to an unknown error.");
106+
107+
if ((FileSystemStatusCode)ex.HResult is FileSystemStatusCode.Unauthorized)
108+
{
109+
string[] filePaths = ContentPageContext.SelectedItems.Select(x => x.ItemPath).ToArray();
110+
await FileOperationsHelpers.SetClipboard(filePaths, type);
111+
112+
return;
113+
}
114+
115+
// Reset cut mode
116+
ContentPageContext.ShellPage.SlimContentPage.ItemManipulationModel.RefreshItemsOpacity();
117+
118+
return;
119+
}
120+
finally
121+
{
122+
if (statusCenterItem is not null)
123+
StatusCenterViewModel.RemoveItem(statusCenterItem);
124+
}
125+
}
126+
127+
private void ContentPageContext_PropertyChanged(object? sender, PropertyChangedEventArgs e)
128+
{
129+
if (e.PropertyName is nameof(IContentPageContext.HasSelection))
130+
OnPropertyChanged(nameof(IsExecutable));
131+
}
132+
}
133+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2024 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
4+
using Windows.ApplicationModel.DataTransfer;
5+
6+
namespace Files.App.Actions
7+
{
8+
internal sealed class CopyItemAction : BaseTransferItemAction, IAction
9+
{
10+
public string Label
11+
=> "Copy".GetLocalizedResource();
12+
13+
public string Description
14+
=> "CopyItemDescription".GetLocalizedResource();
15+
16+
public RichGlyph Glyph
17+
=> new(opacityStyle: "ColorIconCopy");
18+
19+
public HotKey HotKey
20+
=> new(Keys.C, KeyModifiers.Ctrl);
21+
22+
public CopyItemAction() : base()
23+
{
24+
}
25+
26+
public Task ExecuteAsync(object? parameter = null)
27+
{
28+
return ExecuteTransferAsync(DataPackageOperation.Copy);
29+
}
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2024 Files Community
2+
// Licensed under the MIT License. See the LICENSE.
3+
4+
using Windows.ApplicationModel.DataTransfer;
5+
6+
namespace Files.App.Actions
7+
{
8+
internal sealed class CutItemAction : BaseTransferItemAction, IAction
9+
{
10+
public string Label
11+
=> "Cut".GetLocalizedResource();
12+
13+
public string Description
14+
=> "CutItemDescription".GetLocalizedResource();
15+
16+
public RichGlyph Glyph
17+
=> new(opacityStyle: "ColorIconCut");
18+
19+
public HotKey HotKey
20+
=> new(Keys.X, KeyModifiers.Ctrl);
21+
22+
public CutItemAction() : base()
23+
{
24+
}
25+
26+
public Task ExecuteAsync(object? parameter = null)
27+
{
28+
return ExecuteTransferAsync(DataPackageOperation.Move);
29+
}
30+
}
31+
}

0 commit comments

Comments
 (0)