Skip to content

Commit dac6a20

Browse files
authored
Code Quality: Introduced IStorageArchiveService (#15341)
1 parent 9c03c54 commit dac6a20

19 files changed

+516
-437
lines changed

src/Files.App/Actions/Content/Archives/Compress/BaseCompressArchiveAction.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ namespace Files.App.Actions
66
internal abstract class BaseCompressArchiveAction : BaseUIAction, IAction
77
{
88
protected readonly IContentPageContext context;
9+
protected IStorageArchiveService StorageArchiveService { get; } = Ioc.Default.GetRequiredService<IStorageArchiveService>();
910

1011
public abstract string Label { get; }
1112

1213
public abstract string Description { get; }
1314

1415
public override bool IsExecutable =>
1516
IsContextPageTypeAdaptedToCommand() &&
16-
CompressHelper.CanCompress(context.SelectedItems) &&
17+
StorageArchiveService.CanCompress(context.SelectedItems) &&
1718
UIHelpers.CanShowDialog;
1819

1920
public BaseCompressArchiveAction()
@@ -25,6 +26,26 @@ public BaseCompressArchiveAction()
2526

2627
public abstract Task ExecuteAsync(object? parameter = null);
2728

29+
protected void GetDestination(out string[] sources, out string directory, out string fileName)
30+
{
31+
sources = context.SelectedItems.Select(item => item.ItemPath).ToArray();
32+
directory = string.Empty;
33+
fileName = string.Empty;
34+
35+
if (sources.Length is not 0)
36+
{
37+
// Get the current directory path
38+
directory = context.ShellPage.FilesystemViewModel.WorkingDirectory.Normalize();
39+
40+
// Get the library save folder if the folder is library item
41+
if (App.LibraryManager.TryGetLibrary(directory, out var library) && !library.IsEmpty)
42+
directory = library.DefaultSaveFolder;
43+
44+
// Gets the file name from the directory path
45+
fileName = SystemIO.Path.GetFileName(sources.Length is 1 ? sources[0] : directory);
46+
}
47+
}
48+
2849
private bool IsContextPageTypeAdaptedToCommand()
2950
{
3051
return

src/Files.App/Actions/Content/Archives/Compress/CompressIntoArchiveAction.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,9 @@ public override async Task ExecuteAsync(object? parameter = null)
2424
if (context.ShellPage is null)
2525
return;
2626

27-
var (sources, directory, fileName) = CompressHelper.GetCompressDestination(context.ShellPage);
27+
GetDestination(out var sources, out var directory, out var fileName);
2828

29-
var dialog = new CreateArchiveDialog
30-
{
31-
FileName = fileName,
32-
};
29+
var dialog = new CreateArchiveDialog() { FileName = fileName };
3330

3431
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
3532
dialog.XamlRoot = MainWindow.Instance.Content.XamlRoot;
@@ -39,7 +36,7 @@ public override async Task ExecuteAsync(object? parameter = null)
3936
if (!dialog.CanCreate || result != ContentDialogResult.Primary)
4037
return;
4138

42-
ICompressArchiveModel creator = new CompressArchiveModel(
39+
ICompressArchiveModel compressionModel = new CompressArchiveModel(
4340
sources,
4441
directory,
4542
dialog.FileName,
@@ -48,7 +45,7 @@ public override async Task ExecuteAsync(object? parameter = null)
4845
dialog.CompressionLevel,
4946
dialog.SplittingSize);
5047

51-
await CompressHelper.CompressArchiveAsync(creator);
48+
await StorageArchiveService.CompressAsync(compressionModel);
5249
}
5350
}
5451
}

src/Files.App/Actions/Content/Archives/Compress/CompressIntoSevenZipAction.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Files.App.Actions
66
internal sealed class CompressIntoSevenZipAction : BaseCompressArchiveAction
77
{
88
public override string Label
9-
=> string.Format("CreateNamedArchive".GetLocalizedResource(), $"{CompressHelper.DetermineArchiveNameFromSelection(context.SelectedItems)}.7z");
9+
=> string.Format("CreateNamedArchive".GetLocalizedResource(), $"{StorageArchiveService.GenerateArchiveNameFromItems(context.SelectedItems)}.7z");
1010

1111
public override string Description
1212
=> "CompressIntoSevenZipDescription".GetLocalizedResource();
@@ -20,15 +20,15 @@ public override Task ExecuteAsync(object? parameter = null)
2020
if (context.ShellPage is null)
2121
return Task.CompletedTask;
2222

23-
var (sources, directory, fileName) = CompressHelper.GetCompressDestination(context.ShellPage);
23+
GetDestination(out var sources, out var directory, out var fileName);
2424

25-
ICompressArchiveModel creator = new CompressArchiveModel(
25+
ICompressArchiveModel compressionModel = new CompressArchiveModel(
2626
sources,
2727
directory,
2828
fileName,
2929
fileFormat: ArchiveFormats.SevenZip);
3030

31-
return CompressHelper.CompressArchiveAsync(creator);
31+
return StorageArchiveService.CompressAsync(compressionModel);
3232
}
3333
}
3434
}

src/Files.App/Actions/Content/Archives/Compress/CompressIntoZipAction.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace Files.App.Actions
66
internal sealed class CompressIntoZipAction : BaseCompressArchiveAction
77
{
88
public override string Label
9-
=> string.Format("CreateNamedArchive".GetLocalizedResource(), $"{CompressHelper.DetermineArchiveNameFromSelection(context.SelectedItems)}.zip");
9+
=> string.Format("CreateNamedArchive".GetLocalizedResource(), $"{StorageArchiveService.GenerateArchiveNameFromItems(context.SelectedItems)}.zip");
1010

1111
public override string Description
1212
=> "CompressIntoZipDescription".GetLocalizedResource();
@@ -20,15 +20,15 @@ public override Task ExecuteAsync(object? parameter = null)
2020
if (context.ShellPage is null)
2121
return Task.CompletedTask;
2222

23-
var (sources, directory, fileName) = CompressHelper.GetCompressDestination(context.ShellPage);
23+
GetDestination(out var sources, out var directory, out var fileName);
2424

25-
ICompressArchiveModel creator = new CompressArchiveModel(
25+
ICompressArchiveModel compressionModel = new CompressArchiveModel(
2626
sources,
2727
directory,
2828
fileName,
2929
fileFormat: ArchiveFormats.Zip);
3030

31-
return CompressHelper.CompressArchiveAsync(creator);
31+
return StorageArchiveService.CompressAsync(compressionModel);
3232
}
3333
}
3434
}

src/Files.App/Actions/Content/Archives/Decompress/BaseDecompressArchiveAction.cs

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
// Copyright (c) 2024 Files Community
22
// Licensed under the MIT License. See the LICENSE.
33

4+
using Files.App.Dialogs;
5+
using Microsoft.UI.Xaml.Controls;
6+
using SevenZip;
7+
using System.Diagnostics.CodeAnalysis;
8+
using System.Text;
9+
using Windows.Foundation.Metadata;
10+
using Windows.Storage;
11+
412
namespace Files.App.Actions
513
{
614
internal abstract class BaseDecompressArchiveAction : BaseUIAction, IAction
715
{
816
protected readonly IContentPageContext context;
17+
protected IStorageArchiveService StorageArchiveService { get; } = Ioc.Default.GetRequiredService<IStorageArchiveService>();
918

1019
public abstract string Label { get; }
1120

@@ -16,7 +25,7 @@ public virtual HotKey HotKey
1625

1726
public override bool IsExecutable =>
1827
(IsContextPageTypeAdaptedToCommand() &&
19-
CompressHelper.CanDecompress(context.SelectedItems) ||
28+
StorageArchiveService.CanDecompress(context.SelectedItems) ||
2029
CanDecompressInsideArchive()) &&
2130
UIHelpers.CanShowDialog;
2231

@@ -37,6 +46,80 @@ protected bool IsContextPageTypeAdaptedToCommand()
3746
context.PageType != ContentPageTypes.None;
3847
}
3948

49+
protected async Task DecompressArchiveHereAsync(bool smart = false)
50+
{
51+
if (context.SelectedItems.Count is 0)
52+
return;
53+
54+
foreach (var selectedItem in context.SelectedItems)
55+
{
56+
var password = string.Empty;
57+
BaseStorageFile archive = await StorageHelpers.ToStorageItem<BaseStorageFile>(selectedItem.ItemPath);
58+
BaseStorageFolder currentFolder = await StorageHelpers.ToStorageItem<BaseStorageFolder>(context.ShellPage?.FilesystemViewModel.CurrentFolder?.ItemPath ?? string.Empty);
59+
60+
if (archive?.Path is null)
61+
return;
62+
63+
if (await FilesystemTasks.Wrap(() => StorageArchiveService.IsEncryptedAsync(archive.Path)))
64+
{
65+
DecompressArchiveDialog decompressArchiveDialog = new();
66+
DecompressArchiveDialogViewModel decompressArchiveViewModel = new(archive)
67+
{
68+
IsArchiveEncrypted = true,
69+
ShowPathSelection = false
70+
};
71+
72+
decompressArchiveDialog.ViewModel = decompressArchiveViewModel;
73+
74+
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
75+
decompressArchiveDialog.XamlRoot = MainWindow.Instance.Content.XamlRoot;
76+
77+
ContentDialogResult option = await decompressArchiveDialog.TryShowAsync();
78+
if (option != ContentDialogResult.Primary)
79+
return;
80+
81+
if (decompressArchiveViewModel.Password is not null)
82+
password = Encoding.UTF8.GetString(decompressArchiveViewModel.Password);
83+
}
84+
85+
BaseStorageFolder? destinationFolder = null;
86+
87+
var isMultipleItems = await FilesystemTasks.Wrap(async () =>
88+
{
89+
using SevenZipExtractor? zipFile = await StorageArchiveService.GetSevenZipExtractorAsync(archive.Path);
90+
if (zipFile is null)
91+
return true;
92+
93+
return zipFile.ArchiveFileData.Select(file =>
94+
{
95+
var pathCharIndex = file.FileName.IndexOfAny(['/', '\\']);
96+
if (pathCharIndex == -1)
97+
return file.FileName;
98+
else
99+
return file.FileName.Substring(0, pathCharIndex);
100+
})
101+
.Distinct().Count() > 1;
102+
});
103+
104+
if (smart && currentFolder is not null && isMultipleItems)
105+
{
106+
destinationFolder =
107+
await FilesystemTasks.Wrap(() =>
108+
currentFolder.CreateFolderAsync(
109+
SystemIO.Path.GetFileNameWithoutExtension(archive.Path),
110+
CreationCollisionOption.GenerateUniqueName).AsTask());
111+
}
112+
else
113+
{
114+
destinationFolder = currentFolder;
115+
}
116+
117+
// Operate decompress
118+
var result = await FilesystemTasks.Wrap(() =>
119+
StorageArchiveService.DecompressAsync(selectedItem.ItemPath, destinationFolder?.Path ?? string.Empty, password));
120+
}
121+
}
122+
40123
protected virtual bool CanDecompressInsideArchive()
41124
{
42125
return false;

src/Files.App/Actions/Content/Archives/Decompress/DecompressArchive.cs

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
// Copyright (c) 2024 Files Community
22
// Licensed under the MIT License. See the LICENSE.
33

4+
using Files.App.Dialogs;
45
using Files.Shared.Helpers;
6+
using Microsoft.UI.Xaml.Controls;
57
using System.IO;
8+
using System.Text;
9+
using Windows.Foundation.Metadata;
10+
using Windows.Storage;
611

712
namespace Files.App.Actions
813
{
@@ -21,12 +26,56 @@ public DecompressArchive()
2126
{
2227
}
2328

24-
public override Task ExecuteAsync(object? parameter = null)
29+
public override async Task ExecuteAsync(object? parameter = null)
2530
{
2631
if (context.ShellPage is null)
27-
return Task.CompletedTask;
32+
return;
2833

29-
return DecompressHelper.DecompressArchiveAsync(context.ShellPage);
34+
BaseStorageFile archive = await StorageHelpers.ToStorageItem<BaseStorageFile>(context.SelectedItem?.ItemPath ?? string.Empty);
35+
36+
if (archive?.Path is null)
37+
return;
38+
39+
var isArchiveEncrypted = await FilesystemTasks.Wrap(() => StorageArchiveService.IsEncryptedAsync(archive.Path));
40+
var password = string.Empty;
41+
42+
DecompressArchiveDialog decompressArchiveDialog = new();
43+
DecompressArchiveDialogViewModel decompressArchiveViewModel = new(archive)
44+
{
45+
IsArchiveEncrypted = isArchiveEncrypted,
46+
ShowPathSelection = true
47+
};
48+
decompressArchiveDialog.ViewModel = decompressArchiveViewModel;
49+
50+
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
51+
decompressArchiveDialog.XamlRoot = MainWindow.Instance.Content.XamlRoot;
52+
53+
ContentDialogResult option = await decompressArchiveDialog.TryShowAsync();
54+
if (option != ContentDialogResult.Primary)
55+
return;
56+
57+
if (isArchiveEncrypted && decompressArchiveViewModel.Password is not null)
58+
password = Encoding.UTF8.GetString(decompressArchiveViewModel.Password);
59+
60+
// Check if archive still exists
61+
if (!StorageHelpers.Exists(archive.Path))
62+
return;
63+
64+
BaseStorageFolder destinationFolder = decompressArchiveViewModel.DestinationFolder;
65+
string destinationFolderPath = decompressArchiveViewModel.DestinationFolderPath;
66+
67+
if (destinationFolder is null)
68+
{
69+
BaseStorageFolder parentFolder = await StorageHelpers.ToStorageItem<BaseStorageFolder>(Path.GetDirectoryName(archive.Path) ?? string.Empty);
70+
destinationFolder = await FilesystemTasks.Wrap(() => parentFolder.CreateFolderAsync(Path.GetFileName(destinationFolderPath), CreationCollisionOption.GenerateUniqueName).AsTask());
71+
}
72+
73+
// Operate decompress
74+
var result = await FilesystemTasks.Wrap(() =>
75+
StorageArchiveService.DecompressAsync(archive?.Path ?? string.Empty, destinationFolder?.Path ?? string.Empty, password));
76+
77+
if (decompressArchiveViewModel.OpenDestinationFolderOnCompletion)
78+
await NavigationHelpers.OpenPath(destinationFolderPath, context.ShellPage, FilesystemItemType.Directory);
3079
}
3180

3281
protected override bool CanDecompressInsideArchive()

src/Files.App/Actions/Content/Archives/Decompress/DecompressArchiveHere.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public DecompressArchiveHere()
1717

1818
public override Task ExecuteAsync(object? parameter = null)
1919
{
20-
return DecompressHelper.DecompressArchiveHereAsync(context.ShellPage);
20+
return DecompressArchiveHereAsync();
2121
}
2222
}
2323
}

src/Files.App/Actions/Content/Archives/Decompress/DecompressArchiveHereSmart.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public DecompressArchiveHereSmart()
2020

2121
public override Task ExecuteAsync(object? parameter = null)
2222
{
23-
return DecompressHelper.DecompressArchiveHereAsync(context.ShellPage, true);
23+
return DecompressArchiveHereAsync(true);
2424
}
2525
}
2626
}

0 commit comments

Comments
 (0)