Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public sealed partial class FilterCacheModal : ModalBase<bool>

[Inject] private IDispatcher Dispatcher { get; init; } = null!;

[Inject] private IFilePickerService FilePickerService { get; init; } = null!;

[Inject] private IFileSaveService FileSaveService { get; init; } = null!;

[Inject] private IState<FilterCacheState> FilterCacheState { get; init; } = null!;
Expand All @@ -45,23 +47,15 @@ await AlertDialogService.ShowAlert("Export Failed",

protected override async Task OnImportAsync()
{
PickOptions options = new()
try
{
PickerTitle = "Please select a json file to import",
FileTypes = new FilePickerFileType(
new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.WinUI, [".json"] }
})
};

var result = await FilePicker.Default.PickAsync(options);
var path = await FilePickerService.PickAsync(
"Please select a json file to import",
FilePickerServiceFileTypes.Json);

if (result is null) { return; }
if (path is null) { return; }

try
{
await using var stream = File.OpenRead(result.FullPath);
await using var stream = File.OpenRead(path);
var filters = await JsonSerializer.DeserializeAsync<List<string>>(stream);

if (filters is null) { return; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public sealed partial class FilterGroup

[Inject] private IDispatcher Dispatcher { get; init; } = null!;

[Inject] private IFilePickerService FilePickerService { get; init; } = null!;

[Inject] private IFileSaveService FileSaveService { get; init; } = null!;

protected override void OnParametersSet()
Expand Down Expand Up @@ -110,20 +112,15 @@ private void HandlePendingSave(FilterDraftModel draft, FilterModel filter)

private async Task ImportGroup()
{
PickOptions options = new()
try
{
PickerTitle = "Please select a json file to import",
FileTypes = new FilePickerFileType(
new Dictionary<DevicePlatform, IEnumerable<string>> { { DevicePlatform.WinUI, [".json"] } })
};

var result = await FilePicker.Default.PickAsync(options);
var path = await FilePickerService.PickAsync(
"Please select a json file to import",
FilePickerServiceFileTypes.Json);

if (result is null) { return; }
if (path is null) { return; }

try
{
await using var stream = File.OpenRead(result.FullPath);
await using var stream = File.OpenRead(path);
var group = await JsonSerializer.DeserializeAsync<FilterGroupModel>(stream);

if (group is null) { return; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public sealed partial class FilterGroupModal : ModalBase<bool>

[Inject] private IDispatcher Dispatcher { get; init; } = null!;

[Inject] private IFilePickerService FilePickerService { get; init; } = null!;

[Inject] private IFileSaveService FileSaveService { get; init; } = null!;

[Inject] private IState<FilterGroupState> FilterGroupState { get; init; } = null!;
Expand All @@ -43,20 +45,15 @@ await AlertDialogService.ShowAlert("Export Failed",

protected override async Task OnImportAsync()
{
PickOptions options = new()
try
{
PickerTitle = "Please select a json file to import",
FileTypes = new FilePickerFileType(
new Dictionary<DevicePlatform, IEnumerable<string>> { { DevicePlatform.WinUI, [".json"] } })
};

var result = await FilePicker.Default.PickAsync(options);
var path = await FilePickerService.PickAsync(
"Please select a json file to import",
FilePickerServiceFileTypes.Json);

if (result is null) { return; }
if (path is null) { return; }

try
{
await using var stream = File.OpenRead(result.FullPath);
await using var stream = File.OpenRead(path);
var groups = await JsonSerializer.DeserializeAsync<List<FilterGroupModel>>(stream);

if (groups is null) { return; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public sealed partial class SettingsModal : ModalBase<bool>

[Inject] private IState<EventLogState> EventLogState { get; init; } = null!;

[Inject] private IFilePickerService FilePickerService { get; init; } = null!;

[Inject] private ILogReloadCoordinator LogReloadCoordinator { get; init; } = null!;

private bool IsClassificationPending => !DatabaseService.InitialClassificationTask.IsCompleted;
Expand Down Expand Up @@ -192,26 +194,13 @@ private bool GetEffectiveEnabled(DatabaseEntry entry) =>

private async Task ImportDatabase()
{
PickOptions options = new()
{
PickerTitle = "Please select a database file",
FileTypes = new FilePickerFileType(
new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.WinUI, [".db", ".zip"] }
})
};

try
{
var result = (await FilePicker.Default.PickMultipleAsync(options)).ToArray();

if (result.Length <= 0) { return; }
var sourcePaths = await FilePickerService.PickMultipleAsync(
"Please select database files to import",
FilePickerServiceFileTypes.Database);

var sourcePaths = result
.Where(item => item is not null && !string.IsNullOrEmpty(item.FullPath))
.Select(item => item!.FullPath)
.ToList();
if (sourcePaths.Count == 0) { return; }

var skipFileNames = await ResolveImportConflictsAsync(sourcePaths, CancellationToken.None);

Expand Down
25 changes: 25 additions & 0 deletions src/EventLogExpert.UI/Interfaces/IFilePickerService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// // Copyright (c) Microsoft Corporation.
// // Licensed under the MIT License.

namespace EventLogExpert.UI.Interfaces;

public interface IFilePickerService
{
/// <summary>
/// Opens a system "Open File" dialog filtered to <paramref name="extensions" />; returns the picked path or
/// <c>null</c> if the user cancelled.
/// </summary>
Task<string?> PickAsync(string pickerTitle, IReadOnlyList<string> extensions);

/// <summary>
/// Opens a multi-select "Open File" dialog filtered to <paramref name="extensions" />; returns the picked
/// paths (empty if the user cancelled).
/// </summary>
Task<IReadOnlyList<string>> PickMultipleAsync(string pickerTitle, IReadOnlyList<string> extensions);
}

public static class FilePickerServiceFileTypes
{
public static readonly IReadOnlyList<string> Database = [".db", ".zip"];
public static readonly IReadOnlyList<string> Json = [".json"];
}
1 change: 1 addition & 0 deletions src/EventLogExpert/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public static MauiApp CreateMauiApp()
builder.Services.AddSingleton<IPreferencesProvider, PreferencesProvider>();
builder.Services.AddSingleton<IClipboardService, ClipboardService>();
builder.Services.AddSingleton<IFileSaveService, MauiFileSaveService>();
builder.Services.AddSingleton<IFilePickerService, MauiFilePickerService>();
builder.Services.AddSingleton<IFilterService, FilterService>();
builder.Services.AddSingleton<IPackageVersionProvider, PackageVersionProvider>();
builder.Services.AddSingleton<IWindowsIdentityProvider, WindowsIdentityProvider>();
Expand Down
72 changes: 72 additions & 0 deletions src/EventLogExpert/Services/MauiFilePickerService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// // Copyright (c) Microsoft Corporation.
// // Licensed under the MIT License.

using EventLogExpert.UI.Interfaces;

namespace EventLogExpert.Services;

public sealed class MauiFilePickerService : IFilePickerService
{
public Task<string?> PickAsync(string pickerTitle, IReadOnlyList<string> extensions)
{
ArgumentNullException.ThrowIfNull(pickerTitle);
ArgumentNullException.ThrowIfNull(extensions);

if (extensions.Count == 0)
{
throw new ArgumentException(
"At least one extension must be supplied.", nameof(extensions));
}

return MainThread.InvokeOnMainThreadAsync(async () =>
{
var options = BuildOptions(pickerTitle, extensions);
var result = await FilePicker.Default.PickAsync(options);
return string.IsNullOrEmpty(result?.FullPath) ? null : result.FullPath;
});
}

public Task<IReadOnlyList<string>> PickMultipleAsync(
string pickerTitle,
IReadOnlyList<string> extensions)
{
ArgumentNullException.ThrowIfNull(pickerTitle);
ArgumentNullException.ThrowIfNull(extensions);

if (extensions.Count == 0)
{
throw new ArgumentException(
"At least one extension must be supplied.", nameof(extensions));
}

return MainThread.InvokeOnMainThreadAsync<IReadOnlyList<string>>(async () =>
{
var options = BuildOptions(pickerTitle, extensions);
var results = await FilePicker.Default.PickMultipleAsync(options) ?? [];
var paths = new List<string>();

foreach (var result in results)
{
var path = result?.FullPath;

if (!string.IsNullOrEmpty(path))
{
paths.Add(path);
}
}

return paths;
});
}

private static PickOptions BuildOptions(string pickerTitle, IReadOnlyList<string> extensions) =>
new()
{
PickerTitle = pickerTitle,
FileTypes = new FilePickerFileType(
new Dictionary<DevicePlatform, IEnumerable<string>>
{
{ DevicePlatform.WinUI, extensions }
})
};
Comment thread
jschick04 marked this conversation as resolved.
}