From d838895bdaa7df6d247b37dd10d0d51b70b3ae4b Mon Sep 17 00:00:00 2001 From: cinqmilleans Date: Thu, 16 Feb 2023 16:06:19 +0100 Subject: [PATCH 1/3] manager --- src/Files.App/Actions/IAction.cs | 13 ++ src/Files.App/Actions/IToggleAction.cs | 7 + .../Actions/Show/ShowFileExtensionsAction.cs | 32 ++++ .../Actions/Show/ShowHiddenItemsAction.cs | 32 ++++ src/Files.App/App.xaml.cs | 4 +- src/Files.App/Commands/CommandCodes.cs | 11 ++ src/Files.App/Commands/IRichCommand.cs | 22 +++ .../Commands/Manager/CommandManager.cs | 155 ++++++++++++++++++ .../Commands/Manager/ICommandManager.cs | 14 ++ 9 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 src/Files.App/Actions/IAction.cs create mode 100644 src/Files.App/Actions/IToggleAction.cs create mode 100644 src/Files.App/Actions/Show/ShowFileExtensionsAction.cs create mode 100644 src/Files.App/Actions/Show/ShowHiddenItemsAction.cs create mode 100644 src/Files.App/Commands/CommandCodes.cs create mode 100644 src/Files.App/Commands/IRichCommand.cs create mode 100644 src/Files.App/Commands/Manager/CommandManager.cs create mode 100644 src/Files.App/Commands/Manager/ICommandManager.cs diff --git a/src/Files.App/Actions/IAction.cs b/src/Files.App/Actions/IAction.cs new file mode 100644 index 000000000000..2f2a3d3ee0fc --- /dev/null +++ b/src/Files.App/Actions/IAction.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; + +namespace Files.App.Actions +{ + public interface IAction + { + string Label { get; } + + bool IsExecutable => true; + + Task ExecuteAsync(); + } +} diff --git a/src/Files.App/Actions/IToggleAction.cs b/src/Files.App/Actions/IToggleAction.cs new file mode 100644 index 000000000000..f048e6fd0960 --- /dev/null +++ b/src/Files.App/Actions/IToggleAction.cs @@ -0,0 +1,7 @@ +namespace Files.App.Actions +{ + public interface IToggleAction : IAction + { + bool IsOn { get; } + } +} diff --git a/src/Files.App/Actions/Show/ShowFileExtensionsAction.cs b/src/Files.App/Actions/Show/ShowFileExtensionsAction.cs new file mode 100644 index 000000000000..d3f8cea54e1c --- /dev/null +++ b/src/Files.App/Actions/Show/ShowFileExtensionsAction.cs @@ -0,0 +1,32 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.DependencyInjection; +using Files.App.Extensions; +using Files.Backend.Services.Settings; +using System.ComponentModel; +using System.Threading.Tasks; + +namespace Files.App.Actions +{ + internal class ShowFileExtensionsAction : ObservableObject, IToggleAction + { + private readonly IFoldersSettingsService settings = Ioc.Default.GetRequiredService(); + + public string Label => "NavToolbarShowFileExtensionsHeader/Text".GetLocalizedResource(); + + public bool IsOn => settings.ShowFileExtensions; + + public ShowFileExtensionsAction() => settings.PropertyChanged += Settings_PropertyChanged; + + public Task ExecuteAsync() + { + settings.ShowFileExtensions = !settings.ShowFileExtensions; + return Task.CompletedTask; + } + + private void Settings_PropertyChanged(object? _, PropertyChangedEventArgs e) + { + if (e.PropertyName is nameof(IFoldersSettingsService.ShowFileExtensions)) + OnPropertyChanged(nameof(IsOn)); + } + } +} diff --git a/src/Files.App/Actions/Show/ShowHiddenItemsAction.cs b/src/Files.App/Actions/Show/ShowHiddenItemsAction.cs new file mode 100644 index 000000000000..40c01a0c70a5 --- /dev/null +++ b/src/Files.App/Actions/Show/ShowHiddenItemsAction.cs @@ -0,0 +1,32 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.DependencyInjection; +using Files.App.Extensions; +using Files.Backend.Services.Settings; +using System.ComponentModel; +using System.Threading.Tasks; + +namespace Files.App.Actions +{ + internal class ShowHiddenItemsAction : ObservableObject, IToggleAction + { + private readonly IFoldersSettingsService settings = Ioc.Default.GetRequiredService(); + + public string Label => "NavToolbarShowHiddenItemsHeader/Text".GetLocalizedResource(); + + public bool IsOn => settings.ShowHiddenItems; + + public ShowHiddenItemsAction() => settings.PropertyChanged += Settings_PropertyChanged; + + public Task ExecuteAsync() + { + settings.ShowHiddenItems = !settings.ShowHiddenItems; + return Task.CompletedTask; + } + + private void Settings_PropertyChanged(object? _, PropertyChangedEventArgs e) + { + if (e.PropertyName is nameof(IFoldersSettingsService.ShowHiddenItems)) + OnPropertyChanged(nameof(IsOn)); + } + } +} diff --git a/src/Files.App/App.xaml.cs b/src/Files.App/App.xaml.cs index baef7548d023..5d72b1655d6b 100644 --- a/src/Files.App/App.xaml.cs +++ b/src/Files.App/App.xaml.cs @@ -2,6 +2,7 @@ using CommunityToolkit.WinUI; using CommunityToolkit.WinUI.Helpers; using CommunityToolkit.WinUI.Notifications; +using Files.App.Commands; using Files.App.DataModels; using Files.App.Extensions; using Files.App.Filesystem; @@ -78,7 +79,7 @@ public partial class App : Application public static string AppVersion = $"{Package.Current.Id.Version.Major}.{Package.Current.Id.Version.Minor}.{Package.Current.Id.Version.Build}.{Package.Current.Id.Version.Revision}"; public static string LogoPath; - + public IServiceProvider Services { get; private set; } /// @@ -129,6 +130,7 @@ private IServiceProvider ConfigureServices() .AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton() #if UWP .AddSingleton() #else diff --git a/src/Files.App/Commands/CommandCodes.cs b/src/Files.App/Commands/CommandCodes.cs new file mode 100644 index 000000000000..3fd91442bbc7 --- /dev/null +++ b/src/Files.App/Commands/CommandCodes.cs @@ -0,0 +1,11 @@ +namespace Files.App.Commands +{ + public enum CommandCodes + { + None, + + // show + ShowHiddenItems, + ShowFileExtensions, + } +} diff --git a/src/Files.App/Commands/IRichCommand.cs b/src/Files.App/Commands/IRichCommand.cs new file mode 100644 index 000000000000..4cae03a9a767 --- /dev/null +++ b/src/Files.App/Commands/IRichCommand.cs @@ -0,0 +1,22 @@ +using Microsoft.UI.Xaml.Input; +using System.ComponentModel; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace Files.App.Commands +{ + public interface IRichCommand : ICommand, INotifyPropertyChanging, INotifyPropertyChanged + { + CommandCodes Code { get; } + + string Label { get; } + + bool IsToggle { get; } + bool IsOn { get; set; } + bool IsExecutable { get; } + + Task ExecuteAsync(); + + void ExecuteTapped(object sender, TappedRoutedEventArgs e); + } +} diff --git a/src/Files.App/Commands/Manager/CommandManager.cs b/src/Files.App/Commands/Manager/CommandManager.cs new file mode 100644 index 000000000000..9ec8824f7b79 --- /dev/null +++ b/src/Files.App/Commands/Manager/CommandManager.cs @@ -0,0 +1,155 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using Files.App.Actions; +using Microsoft.UI.Xaml.Input; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace Files.App.Commands +{ + internal class CommandManager : ICommandManager + { + private readonly IDictionary commands = new Dictionary + { + [CommandCodes.None] = new NoneCommand(), + }; + + public IRichCommand this[CommandCodes code] => GetCommand(code); + + public IRichCommand None => GetCommand(CommandCodes.None); + public IRichCommand ShowHiddenItems => GetCommand(CommandCodes.ShowHiddenItems); + public IRichCommand ShowFileExtensions => GetCommand(CommandCodes.ShowFileExtensions); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() => commands.Values.GetEnumerator(); + + private IRichCommand GetCommand(CommandCodes code) + { + if (commands.TryGetValue(code, out IRichCommand? command)) + return command; + + var action = GetAction(code); + var newCommand = new ActionCommand(code, action); + commands.Add(code, newCommand); + + return newCommand; + } + + private static IAction GetAction(CommandCodes code) => code switch + { + CommandCodes.ShowHiddenItems => new ShowHiddenItemsAction(), + CommandCodes.ShowFileExtensions => new ShowFileExtensionsAction(), + _ => throw new ArgumentOutOfRangeException(nameof(code)), + }; + + [DebuggerDisplay("Command None")] + private class NoneCommand : IRichCommand + { + public event EventHandler? CanExecuteChanged; + public event PropertyChangingEventHandler? PropertyChanging; + public event PropertyChangedEventHandler? PropertyChanged; + + public CommandCodes Code => CommandCodes.None; + + public string Label => string.Empty; + + public bool IsToggle => false; + public bool IsOn { get => false; set {} } + public bool IsExecutable => false; + + public bool CanExecute(object? _) => false; + public void Execute(object? _) {} + public Task ExecuteAsync() => Task.CompletedTask; + public void ExecuteTapped(object _, TappedRoutedEventArgs e) {} + } + + [DebuggerDisplay("Command {Code}")] + private class ActionCommand : ObservableObject, IRichCommand + { + public event EventHandler? CanExecuteChanged; + + private readonly IAction action; + private readonly ICommand command; + + public CommandCodes Code { get; } + + public string Label => action.Label; + + public bool IsToggle => action is IToggleAction; + + public bool IsOn + { + get => action is IToggleAction toggleAction && toggleAction.IsOn; + set + { + if (action is IToggleAction toggleAction && toggleAction.IsOn != value) + command.Execute(null); + } + } + + public bool IsExecutable => action.IsExecutable; + + public ActionCommand(CommandCodes code, IAction action) + { + Code = code; + this.action = action; + + command = new AsyncRelayCommand(ExecuteAsync, () => action.IsExecutable); + + if (action is INotifyPropertyChanging notifyPropertyChanging) + notifyPropertyChanging.PropertyChanging += Action_PropertyChanging; + if (action is INotifyPropertyChanged notifyPropertyChanged) + notifyPropertyChanged.PropertyChanged += Action_PropertyChanged; + } + + public bool CanExecute(object? parameter) => command.CanExecute(parameter); + public void Execute(object? parameter) => command.Execute(parameter); + + public Task ExecuteAsync() + { + if (IsExecutable) + return action.ExecuteAsync(); + return Task.CompletedTask; + } + + public async void ExecuteTapped(object _, TappedRoutedEventArgs e) => await action.ExecuteAsync(); + + private void Action_PropertyChanging(object? _, PropertyChangingEventArgs e) + { + switch (e.PropertyName) + { + case nameof(IAction.Label): + OnPropertyChanging(nameof(Label)); + break; + case nameof(IToggleAction.IsOn) when IsToggle: + OnPropertyChanging(nameof(IsOn)); + break; + case nameof(IAction.IsExecutable): + OnPropertyChanging(nameof(IsExecutable)); + break; + } + } + private void Action_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + switch (e.PropertyName) + { + case nameof(IAction.Label): + OnPropertyChanged(nameof(Label)); + break; + case nameof(IToggleAction.IsOn) when IsToggle: + OnPropertyChanged(nameof(IsOn)); + break; + case nameof(IAction.IsExecutable): + OnPropertyChanged(nameof(IsExecutable)); + CanExecuteChanged?.Invoke(this, EventArgs.Empty); + break; + } + } + } + } +} diff --git a/src/Files.App/Commands/Manager/ICommandManager.cs b/src/Files.App/Commands/Manager/ICommandManager.cs new file mode 100644 index 000000000000..b33c1bba7615 --- /dev/null +++ b/src/Files.App/Commands/Manager/ICommandManager.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Files.App.Commands +{ + public interface ICommandManager : IEnumerable + { + IRichCommand this[CommandCodes code] { get; } + + IRichCommand None { get; } + + IRichCommand ShowHiddenItems { get; } + IRichCommand ShowFileExtensions { get; } + } +} From 82e5a612f3c5735224b98053ddb39ff3ba21273f Mon Sep 17 00:00:00 2001 From: cinqmilleans Date: Thu, 16 Feb 2023 17:11:46 +0100 Subject: [PATCH 2/3] ui --- .../Actions/Show/ShowFileExtensionsAction.cs | 2 +- .../Actions/Show/ShowHiddenItemsAction.cs | 2 +- .../Commands/Manager/CommandManager.cs | 6 +- src/Files.App/Strings/en-US/Resources.resw | 72 +++++++++---------- .../UserControls/InnerNavigationToolbar.xaml | 12 ++-- .../InnerNavigationToolbar.xaml.cs | 2 + 6 files changed, 46 insertions(+), 50 deletions(-) diff --git a/src/Files.App/Actions/Show/ShowFileExtensionsAction.cs b/src/Files.App/Actions/Show/ShowFileExtensionsAction.cs index d3f8cea54e1c..a5aa4c86fa71 100644 --- a/src/Files.App/Actions/Show/ShowFileExtensionsAction.cs +++ b/src/Files.App/Actions/Show/ShowFileExtensionsAction.cs @@ -11,7 +11,7 @@ internal class ShowFileExtensionsAction : ObservableObject, IToggleAction { private readonly IFoldersSettingsService settings = Ioc.Default.GetRequiredService(); - public string Label => "NavToolbarShowFileExtensionsHeader/Text".GetLocalizedResource(); + public string Label => "ShowFileExtensions".GetLocalizedResource(); public bool IsOn => settings.ShowFileExtensions; diff --git a/src/Files.App/Actions/Show/ShowHiddenItemsAction.cs b/src/Files.App/Actions/Show/ShowHiddenItemsAction.cs index 40c01a0c70a5..3df1ec3dbb66 100644 --- a/src/Files.App/Actions/Show/ShowHiddenItemsAction.cs +++ b/src/Files.App/Actions/Show/ShowHiddenItemsAction.cs @@ -11,7 +11,7 @@ internal class ShowHiddenItemsAction : ObservableObject, IToggleAction { private readonly IFoldersSettingsService settings = Ioc.Default.GetRequiredService(); - public string Label => "NavToolbarShowHiddenItemsHeader/Text".GetLocalizedResource(); + public string Label => "ShowHiddenItems".GetLocalizedResource(); public bool IsOn => settings.ShowHiddenItems; diff --git a/src/Files.App/Commands/Manager/CommandManager.cs b/src/Files.App/Commands/Manager/CommandManager.cs index 9ec8824f7b79..6dad5cd8f529 100644 --- a/src/Files.App/Commands/Manager/CommandManager.cs +++ b/src/Files.App/Commands/Manager/CommandManager.cs @@ -50,9 +50,9 @@ private IRichCommand GetCommand(CommandCodes code) [DebuggerDisplay("Command None")] private class NoneCommand : IRichCommand { - public event EventHandler? CanExecuteChanged; - public event PropertyChangingEventHandler? PropertyChanging; - public event PropertyChangedEventHandler? PropertyChanged; + public event EventHandler? CanExecuteChanged { add {} remove {} } + public event PropertyChangingEventHandler? PropertyChanging { add { } remove { } } + public event PropertyChangedEventHandler? PropertyChanged { add { } remove { } } public CommandCodes Code => CommandCodes.None; diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw index 50a272619625..5f15dcb54c05 100644 --- a/src/Files.App/Strings/en-US/Resources.resw +++ b/src/Files.App/Strings/en-US/Resources.resw @@ -1,17 +1,17 @@  - @@ -1293,12 +1293,6 @@ Tiles (Ctrl+Shift+2) - - Show file extensions - - - Show hidden items - Date deleted @@ -2310,12 +2304,6 @@ Tiles - - Show file extensions - - - Show hidden items - Open folders in new tab @@ -2958,4 +2946,10 @@ Context menu options + + Show file extensions + + + Show hidden items + \ No newline at end of file diff --git a/src/Files.App/UserControls/InnerNavigationToolbar.xaml b/src/Files.App/UserControls/InnerNavigationToolbar.xaml index c8ee2aad1680..83754f84947f 100644 --- a/src/Files.App/UserControls/InnerNavigationToolbar.xaml +++ b/src/Files.App/UserControls/InnerNavigationToolbar.xaml @@ -807,26 +807,26 @@ Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" - Text="{helpers:ResourceString Name=NavToolbarShowHiddenItemsHeader/Text}" /> + Text="{x:Bind CommandManager.ShowHiddenItems.Label}" /> + Text="{x:Bind CommandManager.ShowFileExtensions.Label}" /> diff --git a/src/Files.App/UserControls/InnerNavigationToolbar.xaml.cs b/src/Files.App/UserControls/InnerNavigationToolbar.xaml.cs index 8a48ba10f62b..1bbdb4f8161d 100644 --- a/src/Files.App/UserControls/InnerNavigationToolbar.xaml.cs +++ b/src/Files.App/UserControls/InnerNavigationToolbar.xaml.cs @@ -1,4 +1,5 @@ using CommunityToolkit.Mvvm.DependencyInjection; +using Files.App.Commands; using Files.App.DataModels; using Files.App.ViewModels; using Files.Backend.Services; @@ -24,6 +25,7 @@ public InnerNavigationToolbar() } public IUserSettingsService UserSettingsService { get; } = Ioc.Default.GetRequiredService(); + public ICommandManager CommandManager { get; } = Ioc.Default.GetRequiredService(); private readonly IAddItemService addItemService = Ioc.Default.GetRequiredService(); From f3a509c024b6966925be5708058053f8c39a7e3d Mon Sep 17 00:00:00 2001 From: cinqmilleans Date: Fri, 17 Feb 2023 16:37:06 +0100 Subject: [PATCH 3/3] fix spacing --- src/Files.App/Strings/en-US/Resources.resw | 54 +++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw index 5f15dcb54c05..889e71a13826 100644 --- a/src/Files.App/Strings/en-US/Resources.resw +++ b/src/Files.App/Strings/en-US/Resources.resw @@ -1,17 +1,17 @@  -