Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/Files.App/Actions/IAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Threading.Tasks;

namespace Files.App.Actions
{
public interface IAction
{
string Label { get; }

bool IsExecutable => true;

Task ExecuteAsync();
}
}
7 changes: 7 additions & 0 deletions src/Files.App/Actions/IToggleAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Files.App.Actions
{
public interface IToggleAction : IAction
{
bool IsOn { get; }
}
}
32 changes: 32 additions & 0 deletions src/Files.App/Actions/Show/ShowFileExtensionsAction.cs
Original file line number Diff line number Diff line change
@@ -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<IFoldersSettingsService>();

public string Label => "ShowFileExtensions".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));
}
}
}
32 changes: 32 additions & 0 deletions src/Files.App/Actions/Show/ShowHiddenItemsAction.cs
Original file line number Diff line number Diff line change
@@ -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<IFoldersSettingsService>();

public string Label => "ShowHiddenItems".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));
}
}
}
4 changes: 3 additions & 1 deletion src/Files.App/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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; }

/// <summary>
Expand Down Expand Up @@ -129,6 +130,7 @@ private IServiceProvider ConfigureServices()
.AddSingleton<ILocalizationService, LocalizationService>()
.AddSingleton<ICloudDetector, CloudDetector>()
.AddSingleton<IFileTagsService, FileTagsService>()
.AddSingleton<ICommandManager, CommandManager>()
#if UWP
.AddSingleton<IStorageService, WindowsStorageService>()
#else
Expand Down
11 changes: 11 additions & 0 deletions src/Files.App/Commands/CommandCodes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Files.App.Commands
{
public enum CommandCodes
{
None,

// show
ShowHiddenItems,
ShowFileExtensions,
}
}
22 changes: 22 additions & 0 deletions src/Files.App/Commands/IRichCommand.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
155 changes: 155 additions & 0 deletions src/Files.App/Commands/Manager/CommandManager.cs
Original file line number Diff line number Diff line change
@@ -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<CommandCodes, IRichCommand> commands = new Dictionary<CommandCodes, IRichCommand>
{
[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<IRichCommand> 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 { add {} remove {} }
public event PropertyChangingEventHandler? PropertyChanging { add { } remove { } }
public event PropertyChangedEventHandler? PropertyChanged { add { } remove { } }

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;
}
}
}
}
}
14 changes: 14 additions & 0 deletions src/Files.App/Commands/Manager/ICommandManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Collections.Generic;

namespace Files.App.Commands
{
public interface ICommandManager : IEnumerable<IRichCommand>
{
IRichCommand this[CommandCodes code] { get; }

IRichCommand None { get; }

IRichCommand ShowHiddenItems { get; }
IRichCommand ShowFileExtensions { get; }
}
}
18 changes: 6 additions & 12 deletions src/Files.App/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -1293,12 +1293,6 @@
<data name="NavToolbarTiles.ToolTipService.ToolTip" xml:space="preserve">
<value>Tiles (Ctrl+Shift+2)</value>
</data>
<data name="NavToolbarShowFileExtensionsHeader.Text" xml:space="preserve">
<value>Show file extensions</value>
</data>
<data name="NavToolbarShowHiddenItems.AutomationProperties.Name" xml:space="preserve">
<value>Show hidden items</value>
</data>
<data name="DateDeleted" xml:space="preserve">
<value>Date deleted</value>
</data>
Expand Down Expand Up @@ -2310,12 +2304,6 @@
<data name="Tiles" xml:space="preserve">
<value>Tiles</value>
</data>
<data name="NavToolbarShowFileExtensions.AutomationProperties.Name" xml:space="preserve">
<value>Show file extensions</value>
</data>
<data name="NavToolbarShowHiddenItemsHeader.Text" xml:space="preserve">
<value>Show hidden items</value>
</data>
<data name="SettingsOpenFoldersNewTabToggleSwitch.AutomationProperties.Name" xml:space="preserve">
<value>Open folders in new tab</value>
</data>
Expand Down Expand Up @@ -2958,4 +2946,10 @@
<data name="ContextMenuOptions" xml:space="preserve">
<value>Context menu options</value>
</data>
<data name="ShowFileExtensions" xml:space="preserve">
<value>Show file extensions</value>
</data>
<data name="ShowHiddenItems" xml:space="preserve">
<value>Show hidden items</value>
</data>
</root>
12 changes: 6 additions & 6 deletions src/Files.App/UserControls/InnerNavigationToolbar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -807,26 +807,26 @@
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
Text="{helpers:ResourceString Name=NavToolbarShowHiddenItemsHeader/Text}" />
Text="{x:Bind CommandManager.ShowHiddenItems.Label}" />
<ToggleSwitch
Grid.Row="0"
Grid.Column="1"
HorizontalAlignment="Right"
AutomationProperties.Name="{helpers:ResourceString Name=NavToolbarShowHiddenItems/AutomationProperties/Name}"
IsOn="{x:Bind UserSettingsService.FoldersSettingsService.ShowHiddenItems, Mode=TwoWay}"
AutomationProperties.Name="{x:Bind CommandManager.ShowHiddenItems.Label}"
IsOn="{x:Bind CommandManager.ShowHiddenItems.IsOn, Mode=TwoWay}"
Style="{StaticResource RightAlignedToggleSwitchStyle}" />

<TextBlock
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Text="{helpers:ResourceString Name=NavToolbarShowFileExtensionsHeader/Text}" />
Text="{x:Bind CommandManager.ShowFileExtensions.Label}" />
<ToggleSwitch
Grid.Row="1"
Grid.Column="1"
HorizontalAlignment="Right"
AutomationProperties.Name="{helpers:ResourceString Name=NavToolbarShowFileExtensions/AutomationProperties/Name}"
IsOn="{x:Bind UserSettingsService.FoldersSettingsService.ShowFileExtensions, Mode=TwoWay}"
AutomationProperties.Name="{x:Bind CommandManager.ShowFileExtensions.Label}"
IsOn="{x:Bind CommandManager.ShowFileExtensions.IsOn, Mode=TwoWay}"
Rotation="1"
Style="{StaticResource RightAlignedToggleSwitchStyle}" />
</Grid>
Expand Down
Loading