Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Fixed issue where opening and closing modals quickly may lead to a crash #11928

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/Files.App/Actions/BaseUIAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Files.App.Helpers;
using System.ComponentModel;
using System.Threading.Tasks;

namespace Files.App.Actions
{
internal abstract class BaseUIAction : ObservableObject, IAction
{
public abstract string Label { get; }

public abstract string Description { get; }

public virtual bool IsExecutable => UIHelpers.CanShowDialog;

public BaseUIAction()
{
UIHelpers.PropertyChanged += UIHelpers_PropertyChanged;
}

public abstract Task ExecuteAsync();

private void UIHelpers_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName is nameof(UIHelpers.CanShowDialog))
OnPropertyChanged(nameof(IsExecutable));
}
}
}
22 changes: 12 additions & 10 deletions src/Files.App/Actions/Content/Archives/CompressIntoArchiveAction.cs
Original file line number Diff line number Diff line change
@@ -1,42 +1,44 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.DependencyInjection;
using Files.App.Contexts;
using Files.App.Dialogs;
using Files.App.Extensions;
using Files.App.Filesystem.Archive;
using Files.App.Helpers;
using Microsoft.UI.Xaml.Controls;
using System.ComponentModel;
using System.Threading.Tasks;

namespace Files.App.Actions
{
internal class CompressIntoArchiveAction : ObservableObject, IAction
internal class CompressIntoArchiveAction : BaseUIAction
{
private readonly IContentPageContext context = Ioc.Default.GetRequiredService<IContentPageContext>();

public string Label => "CreateArchive".GetLocalizedResource();
public override string Label => "CreateArchive".GetLocalizedResource();

public string Description => "TODO: Need to be described.";
public override string Description => "TODO: Need to be described.";

public bool IsExecutable => IsContextPageTypeAdaptedToCommand()
&& ArchiveHelpers.CanCompress(context.SelectedItems);
public override bool IsExecutable =>
IsContextPageTypeAdaptedToCommand() &&
ArchiveHelpers.CanCompress(context.SelectedItems) &&
UIHelpers.CanShowDialog;

public CompressIntoArchiveAction()
{
context.PropertyChanged += Context_PropertyChanged;
}

public async Task ExecuteAsync()
public override async Task ExecuteAsync()
{
var (sources, directory, fileName) = ArchiveHelpers.GetCompressDestination(context.ShellPage);

var dialog = new CreateArchiveDialog
{
FileName = fileName,
};
await dialog.ShowAsync();
var result = await dialog.TryShowAsync();

if (!dialog.CanCreate)
if (!dialog.CanCreate || result != ContentDialogResult.Primary)
return;

IArchiveCreator creator = new ArchiveCreator
Expand Down
17 changes: 9 additions & 8 deletions src/Files.App/Actions/Content/Archives/DecompressArchive.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.DependencyInjection;
using Files.App.Commands;
using Files.App.Contexts;
using Files.App.Extensions;
Expand All @@ -9,25 +8,27 @@

namespace Files.App.Actions
{
internal class DecompressArchive : ObservableObject, IAction
internal class DecompressArchive : BaseUIAction
{
private readonly IContentPageContext context = Ioc.Default.GetRequiredService<IContentPageContext>();

public string Label => "ExtractFiles".GetLocalizedResource();
public override string Label => "ExtractFiles".GetLocalizedResource();

public string Description => "TODO: Need to be described.";
public override string Description => "TODO: Need to be described.";

public HotKey HotKey { get; } = new(Keys.E, KeyModifiers.Ctrl);

public bool IsExecutable => IsContextPageTypeAdaptedToCommand()
&& ArchiveHelpers.CanDecompress(context.SelectedItems);
public override bool IsExecutable =>
IsContextPageTypeAdaptedToCommand() &&
ArchiveHelpers.CanDecompress(context.SelectedItems) &&
UIHelpers.CanShowDialog;

public DecompressArchive()
{
context.PropertyChanged += Context_PropertyChanged;
}

public async Task ExecuteAsync()
public override async Task ExecuteAsync()
{
await ArchiveHelpers.DecompressArchive(context.ShellPage);
}
Expand Down
17 changes: 9 additions & 8 deletions src/Files.App/Actions/Content/Archives/DecompressArchiveHere.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.DependencyInjection;
using Files.App.Contexts;
using Files.App.Extensions;
using Files.App.Helpers;
Expand All @@ -8,23 +7,25 @@

namespace Files.App.Actions
{
internal class DecompressArchiveHere : ObservableObject, IAction
internal class DecompressArchiveHere : BaseUIAction
{
private readonly IContentPageContext context = Ioc.Default.GetRequiredService<IContentPageContext>();

public string Label => "ExtractHere".GetLocalizedResource();
public override string Label => "ExtractHere".GetLocalizedResource();

public string Description => "TODO: Need to be described.";
public override string Description => "TODO: Need to be described.";

public bool IsExecutable => IsContextPageTypeAdaptedToCommand()
&& ArchiveHelpers.CanDecompress(context.SelectedItems);
public override bool IsExecutable =>
IsContextPageTypeAdaptedToCommand() &&
ArchiveHelpers.CanDecompress(context.SelectedItems) &&
UIHelpers.CanShowDialog;

public DecompressArchiveHere()
{
context.PropertyChanged += Context_PropertyChanged;
}

public async Task ExecuteAsync()
public override async Task ExecuteAsync()
{
await ArchiveHelpers.DecompressArchiveHere(context.ShellPage);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.DependencyInjection;
using Files.App.Contexts;
using Files.App.Extensions;
using Files.App.Helpers;
Expand All @@ -10,23 +9,25 @@

namespace Files.App.Actions
{
internal class DecompressArchiveToChildFolderAction : ObservableObject, IAction
internal class DecompressArchiveToChildFolderAction : BaseUIAction
{
private readonly IContentPageContext context = Ioc.Default.GetRequiredService<IContentPageContext>();

public string Label => ComputeLabel();
public override string Label => ComputeLabel();

public string Description => "TODO: Need to be described.";
public override string Description => "TODO: Need to be described.";

public bool IsExecutable => IsContextPageTypeAdaptedToCommand()
&& ArchiveHelpers.CanDecompress(context.SelectedItems);
public override bool IsExecutable =>
IsContextPageTypeAdaptedToCommand() &&
ArchiveHelpers.CanDecompress(context.SelectedItems) &&
UIHelpers.CanShowDialog;

public DecompressArchiveToChildFolderAction()
{
context.PropertyChanged += Context_PropertyChanged;
}

public async Task ExecuteAsync()
public override async Task ExecuteAsync()
{
await ArchiveHelpers.DecompressArchiveToChildFolder(context.ShellPage);
}
Expand Down
13 changes: 6 additions & 7 deletions src/Files.App/Actions/FileSystem/CreateFolderAction.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.DependencyInjection;
using Files.App.Commands;
using Files.App.Contexts;
using Files.App.Extensions;
Expand All @@ -10,24 +9,24 @@

namespace Files.App.Actions
{
internal class CreateFolderAction : ObservableObject, IAction
internal class CreateFolderAction : BaseUIAction
{
private readonly IContentPageContext context = Ioc.Default.GetRequiredService<IContentPageContext>();

public string Label { get; } = "Folder".GetLocalizedResource();
public override string Label { get; } = "Folder".GetLocalizedResource();

public string Description => "TODO: Need to be described.";
public override string Description => "TODO: Need to be described.";

public RichGlyph Glyph { get; } = new RichGlyph(baseGlyph: "\uE8B7");

public bool IsExecutable => context.ShellPage is not null;
public override bool IsExecutable => context.ShellPage is not null && UIHelpers.CanShowDialog;

public CreateFolderAction()
{
context.PropertyChanged += Context_PropertyChanged;
}

public Task ExecuteAsync()
public override Task ExecuteAsync()
{
if (context.ShellPage is not null)
UIFilesystemHelpers.CreateFileFromDialogResultType(AddItemDialogItemType.Folder, null!, context.ShellPage);
Expand Down
13 changes: 6 additions & 7 deletions src/Files.App/Actions/FileSystem/CreateShortcutAction.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.DependencyInjection;
using Files.App.Commands;
using Files.App.Contexts;
using Files.App.Extensions;
Expand All @@ -11,24 +10,24 @@

namespace Files.App.Actions
{
internal class CreateShortcutAction : ObservableObject, IAction
internal class CreateShortcutAction : BaseUIAction
{
private readonly IContentPageContext context = Ioc.Default.GetRequiredService<IContentPageContext>();

public string Label { get; } = "CreateShortcut".GetLocalizedResource();
public override string Label { get; } = "CreateShortcut".GetLocalizedResource();

public string Description => "TODO: Need to be described.";
public override string Description => "TODO: Need to be described.";

public RichGlyph Glyph { get; } = new RichGlyph(opacityStyle: "ColorIconShortcut");

public bool IsExecutable => context.HasSelection;
public override bool IsExecutable => context.HasSelection && UIHelpers.CanShowDialog;

public CreateShortcutAction()
{
context.PropertyChanged += Context_PropertyChanged;
}

public async Task ExecuteAsync()
public override async Task ExecuteAsync()
{
var currentPath = context.ShellPage?.FilesystemViewModel.WorkingDirectory;

Expand Down
28 changes: 20 additions & 8 deletions src/Files.App/Actions/FileSystem/CreateShortcutFromDialogAction.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,39 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.DependencyInjection;
using Files.App.Commands;
using Files.App.Contexts;
using Files.App.Extensions;
using Files.App.Helpers;
using System.ComponentModel;
using System.Threading.Tasks;

namespace Files.App.Actions
{
internal class CreateShortcutFromDialogAction : ObservableObject, IAction
internal class CreateShortcutFromDialogAction : BaseUIAction
{
private readonly IContentPageContext context = Ioc.Default.GetRequiredService<IContentPageContext>();

public string Label { get; } = "Shortcut".GetLocalizedResource();
public override string Label { get; } = "Shortcut".GetLocalizedResource();

public string Description => "TODO: Need to be described.";
public override string Description => "TODO: Need to be described.";

public RichGlyph Glyph { get; } = new RichGlyph(opacityStyle: "ColorIconShortcut");

public async Task ExecuteAsync()
public override bool IsExecutable => context.ShellPage is not null && UIHelpers.CanShowDialog;

public CreateShortcutFromDialogAction()
{
context.PropertyChanged += Context_PropertyChanged;
}

public override async Task ExecuteAsync()
{
await UIFilesystemHelpers.CreateShortcutFromDialogAsync(context.ShellPage);
}

private void Context_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (context.ShellPage is not null)
await UIFilesystemHelpers.CreateShortcutFromDialogAsync(context.ShellPage);
if (e.PropertyName is nameof(IContentPageContext.ShellPage))
OnPropertyChanged(nameof(IsExecutable));
}
}
}
16 changes: 8 additions & 8 deletions src/Files.App/Actions/FileSystem/DeleteItemAction.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.DependencyInjection;
using Files.App.Commands;
using Files.App.Contexts;
using Files.App.Extensions;
Expand All @@ -13,29 +12,30 @@

namespace Files.App.Actions
{
internal class DeleteItemAction : ObservableObject, IAction
internal class DeleteItemAction : BaseUIAction
{
private readonly IContentPageContext context = Ioc.Default.GetRequiredService<IContentPageContext>();
private readonly IFoldersSettingsService settings = Ioc.Default.GetRequiredService<IFoldersSettingsService>();

public string Label { get; } = "Delete".GetLocalizedResource();
public override string Label { get; } = "Delete".GetLocalizedResource();

public string Description => "TODO: Need to be described.";
public override string Description => "TODO: Need to be described.";

public RichGlyph Glyph { get; } = new RichGlyph(opacityStyle: "ColorIconDelete");

public HotKey HotKey { get; } = new(Keys.Delete);

public bool IsExecutable =>
public override bool IsExecutable =>
context.HasSelection &&
(!context.ShellPage?.SlimContentPage?.IsRenamingItem ?? false);
(!context.ShellPage?.SlimContentPage?.IsRenamingItem ?? false) &&
UIHelpers.CanShowDialog;

public DeleteItemAction()
{
context.PropertyChanged += Context_PropertyChanged;
}

public async Task ExecuteAsync()
public override async Task ExecuteAsync()
{
if (context.ShellPage is null || !IsExecutable)
return;
Expand Down