diff --git a/src/Files.App (Package)/Package.appxmanifest b/src/Files.App (Package)/Package.appxmanifest
index baa16eb56734..8c8ac739b25a 100644
--- a/src/Files.App (Package)/Package.appxmanifest
+++ b/src/Files.App (Package)/Package.appxmanifest
@@ -16,7 +16,7 @@
+ Version="2.5.22.0" />
Files - Dev
diff --git a/src/Files.App.Storage/NativeStorage/NativeFile.cs b/src/Files.App.Storage/NativeStorage/NativeFile.cs
index a22e9b6eab57..bb8fbea713f7 100644
--- a/src/Files.App.Storage/NativeStorage/NativeFile.cs
+++ b/src/Files.App.Storage/NativeStorage/NativeFile.cs
@@ -15,13 +15,13 @@ namespace Files.App.Storage.NativeStorage
///
public class NativeFile : NativeStorable, ILocatableFile, IModifiableFile, IFileExtended, INestedFile
{
- public NativeFile(FileInfo fileInfo)
- : base(fileInfo)
+ public NativeFile(FileInfo fileInfo, string? name = null)
+ : base(fileInfo, name)
{
}
- public NativeFile(string path)
- : this(new FileInfo(path))
+ public NativeFile(string path, string? name = null)
+ : this(new FileInfo(path), name)
{
}
diff --git a/src/Files.App.Storage/NativeStorage/NativeFolder.cs b/src/Files.App.Storage/NativeStorage/NativeFolder.cs
index fedea9a05bfb..d59f2e02ef49 100644
--- a/src/Files.App.Storage/NativeStorage/NativeFolder.cs
+++ b/src/Files.App.Storage/NativeStorage/NativeFolder.cs
@@ -22,13 +22,13 @@ namespace Files.App.Storage.NativeStorage
///
public class NativeFolder : NativeStorable, ILocatableFolder, IModifiableFolder, IMutableFolder, IFolderExtended, INestedFolder, IDirectCopy, IDirectMove
{
- public NativeFolder(DirectoryInfo directoryInfo)
- : base(directoryInfo)
+ public NativeFolder(DirectoryInfo directoryInfo, string? name = null)
+ : base(directoryInfo, name)
{
}
- public NativeFolder(string path)
- : this(new DirectoryInfo(path))
+ public NativeFolder(string path, string? name = null)
+ : this(new DirectoryInfo(path), name)
{
}
diff --git a/src/Files.App.Storage/NativeStorage/NativeStorable.cs b/src/Files.App.Storage/NativeStorage/NativeStorable.cs
index 1a8fbcc3ca7a..966dc97d3d32 100644
--- a/src/Files.App.Storage/NativeStorage/NativeStorable.cs
+++ b/src/Files.App.Storage/NativeStorage/NativeStorable.cs
@@ -17,19 +17,19 @@ public abstract class NativeStorable : ILocatableStorable, INestedStor
protected readonly TStorage storage;
///
- public virtual string Path { get; protected set; }
+ public string Path { get; protected set; }
///
- public virtual string Name { get; protected set; }
+ public string Name { get; protected set; }
///
public virtual string Id { get; }
- protected NativeStorable(TStorage storage)
+ protected NativeStorable(TStorage storage, string? name = null)
{
this.storage = storage;
Path = storage.FullName;
- Name = storage.Name;
+ Name = name ?? storage.Name;
Id = storage.FullName;
}
diff --git a/src/Files.App.Storage/NativeStorage/NativeStorageService.cs b/src/Files.App.Storage/NativeStorage/NativeStorageService.cs
index 7e2326325dce..5812862ba8a9 100644
--- a/src/Files.App.Storage/NativeStorage/NativeStorageService.cs
+++ b/src/Files.App.Storage/NativeStorage/NativeStorageService.cs
@@ -2,10 +2,12 @@
// Licensed under the MIT License. See the LICENSE.
using Files.Core.Storage;
-using Files.Core.Storage.LocatableStorage;
+using Files.Shared.Helpers;
+using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using Windows.Storage;
namespace Files.App.Storage.NativeStorage
{
@@ -22,12 +24,31 @@ public Task GetFileAsync(string id, CancellationToken cancellationToken =
}
///
- public Task GetFolderAsync(string id, CancellationToken cancellationToken = default)
+ public async Task GetFolderAsync(string id, CancellationToken cancellationToken = default)
{
if (!Directory.Exists(id))
throw new DirectoryNotFoundException();
- return Task.FromResult(new NativeFolder(id));
+ // A special folder should use the localized name
+ if (PathHelpers.IsSpecialFolder(id))
+ {
+ var storageFolder = await TryGetStorageFolderAsync(id);
+ return new NativeFolder(id, storageFolder?.DisplayName);
+ }
+
+ return new NativeFolder(id);
+
+ async Task TryGetStorageFolderAsync(string path)
+ {
+ try
+ {
+ return await StorageFolder.GetFolderFromPathAsync(path);
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
}
}
}
diff --git a/src/Files.App/Actions/Content/Archives/DecompressArchiveHere.cs b/src/Files.App/Actions/Content/Archives/Compress/BaseCompressArchiveAction.cs
similarity index 65%
rename from src/Files.App/Actions/Content/Archives/DecompressArchiveHere.cs
rename to src/Files.App/Actions/Content/Archives/Compress/BaseCompressArchiveAction.cs
index 765a6698e2d0..e9e4cb06d6ba 100644
--- a/src/Files.App/Actions/Content/Archives/DecompressArchiveHere.cs
+++ b/src/Files.App/Actions/Content/Archives/Compress/BaseCompressArchiveAction.cs
@@ -3,32 +3,27 @@
namespace Files.App.Actions
{
- internal class DecompressArchiveHere : BaseUIAction, IAction
+ internal abstract class BaseCompressArchiveAction : BaseUIAction, IAction
{
- private readonly IContentPageContext context;
+ protected readonly IContentPageContext context;
- public string Label
- => "ExtractHere".GetLocalizedResource();
+ public abstract string Label { get; }
- public string Description
- => "DecompressArchiveHereDescription".GetLocalizedResource();
+ public abstract string Description { get; }
public override bool IsExecutable =>
IsContextPageTypeAdaptedToCommand() &&
- ArchiveHelpers.CanDecompress(context.SelectedItems) &&
+ ArchiveHelpers.CanCompress(context.SelectedItems) &&
UIHelpers.CanShowDialog;
- public DecompressArchiveHere()
+ public BaseCompressArchiveAction()
{
context = Ioc.Default.GetRequiredService();
context.PropertyChanged += Context_PropertyChanged;
}
- public Task ExecuteAsync()
- {
- return ArchiveHelpers.DecompressArchiveHere(context.ShellPage);
- }
+ public abstract Task ExecuteAsync();
private bool IsContextPageTypeAdaptedToCommand()
{
diff --git a/src/Files.App/Actions/Content/Archives/Compress/CompressIntoArchiveAction.cs b/src/Files.App/Actions/Content/Archives/Compress/CompressIntoArchiveAction.cs
new file mode 100644
index 000000000000..9455c0b42a15
--- /dev/null
+++ b/src/Files.App/Actions/Content/Archives/Compress/CompressIntoArchiveAction.cs
@@ -0,0 +1,49 @@
+// Copyright (c) 2023 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
+using Files.App.Dialogs;
+using Microsoft.UI.Xaml.Controls;
+
+namespace Files.App.Actions
+{
+ internal sealed class CompressIntoArchiveAction : BaseCompressArchiveAction
+ {
+ public override string Label
+ => "CreateArchive".GetLocalizedResource();
+
+ public override string Description
+ => "CompressIntoArchiveDescription".GetLocalizedResource();
+
+ public CompressIntoArchiveAction()
+ {
+ }
+
+ public override async Task ExecuteAsync()
+ {
+ var (sources, directory, fileName) = ArchiveHelpers.GetCompressDestination(context.ShellPage);
+
+ var dialog = new CreateArchiveDialog
+ {
+ FileName = fileName,
+ };
+
+ var result = await dialog.TryShowAsync();
+
+ if (!dialog.CanCreate || result != ContentDialogResult.Primary)
+ return;
+
+ IArchiveCreator creator = new ArchiveCreator
+ {
+ Sources = sources,
+ Directory = directory,
+ FileName = dialog.FileName,
+ Password = dialog.Password,
+ FileFormat = dialog.FileFormat,
+ CompressionLevel = dialog.CompressionLevel,
+ SplittingSize = dialog.SplittingSize,
+ };
+
+ await ArchiveHelpers.CompressArchiveAsync(creator);
+ }
+ }
+}
diff --git a/src/Files.App/Actions/Content/Archives/Compress/CompressIntoSevenZipAction.cs b/src/Files.App/Actions/Content/Archives/Compress/CompressIntoSevenZipAction.cs
new file mode 100644
index 000000000000..7f4a79e79819
--- /dev/null
+++ b/src/Files.App/Actions/Content/Archives/Compress/CompressIntoSevenZipAction.cs
@@ -0,0 +1,33 @@
+// Copyright (c) 2023 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
+namespace Files.App.Actions
+{
+ internal sealed class CompressIntoSevenZipAction : BaseCompressArchiveAction
+ {
+ public override string Label
+ => string.Format("CreateNamedArchive".GetLocalizedResource(), $"{ArchiveHelpers.DetermineArchiveNameFromSelection(context.SelectedItems)}.7z");
+
+ public override string Description
+ => "CompressIntoSevenZipDescription".GetLocalizedResource();
+
+ public CompressIntoSevenZipAction()
+ {
+ }
+
+ public override Task ExecuteAsync()
+ {
+ var (sources, directory, fileName) = ArchiveHelpers.GetCompressDestination(context.ShellPage);
+
+ IArchiveCreator creator = new ArchiveCreator
+ {
+ Sources = sources,
+ Directory = directory,
+ FileName = fileName,
+ FileFormat = ArchiveFormats.SevenZip,
+ };
+
+ return ArchiveHelpers.CompressArchiveAsync(creator);
+ }
+ }
+}
diff --git a/src/Files.App/Actions/Content/Archives/Compress/CompressIntoZipAction.cs b/src/Files.App/Actions/Content/Archives/Compress/CompressIntoZipAction.cs
new file mode 100644
index 000000000000..6c473f7beb82
--- /dev/null
+++ b/src/Files.App/Actions/Content/Archives/Compress/CompressIntoZipAction.cs
@@ -0,0 +1,33 @@
+// Copyright (c) 2023 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
+namespace Files.App.Actions
+{
+ internal sealed class CompressIntoZipAction : BaseCompressArchiveAction
+ {
+ public override string Label
+ => string.Format("CreateNamedArchive".GetLocalizedResource(), $"{ArchiveHelpers.DetermineArchiveNameFromSelection(context.SelectedItems)}.zip");
+
+ public override string Description
+ => "CompressIntoZipDescription".GetLocalizedResource();
+
+ public CompressIntoZipAction()
+ {
+ }
+
+ public override Task ExecuteAsync()
+ {
+ var (sources, directory, fileName) = ArchiveHelpers.GetCompressDestination(context.ShellPage);
+
+ IArchiveCreator creator = new ArchiveCreator
+ {
+ Sources = sources,
+ Directory = directory,
+ FileName = fileName,
+ FileFormat = ArchiveFormats.Zip,
+ };
+
+ return ArchiveHelpers.CompressArchiveAsync(creator);
+ }
+ }
+}
diff --git a/src/Files.App/Actions/Content/Archives/CompressIntoArchiveAction.cs b/src/Files.App/Actions/Content/Archives/CompressIntoArchiveAction.cs
deleted file mode 100644
index e2db95ccfc15..000000000000
--- a/src/Files.App/Actions/Content/Archives/CompressIntoArchiveAction.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright (c) 2023 Files Community
-// Licensed under the MIT License. See the LICENSE.
-
-using Files.App.Dialogs;
-using Files.App.Utils.Archives;
-using Microsoft.UI.Xaml.Controls;
-
-namespace Files.App.Actions
-{
- internal class CompressIntoArchiveAction : BaseUIAction, IAction
- {
- private readonly IContentPageContext context;
-
- public string Label
- => "CreateArchive".GetLocalizedResource();
-
- public string Description
- => "CompressIntoArchiveDescription".GetLocalizedResource();
-
- public override bool IsExecutable =>
- IsContextPageTypeAdaptedToCommand() &&
- ArchiveHelpers.CanCompress(context.SelectedItems) &&
- UIHelpers.CanShowDialog;
-
- public CompressIntoArchiveAction()
- {
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
- }
-
- public async Task ExecuteAsync()
- {
- var (sources, directory, fileName) = ArchiveHelpers.GetCompressDestination(context.ShellPage);
-
- var dialog = new CreateArchiveDialog
- {
- FileName = fileName,
- };
-
- var result = await dialog.TryShowAsync();
-
- if (!dialog.CanCreate || result != ContentDialogResult.Primary)
- return;
-
- IArchiveCreator creator = new ArchiveCreator
- {
- Sources = sources,
- Directory = directory,
- FileName = dialog.FileName,
- Password = dialog.Password,
- FileFormat = dialog.FileFormat,
- CompressionLevel = dialog.CompressionLevel,
- SplittingSize = dialog.SplittingSize,
- };
-
- await ArchiveHelpers.CompressArchiveAsync(creator);
- }
-
- private bool IsContextPageTypeAdaptedToCommand()
- {
- return
- context.PageType != ContentPageTypes.RecycleBin &&
- context.PageType != ContentPageTypes.ZipFolder &&
- context.PageType != ContentPageTypes.None;
- }
-
- private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
- {
- switch (e.PropertyName)
- {
- case nameof(IContentPageContext.SelectedItems):
- if (IsContextPageTypeAdaptedToCommand())
- OnPropertyChanged(nameof(IsExecutable));
- break;
- }
- }
- }
-}
diff --git a/src/Files.App/Actions/Content/Archives/CompressIntoSevenZipAction.cs b/src/Files.App/Actions/Content/Archives/CompressIntoSevenZipAction.cs
deleted file mode 100644
index a816ed9e6361..000000000000
--- a/src/Files.App/Actions/Content/Archives/CompressIntoSevenZipAction.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2023 Files Community
-// Licensed under the MIT License. See the LICENSE.
-
-using Files.App.Utils.Archives;
-
-namespace Files.App.Actions
-{
- internal class CompressIntoSevenZipAction : ObservableObject, IAction
- {
- private readonly IContentPageContext context;
-
- public string Label
- => string.Format("CreateNamedArchive".GetLocalizedResource(), $"{ArchiveHelpers.DetermineArchiveNameFromSelection(context.SelectedItems)}.7z");
-
- public string Description
- => "CompressIntoSevenZipDescription".GetLocalizedResource();
-
- public bool IsExecutable =>
- IsContextPageTypeAdaptedToCommand() &&
- ArchiveHelpers.CanCompress(context.SelectedItems);
-
- public CompressIntoSevenZipAction()
- {
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
- }
-
- public Task ExecuteAsync()
- {
- var (sources, directory, fileName) = ArchiveHelpers.GetCompressDestination(context.ShellPage);
-
- IArchiveCreator creator = new ArchiveCreator
- {
- Sources = sources,
- Directory = directory,
- FileName = fileName,
- FileFormat = ArchiveFormats.SevenZip,
- };
-
- return ArchiveHelpers.CompressArchiveAsync(creator);
- }
-
- private bool IsContextPageTypeAdaptedToCommand()
- {
- return
- context.PageType != ContentPageTypes.RecycleBin &&
- context.PageType != ContentPageTypes.ZipFolder &&
- context.PageType != ContentPageTypes.None;
- }
-
- private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
- {
- switch (e.PropertyName)
- {
- case nameof(IContentPageContext.SelectedItems):
- if (IsContextPageTypeAdaptedToCommand())
- OnPropertyChanged(nameof(IsExecutable));
- break;
- }
- }
- }
-}
diff --git a/src/Files.App/Actions/Content/Archives/CompressIntoZipAction.cs b/src/Files.App/Actions/Content/Archives/CompressIntoZipAction.cs
deleted file mode 100644
index c38fae0c6af6..000000000000
--- a/src/Files.App/Actions/Content/Archives/CompressIntoZipAction.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2023 Files Community
-// Licensed under the MIT License. See the LICENSE.
-
-using Files.App.Utils.Archives;
-
-namespace Files.App.Actions
-{
- internal class CompressIntoZipAction : ObservableObject, IAction
- {
- private readonly IContentPageContext context;
-
- public string Label
- => string.Format("CreateNamedArchive".GetLocalizedResource(), $"{ArchiveHelpers.DetermineArchiveNameFromSelection(context.SelectedItems)}.zip");
-
- public string Description
- => "CompressIntoZipDescription".GetLocalizedResource();
-
- public bool IsExecutable =>
- IsContextPageTypeAdaptedToCommand() &&
- ArchiveHelpers.CanCompress(context.SelectedItems);
-
- public CompressIntoZipAction()
- {
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
- }
-
- public Task ExecuteAsync()
- {
- var (sources, directory, fileName) = ArchiveHelpers.GetCompressDestination(context.ShellPage);
-
- IArchiveCreator creator = new ArchiveCreator
- {
- Sources = sources,
- Directory = directory,
- FileName = fileName,
- FileFormat = ArchiveFormats.Zip,
- };
-
- return ArchiveHelpers.CompressArchiveAsync(creator);
- }
-
- private bool IsContextPageTypeAdaptedToCommand()
- {
- return
- context.PageType != ContentPageTypes.RecycleBin &&
- context.PageType != ContentPageTypes.ZipFolder &&
- context.PageType != ContentPageTypes.None;
- }
-
- private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
- {
- switch (e.PropertyName)
- {
- case nameof(IContentPageContext.SelectedItems):
- if (IsContextPageTypeAdaptedToCommand())
- OnPropertyChanged(nameof(IsExecutable));
- break;
- }
- }
- }
-}
diff --git a/src/Files.App/Actions/Content/Archives/Decompress/BaseDecompressArchiveAction.cs b/src/Files.App/Actions/Content/Archives/Decompress/BaseDecompressArchiveAction.cs
new file mode 100644
index 000000000000..52075e7e7978
--- /dev/null
+++ b/src/Files.App/Actions/Content/Archives/Decompress/BaseDecompressArchiveAction.cs
@@ -0,0 +1,55 @@
+// Copyright (c) 2023 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
+namespace Files.App.Actions
+{
+ internal abstract class BaseDecompressArchiveAction : BaseUIAction, IAction
+ {
+ protected readonly IContentPageContext context;
+
+ public abstract string Label { get; }
+
+ public abstract string Description { get; }
+
+ public virtual HotKey HotKey
+ => HotKey.None;
+
+ public override bool IsExecutable =>
+ (IsContextPageTypeAdaptedToCommand() &&
+ ArchiveHelpers.CanDecompress(context.SelectedItems) ||
+ CanDecompressInsideArchive()) &&
+ UIHelpers.CanShowDialog;
+
+ public BaseDecompressArchiveAction()
+ {
+ context = Ioc.Default.GetRequiredService();
+
+ context.PropertyChanged += Context_PropertyChanged;
+ }
+
+ public abstract Task ExecuteAsync();
+
+ protected bool IsContextPageTypeAdaptedToCommand()
+ {
+ return
+ context.PageType != ContentPageTypes.RecycleBin &&
+ context.PageType != ContentPageTypes.ZipFolder &&
+ context.PageType != ContentPageTypes.None;
+ }
+
+ protected virtual bool CanDecompressInsideArchive()
+ {
+ return false;
+ }
+
+ protected virtual void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
+ {
+ switch (e.PropertyName)
+ {
+ case nameof(IContentPageContext.SelectedItems):
+ OnPropertyChanged(nameof(IsExecutable));
+ break;
+ }
+ }
+ }
+}
diff --git a/src/Files.App/Actions/Content/Archives/Decompress/DecompressArchive.cs b/src/Files.App/Actions/Content/Archives/Decompress/DecompressArchive.cs
new file mode 100644
index 000000000000..62754bf93664
--- /dev/null
+++ b/src/Files.App/Actions/Content/Archives/Decompress/DecompressArchive.cs
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
+using Files.Shared.Helpers;
+using System.IO;
+
+namespace Files.App.Actions
+{
+ internal sealed class DecompressArchive : BaseDecompressArchiveAction
+ {
+ public override string Label
+ => "ExtractFiles".GetLocalizedResource();
+
+ public override string Description
+ => "DecompressArchiveDescription".GetLocalizedResource();
+
+ public override HotKey HotKey
+ => new(Keys.E, KeyModifiers.Ctrl);
+
+ public DecompressArchive()
+ {
+ }
+
+ public override Task ExecuteAsync()
+ {
+ return ArchiveHelpers.DecompressArchive(context.ShellPage);
+ }
+
+ protected override bool CanDecompressInsideArchive()
+ {
+ return
+ context.PageType == ContentPageTypes.ZipFolder &&
+ !context.HasSelection &&
+ context.Folder is not null &&
+ FileExtensionHelpers.IsZipFile(Path.GetExtension(context.Folder.ItemPath));
+ }
+ }
+}
diff --git a/src/Files.App/Actions/Content/Archives/Decompress/DecompressArchiveHere.cs b/src/Files.App/Actions/Content/Archives/Decompress/DecompressArchiveHere.cs
new file mode 100644
index 000000000000..7106d0a18bdd
--- /dev/null
+++ b/src/Files.App/Actions/Content/Archives/Decompress/DecompressArchiveHere.cs
@@ -0,0 +1,23 @@
+// Copyright (c) 2023 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
+namespace Files.App.Actions
+{
+ internal sealed class DecompressArchiveHere : BaseDecompressArchiveAction
+ {
+ public override string Label
+ => "ExtractHere".GetLocalizedResource();
+
+ public override string Description
+ => "DecompressArchiveHereDescription".GetLocalizedResource();
+
+ public DecompressArchiveHere()
+ {
+ }
+
+ public override Task ExecuteAsync()
+ {
+ return ArchiveHelpers.DecompressArchiveHere(context.ShellPage);
+ }
+ }
+}
diff --git a/src/Files.App/Actions/Content/Archives/DecompressArchiveToChildFolderAction.cs b/src/Files.App/Actions/Content/Archives/Decompress/DecompressArchiveToChildFolderAction.cs
similarity index 57%
rename from src/Files.App/Actions/Content/Archives/DecompressArchiveToChildFolderAction.cs
rename to src/Files.App/Actions/Content/Archives/Decompress/DecompressArchiveToChildFolderAction.cs
index d1cb7d433017..7d1dbc3c4d35 100644
--- a/src/Files.App/Actions/Content/Archives/DecompressArchiveToChildFolderAction.cs
+++ b/src/Files.App/Actions/Content/Archives/Decompress/DecompressArchiveToChildFolderAction.cs
@@ -3,52 +3,24 @@
namespace Files.App.Actions
{
- internal class DecompressArchiveToChildFolderAction : BaseUIAction, IAction
+ internal sealed class DecompressArchiveToChildFolderAction : BaseDecompressArchiveAction
{
- private readonly IContentPageContext context;
-
- public string Label
+ public override string Label
=> ComputeLabel();
- public string Description
+ public override string Description
=> "DecompressArchiveToChildFolderDescription".GetLocalizedResource();
- public override bool IsExecutable =>
- IsContextPageTypeAdaptedToCommand() &&
- ArchiveHelpers.CanDecompress(context.SelectedItems) &&
- UIHelpers.CanShowDialog;
-
public DecompressArchiveToChildFolderAction()
{
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
}
- public Task ExecuteAsync()
+ public override Task ExecuteAsync()
{
return ArchiveHelpers.DecompressArchiveToChildFolder(context.ShellPage);
}
- private bool IsContextPageTypeAdaptedToCommand()
- {
- return
- context.PageType != ContentPageTypes.RecycleBin &&
- context.PageType != ContentPageTypes.ZipFolder &&
- context.PageType != ContentPageTypes.None;
- }
-
- private string ComputeLabel()
- {
- if (context.SelectedItems == null || context.SelectedItems.Count == 0)
- return string.Empty;
-
- return context.SelectedItems.Count > 1
- ? string.Format("BaseLayoutItemContextFlyoutExtractToChildFolder".GetLocalizedResource(), "*")
- : string.Format("BaseLayoutItemContextFlyoutExtractToChildFolder".GetLocalizedResource(), SystemIO.Path.GetFileNameWithoutExtension(context.SelectedItems.First().Name));
- }
-
- private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
+ protected override void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
@@ -64,5 +36,15 @@ private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
}
}
}
+
+ private string ComputeLabel()
+ {
+ if (context.SelectedItems == null || context.SelectedItems.Count == 0)
+ return string.Empty;
+
+ return context.SelectedItems.Count > 1
+ ? string.Format("BaseLayoutItemContextFlyoutExtractToChildFolder".GetLocalizedResource(), "*")
+ : string.Format("BaseLayoutItemContextFlyoutExtractToChildFolder".GetLocalizedResource(), SystemIO.Path.GetFileNameWithoutExtension(context.SelectedItems.First().Name));
+ }
}
}
diff --git a/src/Files.App/Actions/Content/Archives/DecompressArchive.cs b/src/Files.App/Actions/Content/Archives/DecompressArchive.cs
deleted file mode 100644
index 23dbb1b5f816..000000000000
--- a/src/Files.App/Actions/Content/Archives/DecompressArchive.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2023 Files Community
-// Licensed under the MIT License. See the LICENSE.
-
-using System.IO;
-
-namespace Files.App.Actions
-{
- internal class DecompressArchive : BaseUIAction, IAction
- {
- private readonly IContentPageContext context;
-
- public string Label
- => "ExtractFiles".GetLocalizedResource();
-
- public string Description
- => "DecompressArchiveDescription".GetLocalizedResource();
-
- public HotKey HotKey
- => new(Keys.E, KeyModifiers.Ctrl);
-
- public override bool IsExecutable =>
- (IsContextPageTypeAdaptedToCommand() &&
- ArchiveHelpers.CanDecompress(context.SelectedItems) ||
- CanDecompressInsideArchive()) &&
- UIHelpers.CanShowDialog;
-
- public DecompressArchive()
- {
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
- }
-
- public Task ExecuteAsync()
- {
- return ArchiveHelpers.DecompressArchive(context.ShellPage);
- }
-
- private bool IsContextPageTypeAdaptedToCommand()
- {
- return
- context.PageType != ContentPageTypes.RecycleBin &&
- context.PageType != ContentPageTypes.ZipFolder &&
- context.PageType != ContentPageTypes.None;
- }
-
- private bool CanDecompressInsideArchive()
- {
- return
- context.PageType == ContentPageTypes.ZipFolder &&
- !context.HasSelection &&
- context.Folder is not null &&
- FileExtensionHelpers.IsZipFile(Path.GetExtension(context.Folder.ItemPath));
- }
-
- private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
- {
- switch (e.PropertyName)
- {
- case nameof(IContentPageContext.SelectedItems):
- OnPropertyChanged(nameof(IsExecutable));
- break;
- }
- }
- }
-}
diff --git a/src/Files.App/Actions/Content/Install/InstallCertificateAction.cs b/src/Files.App/Actions/Content/Install/InstallCertificateAction.cs
index 1bd17ebe0476..7da225655641 100644
--- a/src/Files.App/Actions/Content/Install/InstallCertificateAction.cs
+++ b/src/Files.App/Actions/Content/Install/InstallCertificateAction.cs
@@ -1,7 +1,7 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
-using Files.App.Utils.Shell;
+using Files.Shared.Helpers;
namespace Files.App.Actions
{
diff --git a/src/Files.App/Actions/Content/Install/InstallFontAction.cs b/src/Files.App/Actions/Content/Install/InstallFontAction.cs
index 66a7cf8ada86..f0df08623624 100644
--- a/src/Files.App/Actions/Content/Install/InstallFontAction.cs
+++ b/src/Files.App/Actions/Content/Install/InstallFontAction.cs
@@ -1,7 +1,7 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
-using Files.App.Utils.Shell;
+using Files.Shared.Helpers;
namespace Files.App.Actions
{
diff --git a/src/Files.App/Actions/Content/Install/InstallInfDriverAction.cs b/src/Files.App/Actions/Content/Install/InstallInfDriverAction.cs
index 960f98d68b35..d2bbe004b551 100644
--- a/src/Files.App/Actions/Content/Install/InstallInfDriverAction.cs
+++ b/src/Files.App/Actions/Content/Install/InstallInfDriverAction.cs
@@ -1,7 +1,7 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
-using Files.App.Utils.Shell;
+using Files.Shared.Helpers;
namespace Files.App.Actions
{
diff --git a/src/Files.App/Actions/Content/PlayAllAction.cs b/src/Files.App/Actions/Content/PlayAllAction.cs
index 3d8a58d7f029..3fdfc3c872a8 100644
--- a/src/Files.App/Actions/Content/PlayAllAction.cs
+++ b/src/Files.App/Actions/Content/PlayAllAction.cs
@@ -1,6 +1,8 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
+using Files.Shared.Helpers;
+
namespace Files.App.Actions
{
internal class PlayAllAction : ObservableObject, IAction
diff --git a/src/Files.App/Actions/Content/Run/BaseRunAsAction.cs b/src/Files.App/Actions/Content/Run/BaseRunAsAction.cs
new file mode 100644
index 000000000000..002e6a91873a
--- /dev/null
+++ b/src/Files.App/Actions/Content/Run/BaseRunAsAction.cs
@@ -0,0 +1,50 @@
+// Copyright (c) 2023 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
+using Files.Shared.Helpers;
+
+namespace Files.App.Actions
+{
+ internal abstract class BaseRunAsAction : ObservableObject, IAction
+ {
+ private readonly IContentPageContext _context;
+
+ private readonly string _verb;
+
+ public abstract string Label { get; }
+
+ public abstract string Description { get; }
+
+ public abstract RichGlyph Glyph { get; }
+
+ public bool IsExecutable =>
+ _context.SelectedItem is not null &&
+ (FileExtensionHelpers.IsExecutableFile(_context.SelectedItem.FileExtension) ||
+ (_context.SelectedItem is ShortcutItem shortcut &&
+ shortcut.IsExecutable));
+
+ public BaseRunAsAction(string verb)
+ {
+ _verb = verb;
+ _context = Ioc.Default.GetRequiredService();
+
+ _context.PropertyChanged += Context_PropertyChanged;
+ }
+
+ public async Task ExecuteAsync()
+ {
+ await ContextMenu.InvokeVerb(_verb, _context.SelectedItem!.ItemPath);
+ }
+
+ public void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
+ {
+ switch (e.PropertyName)
+ {
+ case nameof(IContentPageContext.SelectedItems):
+ case nameof(IContentPageContext.Folder):
+ OnPropertyChanged(nameof(IsExecutable));
+ break;
+ }
+ }
+ }
+}
diff --git a/src/Files.App/Actions/Content/Run/RunAsAdminAction.cs b/src/Files.App/Actions/Content/Run/RunAsAdminAction.cs
index 8facd2f3807b..451988dd06f7 100644
--- a/src/Files.App/Actions/Content/Run/RunAsAdminAction.cs
+++ b/src/Files.App/Actions/Content/Run/RunAsAdminAction.cs
@@ -1,48 +1,23 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
+using Files.Shared.Helpers;
+
namespace Files.App.Actions
{
- internal class RunAsAdminAction : ObservableObject, IAction
+ internal sealed class RunAsAdminAction : BaseRunAsAction
{
- private readonly IContentPageContext context;
-
- public string Label
+ public override string Label
=> "RunAsAdministrator".GetLocalizedResource();
- public string Description
+ public override string Description
=> "RunAsAdminDescription".GetLocalizedResource();
- public RichGlyph Glyph
+ public override RichGlyph Glyph
=> new("\uE7EF");
- public bool IsExecutable =>
- context.SelectedItem is not null &&
- (FileExtensionHelpers.IsExecutableFile(context.SelectedItem.FileExtension) ||
- (context.SelectedItem is ShortcutItem shortcut &&
- shortcut.IsExecutable));
-
- public RunAsAdminAction()
- {
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
- }
-
- public async Task ExecuteAsync()
- {
- await ContextMenu.InvokeVerb("runas", context.SelectedItem!.ItemPath);
- }
-
- public void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
+ public RunAsAdminAction() : base("runas")
{
- switch (e.PropertyName)
- {
- case nameof(IContentPageContext.SelectedItems):
- case nameof(IContentPageContext.Folder):
- OnPropertyChanged(nameof(IsExecutable));
- break;
- }
}
}
}
diff --git a/src/Files.App/Actions/Content/Run/RunAsAnotherUserAction.cs b/src/Files.App/Actions/Content/Run/RunAsAnotherUserAction.cs
index f3e7b97df0a4..b42ee8008d7d 100644
--- a/src/Files.App/Actions/Content/Run/RunAsAnotherUserAction.cs
+++ b/src/Files.App/Actions/Content/Run/RunAsAnotherUserAction.cs
@@ -1,48 +1,23 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
+using Files.Shared.Helpers;
+
namespace Files.App.Actions
{
- internal class RunAsAnotherUserAction : ObservableObject, IAction
+ internal sealed class RunAsAnotherUserAction : BaseRunAsAction
{
- public IContentPageContext context;
-
- public bool IsExecutable =>
- context.SelectedItem is not null &&
- (FileExtensionHelpers.IsExecutableFile(context.SelectedItem.FileExtension) ||
- (context.SelectedItem is ShortcutItem shortcut &&
- shortcut.IsExecutable));
-
- public string Label
+ public override string Label
=> "BaseLayoutContextFlyoutRunAsAnotherUser/Text".GetLocalizedResource();
- public string Description
+ public override string Description
=> "RunAsAnotherUserDescription".GetLocalizedResource();
- public RichGlyph Glyph
+ public override RichGlyph Glyph
=> new("\uE7EE");
- public RunAsAnotherUserAction()
- {
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
- }
-
- public async Task ExecuteAsync()
- {
- await ContextMenu.InvokeVerb("runasuser", context.SelectedItem!.ItemPath);
- }
-
- public void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
+ public RunAsAnotherUserAction() : base("runasuser")
{
- switch (e.PropertyName)
- {
- case nameof(IContentPageContext.SelectedItems):
- case nameof(IContentPageContext.Folder):
- OnPropertyChanged(nameof(IsExecutable));
- break;
- }
}
}
}
diff --git a/src/Files.App/Actions/Content/Run/RunWithPowershellAction.cs b/src/Files.App/Actions/Content/Run/RunWithPowershellAction.cs
index 85f153f6802a..9cd6c2771455 100644
--- a/src/Files.App/Actions/Content/Run/RunWithPowershellAction.cs
+++ b/src/Files.App/Actions/Content/Run/RunWithPowershellAction.cs
@@ -1,7 +1,7 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
-using Files.App.Utils.Shell;
+using Files.Shared.Helpers;
namespace Files.App.Actions
{
diff --git a/src/Files.App/Actions/Navigation/CloseOtherTabsCurrentAction.cs b/src/Files.App/Actions/Navigation/CloseOtherTabsCurrentAction.cs
index 650cf05759ba..724704f1e4d9 100644
--- a/src/Files.App/Actions/Navigation/CloseOtherTabsCurrentAction.cs
+++ b/src/Files.App/Actions/Navigation/CloseOtherTabsCurrentAction.cs
@@ -3,48 +3,24 @@
namespace Files.App.Actions
{
- internal class CloseOtherTabsCurrentAction : ObservableObject, IAction
+ internal sealed class CloseOtherTabsCurrentAction : CloseTabBaseAction
{
- private readonly IMultitaskingContext context;
-
- public string Label
+ public override string Label
=> "CloseOtherTabs".GetLocalizedResource();
- public string Description
+ public override string Description
=> "CloseOtherTabsCurrentDescription".GetLocalizedResource();
- public bool IsExecutable
- => GetIsExecutable();
-
public CloseOtherTabsCurrentAction()
{
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
}
- public Task ExecuteAsync()
+ public override Task ExecuteAsync()
{
if (context.Control is not null)
MultitaskingTabsHelpers.CloseOtherTabs(context.CurrentTabItem, context.Control);
return Task.CompletedTask;
}
-
- private bool GetIsExecutable()
- {
- return context.Control is not null && context.TabCount > 1;
- }
-
- private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
- {
- switch (e.PropertyName)
- {
- case nameof(IMultitaskingContext.Control):
- case nameof(IMultitaskingContext.TabCount):
- OnPropertyChanged(nameof(IsExecutable));
- break;
- }
- }
}
}
diff --git a/src/Files.App/Actions/Navigation/CloseOtherTabsSelectedAction.cs b/src/Files.App/Actions/Navigation/CloseOtherTabsSelectedAction.cs
index 97075fd19ccc..107ef00a4cc7 100644
--- a/src/Files.App/Actions/Navigation/CloseOtherTabsSelectedAction.cs
+++ b/src/Files.App/Actions/Navigation/CloseOtherTabsSelectedAction.cs
@@ -3,48 +3,23 @@
namespace Files.App.Actions
{
- internal class CloseOtherTabsSelectedAction : ObservableObject, IAction
+ internal sealed class CloseOtherTabsSelectedAction : CloseTabBaseAction
{
- private readonly IMultitaskingContext context;
-
- public string Label
+ public override string Label
=> "CloseOtherTabs".GetLocalizedResource();
- public string Description
+ public override string Description
=> "CloseOtherTabsSelectedDescription".GetLocalizedResource();
- public bool IsExecutable
- => GetIsExecutable();
-
public CloseOtherTabsSelectedAction()
{
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
}
- public Task ExecuteAsync()
+ public override Task ExecuteAsync()
{
- if (context.Control is not null)
- MultitaskingTabsHelpers.CloseOtherTabs(context.SelectedTabItem, context.Control);
+ MultitaskingTabsHelpers.CloseOtherTabs(context.SelectedTabItem, context.Control!);
return Task.CompletedTask;
}
-
- private bool GetIsExecutable()
- {
- return context.Control is not null && context.TabCount > 1;
- }
-
- private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
- {
- switch (e.PropertyName)
- {
- case nameof(IMultitaskingContext.Control):
- case nameof(IMultitaskingContext.TabCount):
- OnPropertyChanged(nameof(IsExecutable));
- break;
- }
- }
}
}
diff --git a/src/Files.App/Actions/Navigation/CloseSelectedTabAction.cs b/src/Files.App/Actions/Navigation/CloseSelectedTabAction.cs
index 6a43bcd4b6b4..be16115d6cf7 100644
--- a/src/Files.App/Actions/Navigation/CloseSelectedTabAction.cs
+++ b/src/Files.App/Actions/Navigation/CloseSelectedTabAction.cs
@@ -3,45 +3,43 @@
namespace Files.App.Actions
{
- internal class CloseSelectedTabAction : ObservableObject, IAction
+ internal sealed class CloseSelectedTabAction : CloseTabBaseAction
{
- private readonly IMultitaskingContext context;
-
- public string Label
+ public override string Label
=> "CloseTab".GetLocalizedResource();
- public string Description
+ public override string Description
=> "CloseSelectedTabDescription".GetLocalizedResource();
- public HotKey HotKey
+ public override HotKey HotKey
=> new(Keys.W, KeyModifiers.Ctrl);
- public HotKey SecondHotKey
+ public override HotKey SecondHotKey
=> new(Keys.F4, KeyModifiers.Ctrl);
- public RichGlyph Glyph
+ public override RichGlyph Glyph
=> new();
- public bool IsExecutable =>
- context.Control is not null &&
- context.TabCount > 0 &&
- context.CurrentTabItem is not null;
-
public CloseSelectedTabAction()
{
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
}
- public Task ExecuteAsync()
+ public override Task ExecuteAsync()
{
context.Control!.CloseTab(context.CurrentTabItem);
return Task.CompletedTask;
}
- private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
+ protected override bool GetIsExecutable()
+ {
+ return
+ context.Control is not null &&
+ context.TabCount > 0 &&
+ context.CurrentTabItem is not null;
+ }
+
+ protected override void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
diff --git a/src/Files.App/Actions/Navigation/CloseTabBaseAction.cs b/src/Files.App/Actions/Navigation/CloseTabBaseAction.cs
new file mode 100644
index 000000000000..2a0062650c64
--- /dev/null
+++ b/src/Files.App/Actions/Navigation/CloseTabBaseAction.cs
@@ -0,0 +1,51 @@
+// Copyright (c) 2023 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
+namespace Files.App.Actions
+{
+ internal abstract class CloseTabBaseAction : ObservableObject, IAction
+ {
+ protected readonly IMultitaskingContext context;
+
+ public abstract string Label { get; }
+
+ public abstract string Description { get; }
+
+ public bool IsExecutable
+ => GetIsExecutable();
+
+ public virtual HotKey HotKey
+ => HotKey.None;
+
+ public virtual HotKey SecondHotKey
+ => HotKey.None;
+
+ public virtual RichGlyph Glyph
+ => RichGlyph.None;
+
+ public CloseTabBaseAction()
+ {
+ context = Ioc.Default.GetRequiredService();
+
+ context.PropertyChanged += Context_PropertyChanged;
+ }
+
+ public abstract Task ExecuteAsync();
+
+ protected virtual bool GetIsExecutable()
+ {
+ return context.Control is not null && context.TabCount > 1;
+ }
+
+ protected virtual void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
+ {
+ switch (e.PropertyName)
+ {
+ case nameof(IMultitaskingContext.Control):
+ case nameof(IMultitaskingContext.TabCount):
+ OnPropertyChanged(nameof(IsExecutable));
+ break;
+ }
+ }
+ }
+}
diff --git a/src/Files.App/Actions/Navigation/CloseTabsToTheLeftCurrentAction.cs b/src/Files.App/Actions/Navigation/CloseTabsToTheLeftCurrentAction.cs
index 7602f9a72f37..07ae02c6aa17 100644
--- a/src/Files.App/Actions/Navigation/CloseTabsToTheLeftCurrentAction.cs
+++ b/src/Files.App/Actions/Navigation/CloseTabsToTheLeftCurrentAction.cs
@@ -3,40 +3,31 @@
namespace Files.App.Actions
{
- internal class CloseTabsToTheLeftCurrentAction : ObservableObject, IAction
+ internal sealed class CloseTabsToTheLeftCurrentAction : CloseTabBaseAction
{
- private readonly IMultitaskingContext context;
-
- public string Label
+ public override string Label
=> "CloseTabsToTheLeft".GetLocalizedResource();
- public string Description
+ public override string Description
=> "CloseTabsToTheLeftCurrentDescription".GetLocalizedResource();
- public bool IsExecutable
- => GetIsExecutable();
-
public CloseTabsToTheLeftCurrentAction()
{
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
}
- public Task ExecuteAsync()
+ public override Task ExecuteAsync()
{
- if (context.Control is not null)
- MultitaskingTabsHelpers.CloseTabsToTheLeft(context.CurrentTabItem, context.Control);
+ MultitaskingTabsHelpers.CloseTabsToTheLeft(context.CurrentTabItem, context.Control!);
return Task.CompletedTask;
}
- private bool GetIsExecutable()
+ protected override bool GetIsExecutable()
{
return context.Control is not null && context.CurrentTabIndex > 0;
}
- private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
+ protected override void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
diff --git a/src/Files.App/Actions/Navigation/CloseTabsToTheLeftSelectedAction.cs b/src/Files.App/Actions/Navigation/CloseTabsToTheLeftSelectedAction.cs
index 1c93e244cd45..d08ee12dc2a9 100644
--- a/src/Files.App/Actions/Navigation/CloseTabsToTheLeftSelectedAction.cs
+++ b/src/Files.App/Actions/Navigation/CloseTabsToTheLeftSelectedAction.cs
@@ -3,40 +3,31 @@
namespace Files.App.Actions
{
- internal class CloseTabsToTheLeftSelectedAction : ObservableObject, IAction
+ internal sealed class CloseTabsToTheLeftSelectedAction : CloseTabBaseAction
{
- private readonly IMultitaskingContext context;
-
- public string Label
+ public override string Label
=> "CloseTabsToTheLeft".GetLocalizedResource();
- public string Description
+ public override string Description
=> "CloseTabsToTheLeftSelectedDescription".GetLocalizedResource();
- public bool IsExecutable
- => GetIsExecutable();
-
public CloseTabsToTheLeftSelectedAction()
{
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
}
- public Task ExecuteAsync()
+ public override Task ExecuteAsync()
{
- if (context.Control is not null)
- MultitaskingTabsHelpers.CloseTabsToTheLeft(context.SelectedTabItem, context.Control);
+ MultitaskingTabsHelpers.CloseTabsToTheLeft(context.SelectedTabItem, context.Control!);
return Task.CompletedTask;
}
- private bool GetIsExecutable()
+ protected override bool GetIsExecutable()
{
return context.Control is not null && context.SelectedTabIndex > 0;
}
- private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
+ protected override void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
diff --git a/src/Files.App/Actions/Navigation/CloseTabsToTheRightCurrentAction.cs b/src/Files.App/Actions/Navigation/CloseTabsToTheRightCurrentAction.cs
index f0ee3cad5c1c..ff434b7f6a84 100644
--- a/src/Files.App/Actions/Navigation/CloseTabsToTheRightCurrentAction.cs
+++ b/src/Files.App/Actions/Navigation/CloseTabsToTheRightCurrentAction.cs
@@ -3,40 +3,31 @@
namespace Files.App.Actions
{
- internal class CloseTabsToTheRightCurrentAction : ObservableObject, IAction
+ internal sealed class CloseTabsToTheRightCurrentAction : CloseTabBaseAction
{
- private readonly IMultitaskingContext context;
-
- public string Label
+ public override string Label
=> "CloseTabsToTheRight".GetLocalizedResource();
- public string Description
+ public override string Description
=> "CloseTabsToTheRightCurrentDescription".GetLocalizedResource();
- public bool IsExecutable
- => GetIsExecutable();
-
public CloseTabsToTheRightCurrentAction()
{
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
}
- public Task ExecuteAsync()
+ public override Task ExecuteAsync()
{
- if (context.Control is not null)
- MultitaskingTabsHelpers.CloseTabsToTheRight(context.CurrentTabItem, context.Control);
+ MultitaskingTabsHelpers.CloseTabsToTheRight(context.CurrentTabItem, context.Control!);
return Task.CompletedTask;
}
- private bool GetIsExecutable()
+ protected override bool GetIsExecutable()
{
return context.Control is not null && context.CurrentTabIndex < context.TabCount - 1;
}
- private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
+ protected override void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
diff --git a/src/Files.App/Actions/Navigation/CloseTabsToTheRightSelectedAction.cs b/src/Files.App/Actions/Navigation/CloseTabsToTheRightSelectedAction.cs
index 4fd1c9e7dd2f..48474db4c0a3 100644
--- a/src/Files.App/Actions/Navigation/CloseTabsToTheRightSelectedAction.cs
+++ b/src/Files.App/Actions/Navigation/CloseTabsToTheRightSelectedAction.cs
@@ -3,40 +3,31 @@
namespace Files.App.Actions
{
- internal class CloseTabsToTheRightSelectedAction : ObservableObject, IAction
+ internal sealed class CloseTabsToTheRightSelectedAction : CloseTabBaseAction
{
- private readonly IMultitaskingContext context;
-
- public string Label
+ public override string Label
=> "CloseTabsToTheRight".GetLocalizedResource();
- public string Description
+ public override string Description
=> "CloseTabsToTheRightSelectedDescription".GetLocalizedResource();
- public bool IsExecutable
- => GetIsExecutable();
-
public CloseTabsToTheRightSelectedAction()
{
- context = Ioc.Default.GetRequiredService();
-
- context.PropertyChanged += Context_PropertyChanged;
}
- public Task ExecuteAsync()
+ public override Task ExecuteAsync()
{
- if (context.Control is not null)
- MultitaskingTabsHelpers.CloseTabsToTheRight(context.SelectedTabItem, context.Control);
+ MultitaskingTabsHelpers.CloseTabsToTheRight(context.SelectedTabItem, context.Control!);
return Task.CompletedTask;
}
- private bool GetIsExecutable()
+ protected override bool GetIsExecutable()
{
return context.Control is not null && context.SelectedTabIndex < context.TabCount - 1;
}
- private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
+ protected override void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
diff --git a/src/Files.App/Actions/Show/ToggleSidebarAction.cs b/src/Files.App/Actions/Show/ToggleSidebarAction.cs
deleted file mode 100644
index aea3b9a4daea..000000000000
--- a/src/Files.App/Actions/Show/ToggleSidebarAction.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2023 Files Community
-// Licensed under the MIT License. See the LICENSE.
-
-using CommunityToolkit.Mvvm.ComponentModel;
-using CommunityToolkit.Mvvm.DependencyInjection;
-using Files.App.Data.Commands;
-using Files.App.Extensions;
-using Files.App.ViewModels;
-using System.ComponentModel;
-using System.Threading.Tasks;
-
-namespace Files.App.Actions
-{
- internal class ToggleSidebarAction : ObservableObject, IToggleAction
- {
- private readonly SidebarViewModel viewModel;
-
- public string Label
- => "ToggleSidebar".GetLocalizedResource();
-
- public string Description
- => "ToggleSidebarDescription".GetLocalizedResource();
-
- public HotKey HotKey
- => new(Keys.B, KeyModifiers.Ctrl);
-
- public bool IsOn
- => viewModel.IsSidebarOpen;
-
- public ToggleSidebarAction()
- {
- viewModel = Ioc.Default.GetRequiredService();
-
- viewModel.PropertyChanged += ViewModel_PropertyChanged;
- }
-
- public Task ExecuteAsync()
- {
- viewModel.IsSidebarOpen = !IsOn;
-
- return Task.CompletedTask;
- }
-
- private void ViewModel_PropertyChanged(object? sender, PropertyChangedEventArgs e)
- {
- if (e.PropertyName is nameof(SidebarViewModel.IsSidebarOpen))
- OnPropertyChanged(nameof(IsOn));
- }
- }
-}
diff --git a/src/Files.App/App.xaml b/src/Files.App/App.xaml
index 07eebc154f40..cbf0529fb60f 100644
--- a/src/Files.App/App.xaml
+++ b/src/Files.App/App.xaml
@@ -13,9 +13,6 @@
0
-
- 32
-
@@ -34,9 +31,8 @@
-
+
-
diff --git a/src/Files.App/App.xaml.cs b/src/Files.App/App.xaml.cs
index 62fbc622b672..0005b87a43cb 100644
--- a/src/Files.App/App.xaml.cs
+++ b/src/Files.App/App.xaml.cs
@@ -11,6 +11,11 @@
using Files.App.ViewModels.Settings;
using Files.Core.Services.SizeProvider;
using Files.Core.Storage;
+#if STORE || STABLE || PREVIEW
+using Microsoft.AppCenter;
+using Microsoft.AppCenter.Analytics;
+using Microsoft.AppCenter.Crashes;
+#endif
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
@@ -340,7 +345,7 @@ await SafetyExtensions.IgnoreExceptions(async () =>
///
/// Enumerates through all tabs and gets the Path property and saves it to AppSettings.LastSessionPages.
///
- public static void SaveSessionTabs()
+ public static void SaveSessionTabs()
{
IUserSettingsService userSettingsService = Ioc.Default.GetRequiredService();
@@ -420,7 +425,7 @@ private static void AppUnhandledException(Exception? ex, bool shouldShowNotifica
Debug.WriteLine(formattedException.ToString());
- // Please check "Output Window" for exception details (View -> Output Window) (CTRL + ALT + O)
+ // Please check "Output Window" for exception details (View -> Output Window) (CTRL + ALT + O)
Debugger.Break();
SaveSessionTabs();
diff --git a/src/Files.App/Data/Commands/CommandCodes.cs b/src/Files.App/Data/Commands/CommandCodes.cs
index 61e1cf21d99b..d83a044f0f81 100644
--- a/src/Files.App/Data/Commands/CommandCodes.cs
+++ b/src/Files.App/Data/Commands/CommandCodes.cs
@@ -23,7 +23,6 @@ public enum CommandCodes
ToggleShowHiddenItems,
ToggleShowFileExtensions,
TogglePreviewPane,
- ToggleSidebar,
// File System
CopyItem,
diff --git a/src/Files.App/Data/Commands/Manager/CommandManager.cs b/src/Files.App/Data/Commands/Manager/CommandManager.cs
index c9a0cc73e873..b8467816a643 100644
--- a/src/Files.App/Data/Commands/Manager/CommandManager.cs
+++ b/src/Files.App/Data/Commands/Manager/CommandManager.cs
@@ -51,7 +51,6 @@ public IRichCommand this[HotKey hotKey]
public IRichCommand ToggleShowHiddenItems => commands[CommandCodes.ToggleShowHiddenItems];
public IRichCommand ToggleShowFileExtensions => commands[CommandCodes.ToggleShowFileExtensions];
public IRichCommand TogglePreviewPane => commands[CommandCodes.TogglePreviewPane];
- public IRichCommand ToggleSidebar => commands[CommandCodes.ToggleSidebar];
public IRichCommand SelectAll => commands[CommandCodes.SelectAll];
public IRichCommand InvertSelection => commands[CommandCodes.InvertSelection];
public IRichCommand ClearSelection => commands[CommandCodes.ClearSelection];
@@ -213,7 +212,6 @@ public CommandManager()
[CommandCodes.ToggleShowHiddenItems] = new ToggleShowHiddenItemsAction(),
[CommandCodes.ToggleShowFileExtensions] = new ToggleShowFileExtensionsAction(),
[CommandCodes.TogglePreviewPane] = new TogglePreviewPaneAction(),
- [CommandCodes.ToggleSidebar] = new ToggleSidebarAction(),
[CommandCodes.SelectAll] = new SelectAllAction(),
[CommandCodes.InvertSelection] = new InvertSelectionAction(),
[CommandCodes.ClearSelection] = new ClearSelectionAction(),
diff --git a/src/Files.App/Data/Commands/Manager/ICommandManager.cs b/src/Files.App/Data/Commands/Manager/ICommandManager.cs
index 142952cda7a5..3b73d5c257fd 100644
--- a/src/Files.App/Data/Commands/Manager/ICommandManager.cs
+++ b/src/Files.App/Data/Commands/Manager/ICommandManager.cs
@@ -25,7 +25,6 @@ public interface ICommandManager : IEnumerable
IRichCommand ToggleShowHiddenItems { get; }
IRichCommand ToggleShowFileExtensions { get; }
IRichCommand TogglePreviewPane { get; }
- IRichCommand ToggleSidebar { get; }
IRichCommand CopyItem { get; }
IRichCommand CopyPath { get; }
diff --git a/src/Files.App/Data/Contexts/Tags/TagsContext.cs b/src/Files.App/Data/Contexts/Tags/TagsContext.cs
index f43e6329de5a..6564e22a4e16 100644
--- a/src/Files.App/Data/Contexts/Tags/TagsContext.cs
+++ b/src/Files.App/Data/Contexts/Tags/TagsContext.cs
@@ -30,7 +30,7 @@ sealed class TagsContext : ITagsContext
public TagsContext()
{
FileTagsContainerViewModel.SelectedTagChanged += SelectedTagsChanged;
- SidebarControl.SelectedTagChanged += SelectedTagsChanged;
+ SidebarViewModel.SelectedTagChanged += SelectedTagsChanged;
}
private void SelectedTagsChanged(object _, SelectedTagChangedEventArgs e)
diff --git a/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs b/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
index 853e0cc3cd78..4c5753bcb44d 100644
--- a/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
+++ b/src/Files.App/Data/Factories/PropertiesNavigationViewItemFactory.cs
@@ -4,6 +4,7 @@
using Files.Core.Helpers;
using Microsoft.UI.Xaml;
using Windows.Storage;
+using Files.Shared.Helpers;
namespace Files.App.Data.Factories
{
diff --git a/src/Files.App/Data/Items/DriveItem.cs b/src/Files.App/Data/Items/DriveItem.cs
index f076c379c6d7..78b533a86d53 100644
--- a/src/Files.App/Data/Items/DriveItem.cs
+++ b/src/Files.App/Data/Items/DriveItem.cs
@@ -6,7 +6,9 @@
using Files.Core.Storage.Enums;
using Files.Core.Storage.LocatableStorage;
using Files.Core.Storage.NestedStorage;
+using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Imaging;
using Windows.Storage;
using Windows.Storage.Streams;
@@ -20,7 +22,11 @@ public class DriveItem : ObservableObject, INavigationControlItem, ILocatableFol
public BitmapImage Icon
{
get => icon;
- set => SetProperty(ref icon, value);
+ set
+ {
+ SetProperty(ref icon, value, nameof(Icon));
+ OnPropertyChanged(nameof(IconSource));
+ }
}
public byte[] IconData { get; set; }
@@ -32,8 +38,6 @@ public string Path
set => path = value;
}
- public string ToolTipText { get; private set; }
-
public string DeviceID { get; set; }
public StorageFolder Root { get; set; }
@@ -68,7 +72,10 @@ public ByteSize MaxSpace
{
if (SetProperty(ref maxSpace, value))
{
- ToolTipText = GetSizeString();
+ if (Type != DriveType.CloudDrive)
+ {
+ ToolTip = GetSizeString();
+ }
OnPropertyChanged(nameof(MaxSpaceText));
OnPropertyChanged(nameof(ShowDriveDetails));
@@ -84,7 +91,10 @@ public ByteSize FreeSpace
{
if (SetProperty(ref freeSpace, value))
{
- ToolTipText = GetSizeString();
+ if (Type != DriveType.CloudDrive)
+ {
+ ToolTip = GetSizeString();
+ }
OnPropertyChanged(nameof(FreeSpaceText));
}
@@ -107,7 +117,22 @@ public ByteSize SpaceUsed
public bool ShowDriveDetails
=> MaxSpace.Bytes > 0d;
- public DriveType Type { get; set; }
+ private DriveType type;
+ public DriveType Type
+ {
+ get => type; set
+ {
+ type = value;
+ if (value == DriveType.Network)
+ {
+ ToolTip = "Network".GetLocalizedResource();
+ }
+ else if (value == DriveType.CloudDrive)
+ {
+ ToolTip = Text;
+ }
+ }
+ }
private string text;
public string Text
@@ -152,6 +177,28 @@ public bool ShowStorageSense
public string Name => Root.DisplayName;
+ public object? Children => null;
+
+ private object toolTip = "";
+ public object ToolTip
+ {
+ get => toolTip;
+ set
+ {
+ SetProperty(ref toolTip, value);
+ }
+ }
+
+ public bool IsExpanded { get => false; set { } }
+
+ public IconSource? IconSource
+ {
+ get => new ImageIconSource()
+ {
+ ImageSource = Icon
+ };
+ }
+
public static async Task CreateFromPropertiesAsync(StorageFolder root, string deviceId, string label, DriveType type, IRandomAccessStream imageStream = null)
{
var item = new DriveItem();
@@ -255,7 +302,6 @@ public async Task LoadThumbnailAsync(bool isSidebar = false)
}
IconData ??= UIHelpers.GetSidebarIconResourceInfo(Constants.ImageRes.Folder).IconData;
}
-
Icon ??= await IconData.ToBitmapAsync();
}
diff --git a/src/Files.App/Data/Items/FileTagItem.cs b/src/Files.App/Data/Items/FileTagItem.cs
index 7b18b3f76c81..3a74b7dbbfed 100644
--- a/src/Files.App/Data/Items/FileTagItem.cs
+++ b/src/Files.App/Data/Items/FileTagItem.cs
@@ -1,11 +1,17 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
+using CommunityToolkit.WinUI.Helpers;
+using Files.App.Converters;
using Files.Core.ViewModels.FileTags;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Markup;
+using Microsoft.UI.Xaml.Media;
namespace Files.App.Data.Items
{
- public class FileTagItem : INavigationControlItem
+ public class FileTagItem : ObservableObject, INavigationControlItem
{
public string Text { get; set; }
@@ -16,7 +22,8 @@ public string Path
set
{
path = value;
- ToolTipText = Text;
+ OnPropertyChanged(nameof(IconSource));
+ OnPropertyChanged(nameof(ToolTip));
}
}
@@ -33,5 +40,20 @@ public int CompareTo(INavigationControlItem other)
=> Text.CompareTo(other.Text);
public TagViewModel FileTag { get; set; }
+
+ public object? Children => null;
+
+ public IconSource? IconSource
+ {
+ get => new PathIconSource()
+ {
+ Data = (Geometry)XamlBindingHelper.ConvertValue(typeof(Geometry), (string)Application.Current.Resources["ColorIconFilledTag"]),
+ Foreground = new SolidColorBrush(FileTag.Color.ToColor())
+ };
+ }
+
+ public object ToolTip => Text;
+
+ public bool IsExpanded { get => false; set { } }
}
}
diff --git a/src/Files.App/Data/Items/INavigationControlItem.cs b/src/Files.App/Data/Items/INavigationControlItem.cs
index 56da8d24c6ab..6d3802161eb1 100644
--- a/src/Files.App/Data/Items/INavigationControlItem.cs
+++ b/src/Files.App/Data/Items/INavigationControlItem.cs
@@ -1,18 +1,20 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
+using Files.App.UserControls.Sidebar;
+using Microsoft.UI.Xaml.Controls;
+
namespace Files.App.Data.Items
{
- public interface INavigationControlItem : IComparable
+
+ public interface INavigationControlItem : IComparable, INotifyPropertyChanged, ISidebarItemModel
{
- public string Text { get; }
+ public new string Text { get; }
public string Path { get; }
public SectionType Section { get; }
- public string ToolTipText { get; }
-
public NavigationControlItemType ItemType { get; }
public ContextMenuOptions MenuOptions { get; }
diff --git a/src/Files.App/Data/Items/ListedItem.cs b/src/Files.App/Data/Items/ListedItem.cs
index 01d3badddb8f..3da5ce0fc22e 100644
--- a/src/Files.App/Data/Items/ListedItem.cs
+++ b/src/Files.App/Data/Items/ListedItem.cs
@@ -1,14 +1,10 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
-using Files.App.Utils.Cloud;
using Files.App.ViewModels.Properties;
-using Files.Core.Helpers;
-using Files.Core.ViewModels.FileTags;
+using Files.Shared.Helpers;
using FluentFTP;
-using Microsoft.UI;
using Microsoft.UI.Xaml;
-using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using System.IO;
using System.Text;
diff --git a/src/Files.App/Data/Items/LocationItem.cs b/src/Files.App/Data/Items/LocationItem.cs
index e8bb1cce6524..8990698b5516 100644
--- a/src/Files.App/Data/Items/LocationItem.cs
+++ b/src/Files.App/Data/Items/LocationItem.cs
@@ -1,8 +1,7 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
-using CommunityToolkit.WinUI;
-using Files.App.Utils.Shell;
+using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Imaging;
using System.IO;
@@ -14,14 +13,27 @@ public class LocationItem : ObservableObject, INavigationControlItem
public BitmapImage Icon
{
get => icon;
- set => SetProperty(ref icon, value);
+ set
+ {
+ SetProperty(ref icon, value, nameof(Icon));
+ OnPropertyChanged(nameof(IconSource));
+ }
}
- //public Uri IconSource { get; set; }
-
public byte[] IconData { get; set; }
- public string Text { get; set; } = "";
+ private string text = "";
+ public string Text
+ {
+ get => text;
+ set
+ {
+ text = value;
+ // Just in case path hasn't been set
+ if (ToolTip is "")
+ ToolTip = value;
+ }
+ }
private string path;
public string Path
@@ -30,7 +42,7 @@ public string Path
set
{
path = value;
- ToolTipText = string.IsNullOrEmpty(Path) ||
+ ToolTip = string.IsNullOrEmpty(Path) ||
Path.Contains('?', StringComparison.Ordinal) ||
Path.StartsWith("shell:", StringComparison.OrdinalIgnoreCase) ||
Path.EndsWith(ShellLibraryItem.EXTENSION, StringComparison.OrdinalIgnoreCase) ||
@@ -40,14 +52,20 @@ public string Path
}
}
- public virtual string ToolTipText { get; set; }
-
public NavigationControlItemType ItemType
=> NavigationControlItemType.Location;
public bool IsDefaultLocation { get; set; }
- public BulkConcurrentObservableCollection ChildItems { get; set; }
+ public object? Children => Section == SectionType.Home ? null : ChildItems;
+ public BulkConcurrentObservableCollection? ChildItems { get; set; }
+ public IconSource? IconSource
+ {
+ get => new ImageIconSource()
+ {
+ ImageSource = icon
+ };
+ }
public bool SelectsOnInvoked { get; set; } = true;
@@ -68,6 +86,16 @@ public bool IsExpanded
public bool IsHeader { get; set; }
+ private object toolTip = "";
+ public virtual object ToolTip
+ {
+ get => toolTip;
+ set
+ {
+ SetProperty(ref toolTip, value);
+ }
+ }
+
public int CompareTo(INavigationControlItem other)
=> Text.CompareTo(other.Text);
@@ -81,7 +109,10 @@ public class RecycleBinLocationItem : LocationItem
{
public void RefreshSpaceUsed(object sender, FileSystemEventArgs e)
{
- SpaceUsed = RecycleBinHelpers.GetSize();
+ MainWindow.Instance.DispatcherQueue.TryEnqueue(() =>
+ {
+ SpaceUsed = RecycleBinHelpers.GetSize();
+ });
}
private ulong spaceUsed;
@@ -90,14 +121,15 @@ public ulong SpaceUsed
get => spaceUsed;
set
{
- SetProperty(ref spaceUsed, value);
-
- MainWindow.Instance.DispatcherQueue.EnqueueOrInvokeAsync(() => OnPropertyChanged(nameof(ToolTipText)));
+ if (SetProperty(ref spaceUsed, value))
+ OnPropertyChanged(nameof(ToolTip));
}
}
- public override string ToolTipText
- => SpaceUsed.ToSizeString();
+ public override object ToolTip
+ {
+ get => SpaceUsed.ToSizeString();
+ }
public RecycleBinLocationItem()
{
diff --git a/src/Files.App/Data/Items/WslDistroItem.cs b/src/Files.App/Data/Items/WslDistroItem.cs
index 2be4fd90d89e..6f373323d9df 100644
--- a/src/Files.App/Data/Items/WslDistroItem.cs
+++ b/src/Files.App/Data/Items/WslDistroItem.cs
@@ -1,9 +1,11 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
+using Microsoft.UI.Xaml.Controls;
+
namespace Files.App.Data.Items
{
- public class WslDistroItem : INavigationControlItem
+ public class WslDistroItem : ObservableObject, INavigationControlItem
{
public string Text { get; set; }
@@ -14,21 +16,51 @@ public string Path
set
{
path = value;
- ToolTipText = Path.Contains('?', StringComparison.Ordinal) ? Text : Path;
+ ToolTip = Path.Contains('?', StringComparison.Ordinal) ? Text : Path;
}
}
- public string ToolTipText { get; private set; }
-
public NavigationControlItemType ItemType
=> NavigationControlItemType.LinuxDistro;
- public Uri Logo { get; set; }
+ private Uri icon;
+ public Uri Icon
+ {
+ get => icon;
+ set
+ {
+ SetProperty(ref icon, value, nameof(Icon));
+ OnPropertyChanged(nameof(IconSource));
+ }
+ }
public SectionType Section { get; set; }
public ContextMenuOptions MenuOptions { get; set; }
+ public object? Children => null;
+
+ private object toolTip = "";
+ public object ToolTip
+ {
+ get => toolTip;
+ set
+ {
+ SetProperty(ref toolTip, value);
+ }
+ }
+
+ public bool IsExpanded { get => false; set { } }
+
+ public IconSource? IconSource
+ {
+ get => new BitmapIconSource()
+ {
+ UriSource = icon,
+ ShowAsMonochrome = false,
+ };
+ }
+
public int CompareTo(INavigationControlItem other) => Text.CompareTo(other.Text);
}
}
diff --git a/src/Files.App/Data/Models/ItemViewModel.cs b/src/Files.App/Data/Models/ItemViewModel.cs
index 0fbd16382b0a..6de883a990b0 100644
--- a/src/Files.App/Data/Models/ItemViewModel.cs
+++ b/src/Files.App/Data/Models/ItemViewModel.cs
@@ -3,6 +3,7 @@
using Files.App.ViewModels.Previews;
using Files.Core.Services.SizeProvider;
+using Files.Shared.Helpers;
using LibGit2Sharp;
using Microsoft.Extensions.Logging;
using Microsoft.UI.Xaml.Data;
diff --git a/src/Files.App/Data/Models/SelectedItemsPropertiesViewModel.cs b/src/Files.App/Data/Models/SelectedItemsPropertiesViewModel.cs
index 4338dec67433..3dc8693ab0f0 100644
--- a/src/Files.App/Data/Models/SelectedItemsPropertiesViewModel.cs
+++ b/src/Files.App/Data/Models/SelectedItemsPropertiesViewModel.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT License. See the LICENSE.
using Files.App.ViewModels.Properties;
+using Files.Shared.Helpers;
namespace Files.App.Data.Models
{
diff --git a/src/Files.App/Data/Models/SidebarPinnedModel.cs b/src/Files.App/Data/Models/SidebarPinnedModel.cs
index 15e8f26c2a55..f4fde71fe99f 100644
--- a/src/Files.App/Data/Models/SidebarPinnedModel.cs
+++ b/src/Files.App/Data/Models/SidebarPinnedModel.cs
@@ -1,9 +1,6 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
-using CommunityToolkit.WinUI;
-using Files.App.Data.Items;
-using Files.App.Services;
using Files.App.UserControls.Widgets;
using System.Collections.Specialized;
using System.IO;
diff --git a/src/Files.App/Dialogs/FileTooLargeDialog.xaml b/src/Files.App/Dialogs/FileTooLargeDialog.xaml
new file mode 100644
index 000000000000..827187926bee
--- /dev/null
+++ b/src/Files.App/Dialogs/FileTooLargeDialog.xaml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Files.App/Dialogs/FileTooLargeDialog.xaml.cs b/src/Files.App/Dialogs/FileTooLargeDialog.xaml.cs
new file mode 100644
index 000000000000..40a659b4b4b7
--- /dev/null
+++ b/src/Files.App/Dialogs/FileTooLargeDialog.xaml.cs
@@ -0,0 +1,35 @@
+// Copyright (c) 2023 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
+using Microsoft.UI.Xaml.Controls;
+
+namespace Files.App.Dialogs
+{
+ public sealed partial class FileTooLargeDialog : ContentDialog, IDialog
+ {
+ public FileTooLargeDialogViewModel ViewModel
+ {
+ get => (FileTooLargeDialogViewModel)DataContext;
+ set => DataContext = value;
+ }
+
+ public FileTooLargeDialog()
+ {
+ InitializeComponent();
+ }
+
+ public new async Task ShowAsync()
+ {
+ return (DialogResult)await SetContentDialogRoot(this).TryShowAsync();
+ }
+
+ // WINUI3
+ private ContentDialog SetContentDialogRoot(ContentDialog contentDialog)
+ {
+ if (Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
+ contentDialog.XamlRoot = MainWindow.Instance.Content.XamlRoot;
+
+ return contentDialog;
+ }
+ }
+}
diff --git a/src/Files.App/Dialogs/ReorderSidebarItemsDialog.xaml b/src/Files.App/Dialogs/ReorderSidebarItemsDialog.xaml
index 084ad270b8cc..61a6129be386 100644
--- a/src/Files.App/Dialogs/ReorderSidebarItemsDialog.xaml
+++ b/src/Files.App/Dialogs/ReorderSidebarItemsDialog.xaml
@@ -30,7 +30,7 @@
DragStarting="ListViewItem_DragStarting"
Drop="ListViewItem_Drop"
Tag="{x:Bind Path}"
- ToolTipService.ToolTip="{x:Bind ToolTipText, Mode=OneWay}">
+ ToolTipService.ToolTip="{x:Bind ToolTip, Mode=OneWay}">
diff --git a/src/Files.App/Files.App.csproj b/src/Files.App/Files.App.csproj
index 5e923acac12f..75b752a72284 100644
--- a/src/Files.App/Files.App.csproj
+++ b/src/Files.App/Files.App.csproj
@@ -68,6 +68,11 @@
+
+
+
+
+
@@ -77,7 +82,7 @@
-
+
@@ -91,10 +96,10 @@
-
+
-
-
+
+
@@ -130,4 +135,13 @@
+
+
+ $(DefaultXamlRuntime)
+
+
+ MSBuild:Compile
+
+
+
diff --git a/src/Files.App/Helpers/MenuFlyout/ContextFlyoutItemHelper.cs b/src/Files.App/Helpers/MenuFlyout/ContextFlyoutItemHelper.cs
index aff373b7f986..f1f47994a8b6 100644
--- a/src/Files.App/Helpers/MenuFlyout/ContextFlyoutItemHelper.cs
+++ b/src/Files.App/Helpers/MenuFlyout/ContextFlyoutItemHelper.cs
@@ -1,8 +1,11 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
-using Files.App.Data.Commands;
using Files.App.ViewModels.LayoutModes;
+using Files.Shared.Helpers;
+using Files.App.Helpers.ContextFlyouts;
+using Files.App.ViewModels.LayoutModes;
+using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Imaging;
using System.IO;
using Windows.Storage;
@@ -75,7 +78,7 @@ public static List GetBaseItemMenuItems(
SelectedItemsPropertiesViewModel? selectedItemsPropertiesViewModel,
List selectedItems,
CurrentInstanceViewModel currentInstanceViewModel,
- ItemViewModel itemViewModel = null)
+ ItemViewModel? itemViewModel = null)
{
bool itemsSelected = itemViewModel is null;
bool canDecompress = selectedItems.Any() && selectedItems.All(x => x.IsArchive)
@@ -89,6 +92,8 @@ public static List GetBaseItemMenuItems(
Path.GetFileName(selectedItems.Count is 1 ? selectedItems[0].ItemPath : Path.GetDirectoryName(selectedItems[0].ItemPath))
?? string.Empty;
+ bool isDriveRoot = itemViewModel?.CurrentFolder is not null && (itemViewModel.CurrentFolder.ItemPath == Path.GetPathRoot(itemViewModel.CurrentFolder.ItemPath));
+
return new List()
{
new ContextMenuFlyoutItemViewModel()
@@ -541,6 +546,22 @@ public static List GetBaseItemMenuItems(
ShowItem = itemsSelected && userSettingsService.GeneralSettingsService.ShowSendToMenu
},
new ContextMenuFlyoutItemViewModel()
+ {
+ Text = "TurnOnBitLocker".GetLocalizedResource(),
+ Tag = "TurnOnBitLockerPlaceholder",
+ CollapseLabel = true,
+ IsEnabled = false,
+ ShowItem = isDriveRoot
+ },
+ new ContextMenuFlyoutItemViewModel()
+ {
+ Text = "ManageBitLocker".GetLocalizedResource(),
+ Tag = "ManageBitLockerPlaceholder",
+ CollapseLabel = true,
+ ShowItem = isDriveRoot,
+ IsEnabled = false
+ },
+ new ContextMenuFlyoutItemViewModel()
{
ItemType = ContextMenuFlyoutItemType.Separator,
Tag = "OverflowSeparator",
@@ -616,5 +637,23 @@ public static List GetNewItemItems(BaseLayoutVie
return list;
}
+
+ public static void SwapPlaceholderWithShellOption(CommandBarFlyout contextMenu, string placeholderName, ContextMenuFlyoutItemViewModel? replacingItem, int position)
+ {
+ var placeholder = contextMenu.SecondaryCommands
+ .Where(x => Equals((x as AppBarButton)?.Tag, placeholderName))
+ .FirstOrDefault() as AppBarButton;
+ if (placeholder is not null)
+ placeholder.Visibility = Microsoft.UI.Xaml.Visibility.Collapsed;
+
+ if (replacingItem is not null)
+ {
+ var (_, bitLockerCommands) = ItemModelListToContextFlyoutHelper.GetAppBarItemsFromModel(new List() { replacingItem });
+ contextMenu.SecondaryCommands.Insert(
+ position,
+ bitLockerCommands.FirstOrDefault()
+ );
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Files.App/Helpers/MenuFlyout/ShellContextMenuHelper.cs b/src/Files.App/Helpers/MenuFlyout/ShellContextMenuHelper.cs
index 7cc9c758814b..06c36a3f3643 100644
--- a/src/Files.App/Helpers/MenuFlyout/ShellContextMenuHelper.cs
+++ b/src/Files.App/Helpers/MenuFlyout/ShellContextMenuHelper.cs
@@ -1,28 +1,14 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
-using CommunityToolkit.Mvvm.DependencyInjection;
-using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.WinUI.UI;
-using Files.App.Data.Items;
-using Files.App.Extensions;
using Files.App.Helpers.ContextFlyouts;
-using Files.App.Utils.Shell;
-using Files.App.ViewModels;
-using Files.Core.Helpers;
-using Files.Core.Services.Settings;
-using Files.Shared;
-using Files.Shared.Extensions;
+using Files.Shared.Helpers;
using Microsoft.UI.Input;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Imaging;
-using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
using Vanara.PInvoke;
using Windows.System;
using Windows.UI.Core;
@@ -119,7 +105,7 @@ private static void LoadMenuFlyoutItem(IList men
break;
// Avoid duplicate separators
- if ((menuFlyoutItem.Type == MenuItemType.MFT_SEPARATOR) && (menuItemsListLocal.FirstOrDefault().ItemType == ContextMenuFlyoutItemType.Separator))
+ if ((menuFlyoutItem.Type == MenuItemType.MFT_SEPARATOR) && (menuItemsListLocal.FirstOrDefault()?.ItemType == ContextMenuFlyoutItemType.Separator))
continue;
BitmapImage? image = null;
@@ -174,7 +160,7 @@ private static void LoadMenuFlyoutItem(IList men
Text = menuFlyoutItem.Label.Replace("&", "", StringComparison.Ordinal),
Tag = menuFlyoutItem,
BitmapIcon = image,
- Command = new RelayCommand
@@ -108,82 +124,91 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -275,22 +300,22 @@
-
-
-
-
-
-
+
-
-
+
+
+
+
+
+
+
-
+
diff --git a/src/Files.App/Views/MainPage.xaml.cs b/src/Files.App/Views/MainPage.xaml.cs
index 3e4bb22d91e0..c066284102b8 100644
--- a/src/Files.App/Views/MainPage.xaml.cs
+++ b/src/Files.App/Views/MainPage.xaml.cs
@@ -4,6 +4,11 @@
using CommunityToolkit.WinUI.Helpers;
using CommunityToolkit.WinUI.UI;
using CommunityToolkit.WinUI.UI.Controls;
+using Files.App.Data.Items;
+using Files.App.Data.Models;
+using Files.App.UserControls.MultitaskingControl;
+using Files.App.UserControls.Sidebar;
+using Files.Core.Extensions;
using Files.App.UserControls.MultitaskingControl;
using Microsoft.Extensions.Logging;
using Microsoft.UI.Dispatching;
@@ -13,6 +18,7 @@
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Navigation;
using System.Runtime.CompilerServices;
+using Vanara.Extensions.Reflection;
using Windows.ApplicationModel;
using Windows.Services.Store;
using Windows.Storage;
@@ -51,6 +57,7 @@ public MainPage()
Commands = Ioc.Default.GetRequiredService();
WindowContext = Ioc.Default.GetRequiredService();
SidebarAdaptiveViewModel = Ioc.Default.GetRequiredService();
+ SidebarAdaptiveViewModel.PaneFlyout = (MenuFlyout)Resources["SidebarContextMenu"];
ViewModel = Ioc.Default.GetRequiredService();
OngoingTasksViewModel = Ioc.Default.GetRequiredService();
@@ -198,11 +205,6 @@ private void UpdateNavToolbarProperties()
protected override void OnNavigatedTo(NavigationEventArgs e)
{
ViewModel.OnNavigatedTo(e);
-
- SidebarControl.SidebarItemInvoked += SidebarControl_SidebarItemInvoked;
- SidebarControl.SidebarItemPropertiesInvoked += SidebarControl_SidebarItemPropertiesInvoked;
- SidebarControl.SidebarItemDropped += SidebarControl_SidebarItemDropped;
- SidebarControl.SidebarItemNewPaneInvoked += SidebarControl_SidebarItemNewPaneInvoked;
}
protected override async void OnPreviewKeyDown(KeyRoutedEventArgs e)
@@ -263,103 +265,6 @@ protected override void OnLostFocus(RoutedEventArgs e)
keyReleased = true;
}
- private async void SidebarControl_SidebarItemDropped(object sender, SidebarItemDroppedEventArgs e)
- {
- await SidebarAdaptiveViewModel.FilesystemHelpers.PerformOperationTypeAsync(e.AcceptedOperation, e.Package, e.ItemPath, false, true);
- e.SignalEvent?.Set();
- }
-
- private void SidebarControl_SidebarItemPropertiesInvoked(object sender, SidebarItemPropertiesInvokedEventArgs e)
- {
- if (e.InvokedItemDataContext is DriveItem)
- FilePropertiesHelpers.OpenPropertiesWindow(e.InvokedItemDataContext, SidebarAdaptiveViewModel.PaneHolder.ActivePane);
- else if (e.InvokedItemDataContext is LibraryLocationItem library)
- FilePropertiesHelpers.OpenPropertiesWindow(new LibraryItem(library), SidebarAdaptiveViewModel.PaneHolder.ActivePane);
- else if (e.InvokedItemDataContext is LocationItem locationItem)
- {
- ListedItem listedItem = new ListedItem(null!)
- {
- ItemPath = locationItem.Path,
- ItemNameRaw = locationItem.Text,
- PrimaryItemAttribute = StorageItemTypes.Folder,
- ItemType = "Folder".GetLocalizedResource(),
- };
-
- FilePropertiesHelpers.OpenPropertiesWindow(listedItem, SidebarAdaptiveViewModel.PaneHolder.ActivePane);
- }
- }
-
- private void SidebarControl_SidebarItemNewPaneInvoked(object sender, SidebarItemNewPaneInvokedEventArgs e)
- {
- if (e.InvokedItemDataContext is INavigationControlItem navItem)
- SidebarAdaptiveViewModel.PaneHolder.OpenPathInNewPane(navItem.Path);
- }
-
- private void SidebarControl_SidebarItemInvoked(object sender, SidebarItemInvokedEventArgs e)
- {
- var invokedItemContainer = e.InvokedItemContainer;
-
- // Path to navigate
- string? navigationPath;
-
- // Type of page to navigate
- Type? sourcePageType = null;
-
- switch ((invokedItemContainer.DataContext as INavigationControlItem)?.ItemType)
- {
- case NavigationControlItemType.Location:
- {
- // Get the path of the invoked item
- var ItemPath = (invokedItemContainer.DataContext as INavigationControlItem)?.Path;
-
- // Section item
- if (string.IsNullOrEmpty(ItemPath))
- {
- navigationPath = invokedItemContainer.Tag?.ToString();
- }
- // Home item
- else if (ItemPath.Equals("Home", StringComparison.OrdinalIgnoreCase))
- {
- if (ItemPath.Equals(SidebarAdaptiveViewModel.SidebarSelectedItem?.Path, StringComparison.OrdinalIgnoreCase))
- return; // return if already selected
-
- navigationPath = "Home";
- sourcePageType = typeof(HomePage);
- }
- // Any other item
- else
- {
- navigationPath = invokedItemContainer.Tag?.ToString();
- }
- break;
- }
-
- case NavigationControlItemType.FileTag:
- var tagPath = (invokedItemContainer.DataContext as INavigationControlItem)?.Path; // Get the path of the invoked item
- if (SidebarAdaptiveViewModel.PaneHolder?.ActivePane is IShellPage shp)
- {
- shp.NavigateToPath(tagPath, new NavigationArguments()
- {
- IsSearchResultPage = true,
- SearchPathParam = "Home",
- SearchQuery = tagPath,
- AssociatedTabInstance = shp,
- NavPathParam = tagPath
- });
- }
- return;
-
- default:
- {
- navigationPath = invokedItemContainer.Tag?.ToString();
- break;
- }
- }
-
- if (SidebarAdaptiveViewModel.PaneHolder?.ActivePane is IShellPage shellPage)
- shellPage.NavigateToPath(navigationPath, sourcePageType);
- }
-
private void Page_Loaded(object sender, RoutedEventArgs e)
{
// Defers the status bar loading until after the page has loaded to improve startup perf
@@ -554,5 +459,13 @@ private void PaneSplitter_ManipulationStarted(object sender, ManipulationStarted
this.ChangeCursor(InputSystemCursor.Create(PaneSplitter.GripperCursor == GridSplitter.GripperCursorType.SizeWestEast ?
InputSystemCursorShape.SizeWestEast : InputSystemCursorShape.SizeNorthSouth));
}
+
+ private void TogglePaneButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (SidebarControl.DisplayMode == SidebarDisplayMode.Minimal)
+ {
+ SidebarControl.IsPaneOpen = !SidebarControl.IsPaneOpen;
+ }
+ }
}
}
diff --git a/src/Files.App/Views/PaneHolderPage.xaml b/src/Files.App/Views/PaneHolderPage.xaml
index bef476c41261..4b43ddbbb335 100644
--- a/src/Files.App/Views/PaneHolderPage.xaml
+++ b/src/Files.App/Views/PaneHolderPage.xaml
@@ -122,7 +122,7 @@
+ Value="{ThemeResource DividerStrokeColorDefault}" />
+ Value="{ThemeResource DividerStrokeColorDefault}" />
diff --git a/src/Files.App/Views/Properties/SecurityAdvancedPage.xaml b/src/Files.App/Views/Properties/SecurityAdvancedPage.xaml
index bd52485001f7..9eb1a74d6ad6 100644
--- a/src/Files.App/Views/Properties/SecurityAdvancedPage.xaml
+++ b/src/Files.App/Views/Properties/SecurityAdvancedPage.xaml
@@ -242,7 +242,7 @@
Height="32"
Margin="0,4"
Padding="32,0,0,4"
- BorderBrush="{ThemeResource ControlStrokeColorDefault}"
+ BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
BorderThickness="0,0,0,1">
diff --git a/src/Files.Core.Storage/Extensions/StorageExtensions.Storable.cs b/src/Files.Core.Storage/Extensions/StorageExtensions.Storable.cs
index 18d8fff10a86..405bb2f27afe 100644
--- a/src/Files.Core.Storage/Extensions/StorageExtensions.Storable.cs
+++ b/src/Files.Core.Storage/Extensions/StorageExtensions.Storable.cs
@@ -11,10 +11,10 @@ public static partial class StorageExtensions
/// Tries to obtain path from the storable.
///
/// The storable item to get the path from.
- /// A path pointing to the item, otherwise null.
- public static string? TryGetPath(this IStorable storable)
+ /// A path pointing to the item.
+ public static string TryGetPath(this IStorable storable)
{
- return (storable as ILocatableStorable)?.Path;
+ return (storable as ILocatableStorable)?.Path ?? storable.Id;
}
}
}
\ No newline at end of file
diff --git a/src/Files.Core/Data/Enums/CopyEngineResult.cs b/src/Files.Core/Data/Enums/CopyEngineResult.cs
index 149693b05311..93516e727c63 100644
--- a/src/Files.Core/Data/Enums/CopyEngineResult.cs
+++ b/src/Files.Core/Data/Enums/CopyEngineResult.cs
@@ -36,7 +36,7 @@ public struct CopyEngineResult
public const int COPYENGINE_E_ALREADY_EXISTS_SYSTEM = -2144927701;
public const int COPYENGINE_E_ALREADY_EXISTS_FOLDER = -2144927700;
// File too big
- //public const int COPYENGINE_E_FILE_TOO_LARGE = -2144927731;
+ public const int COPYENGINE_E_FILE_TOO_LARGE = -2144927731;
//public const int COPYENGINE_E_REMOVABLE_FULL = -2144927730;
//public const int COPYENGINE_E_DISK_FULL = -2144927694;
//public const int COPYENGINE_E_DISK_FULL_CLEAN = -2144927693;
@@ -78,6 +78,7 @@ public static FileSystemStatusCode Convert(int? hres)
CopyEngineResult.COPYENGINE_E_ALREADY_EXISTS_READONLY => FileSystemStatusCode.AlreadyExists,
CopyEngineResult.COPYENGINE_E_ALREADY_EXISTS_SYSTEM => FileSystemStatusCode.AlreadyExists,
CopyEngineResult.COPYENGINE_E_ALREADY_EXISTS_FOLDER => FileSystemStatusCode.AlreadyExists,
+ CopyEngineResult.COPYENGINE_E_FILE_TOO_LARGE => FileSystemStatusCode.FileTooLarge,
CopyEngineResult.COPYENGINE_E_FILE_IS_FLD_DEST => FileSystemStatusCode.NotAFile,
CopyEngineResult.COPYENGINE_E_FLD_IS_FILE_DEST => FileSystemStatusCode.NotAFolder,
CopyEngineResult.COPYENGINE_E_SHARING_VIOLATION_SRC => FileSystemStatusCode.InUse,
diff --git a/src/Files.Core/Data/Enums/FileSystemStatusCode.cs b/src/Files.Core/Data/Enums/FileSystemStatusCode.cs
index 65899fcadc28..17ae1cbc0cb6 100644
--- a/src/Files.Core/Data/Enums/FileSystemStatusCode.cs
+++ b/src/Files.Core/Data/Enums/FileSystemStatusCode.cs
@@ -64,6 +64,11 @@ public enum FileSystemStatusCode
///
/// InProgress
///
- InProgress = 1024
+ InProgress = 1024,
+
+ ///
+ /// FileTooLarge
+ ///
+ FileTooLarge = 2048
}
}
diff --git a/src/Files.Core/Helpers/PathHelpers.cs b/src/Files.Core/Helpers/PathHelpers.cs
deleted file mode 100644
index 057c45f9b288..000000000000
--- a/src/Files.Core/Helpers/PathHelpers.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2023 Files Community
-// Licensed under the MIT License. See the LICENSE.
-
-using System.IO;
-
-namespace Files.Core.Helpers
-{
- public static class PathHelpers
- {
- public static string FormatName(string path)
- {
- string fileName;
- string rootPath = Path.GetPathRoot(path) ?? string.Empty;
-
- if (rootPath == path && path.StartsWith(@"\\"))
- {
- // Network Share path
- fileName = path.Substring(path.LastIndexOf(@"\", StringComparison.Ordinal) + 1);
- }
- else if (rootPath == path)
- {
- // Drive path
- fileName = path;
- }
- else
- {
- // Standard file name
- fileName = Path.GetFileName(path);
- }
-
- // Check for link file name
- if (FileExtensionHelpers.IsShortcutOrUrlFile(fileName))
- fileName = fileName.Remove(fileName.Length - 4);
-
- return fileName;
- }
- }
-}
diff --git a/src/Files.Core/ViewModels/Dialogs/FileTooLargeDialogViewModel.cs b/src/Files.Core/ViewModels/Dialogs/FileTooLargeDialogViewModel.cs
new file mode 100644
index 000000000000..137295726db8
--- /dev/null
+++ b/src/Files.Core/ViewModels/Dialogs/FileTooLargeDialogViewModel.cs
@@ -0,0 +1,15 @@
+// Copyright (c) 2023 Files Community
+// Licensed under the MIT License. See the LICENSE.
+
+namespace Files.Core.ViewModels.Dialogs
+{
+ public sealed class FileTooLargeDialogViewModel: ObservableObject
+ {
+ public IEnumerable Paths { get; private set; }
+
+ public FileTooLargeDialogViewModel(IEnumerable paths)
+ {
+ Paths = paths;
+ }
+ }
+}
diff --git a/src/Files.Core/ViewModels/Widgets/FileTagsWidget/FileTagsItemViewModel.cs b/src/Files.Core/ViewModels/Widgets/FileTagsWidget/FileTagsItemViewModel.cs
index 0a4058a68690..8a4f163ffa36 100644
--- a/src/Files.Core/ViewModels/Widgets/FileTagsWidget/FileTagsItemViewModel.cs
+++ b/src/Files.Core/ViewModels/Widgets/FileTagsWidget/FileTagsItemViewModel.cs
@@ -3,6 +3,7 @@
using Files.Core.Storage;
using Files.Core.Storage.Extensions;
+using Files.Shared.Helpers;
namespace Files.Core.ViewModels.Widgets.FileTagsWidget
{
diff --git a/src/Files.Core/Helpers/FileExtensionHelpers.cs b/src/Files.Shared/Helpers/FileExtensionHelpers.cs
similarity index 99%
rename from src/Files.Core/Helpers/FileExtensionHelpers.cs
rename to src/Files.Shared/Helpers/FileExtensionHelpers.cs
index f33470e59241..233b5f1f98fb 100644
--- a/src/Files.Core/Helpers/FileExtensionHelpers.cs
+++ b/src/Files.Shared/Helpers/FileExtensionHelpers.cs
@@ -1,7 +1,10 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
-namespace Files.Core.Helpers
+using System;
+using System.Linq;
+
+namespace Files.Shared.Helpers
{
///
/// Provides static extension for path extension.
diff --git a/src/Files.Shared/Helpers/PathHelpers.cs b/src/Files.Shared/Helpers/PathHelpers.cs
index d23d5c837ef3..97d6e675692e 100644
--- a/src/Files.Shared/Helpers/PathHelpers.cs
+++ b/src/Files.Shared/Helpers/PathHelpers.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.
+using System;
using System.IO;
namespace Files.Shared.Helpers
@@ -14,5 +15,53 @@ public static string Combine(string folder, string name)
return folder.Contains('/') ? Path.Combine(folder, name).Replace('\\', '/') : Path.Combine(folder, name);
}
+
+ public static string FormatName(string path)
+ {
+ string fileName;
+ string rootPath = Path.GetPathRoot(path) ?? string.Empty;
+
+ if (rootPath == path && path.StartsWith(@"\\"))
+ {
+ // Network Share path
+ fileName = path.Substring(path.LastIndexOf(@"\", StringComparison.Ordinal) + 1);
+ }
+ else if (rootPath == path)
+ {
+ // Drive path
+ fileName = path;
+ }
+ else
+ {
+ // Standard file name
+ fileName = Path.GetFileName(path);
+ }
+
+ // Check for link file name
+ if (FileExtensionHelpers.IsShortcutOrUrlFile(fileName))
+ fileName = fileName.Remove(fileName.Length - 4);
+
+ return fileName;
+ }
+
+ ///
+ /// Determines whether the points to any special system folders.
+ ///
+ ///
+ /// The term "Special folder" refers to any folders that may be natively supported by a certain platform (e.g. Libraries).
+ ///
+ /// The path to a folder to check.
+ /// If the path points to a special folder, returns true; otherwise false.
+ public static bool IsSpecialFolder(string path)
+ {
+ foreach (Environment.SpecialFolder specialFolder in Enum.GetValues(typeof(Environment.SpecialFolder)))
+ {
+ var specialFolderPath = Environment.GetFolderPath(specialFolder);
+ if (string.Equals(specialFolderPath, path, StringComparison.OrdinalIgnoreCase))
+ return true;
+ }
+
+ return false;
+ }
}
}