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 d3a73c6e140d..000000000000 --- a/src/Files.App/Actions/Content/Archives/DecompressArchive.cs +++ /dev/null @@ -1,67 +0,0 @@ -// 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 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/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 5bd841d8a4c5..451988dd06f7 100644 --- a/src/Files.App/Actions/Content/Run/RunAsAdminAction.cs +++ b/src/Files.App/Actions/Content/Run/RunAsAdminAction.cs @@ -5,46 +5,19 @@ 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 4832eeb2005f..b42ee8008d7d 100644 --- a/src/Files.App/Actions/Content/Run/RunAsAnotherUserAction.cs +++ b/src/Files.App/Actions/Content/Run/RunAsAnotherUserAction.cs @@ -5,46 +5,19 @@ 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/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) {