Skip to content

Commit

Permalink
Gracefully fall back to th next storage provider (#15929)
Browse files Browse the repository at this point in the history
  • Loading branch information
kekekeks authored and maxkatz6 committed Aug 12, 2024
1 parent eefbf66 commit d2fbbc4
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 86 deletions.
95 changes: 95 additions & 0 deletions src/Avalonia.Base/Platform/Storage/FallbackStorageProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace Avalonia.Platform.Storage;
#pragma warning disable CA1823

internal class FallbackStorageProvider : IStorageProvider
{
private readonly Func<Task<IStorageProvider?>>[] _factories;
private readonly List<IStorageProvider> _providers = new();
private int _nextProviderFactory = 0;

public FallbackStorageProvider(Func<Task<IStorageProvider?>>[] factories)
{
_factories = factories;
}

async IAsyncEnumerable<IStorageProvider> GetProviders()
{
foreach (var p in _providers)
yield return p;
for (;_nextProviderFactory < _factories.Length;)
{
var p = await _factories[_nextProviderFactory]();
_nextProviderFactory++;
if (p != null)
{
_providers.Add(p);
yield return p;
}
}
}

async Task<IStorageProvider> GetFor(Func<IStorageProvider, bool> filter)
{
await foreach (var p in GetProviders())
if (filter(p))
return p;
throw new IOException("Unable to select a suitable storage provider");
}


// Those should _really_ have been asynchronous,
// but this class is expected to fall back to the managed implementation anyway
public bool CanOpen => true;
public bool CanSave => true;
public bool CanPickFolder => true;

public async Task<IReadOnlyList<IStorageFile>> OpenFilePickerAsync(FilePickerOpenOptions options)
{
return await (await GetFor(p => p.CanOpen)).OpenFilePickerAsync(options);
}

public async Task<IStorageFile?> SaveFilePickerAsync(FilePickerSaveOptions options)
{
return await (await GetFor(p => p.CanSave)).SaveFilePickerAsync(options);
}


public async Task<IReadOnlyList<IStorageFolder>> OpenFolderPickerAsync(FolderPickerOpenOptions options)
{
return await (await GetFor(p => p.CanPickFolder)).OpenFolderPickerAsync(options);
}

async Task<TResult?> FirstNotNull<TArg, TResult>(TArg arg, Func<IStorageProvider, TArg, Task<TResult?>> cb)
where TResult : class
{
await foreach (var p in GetProviders())
{
var res = await cb(p, arg);
if (res != null)
return res;
}

return null;
}

public Task<IStorageBookmarkFile?> OpenFileBookmarkAsync(string bookmark) =>
FirstNotNull(bookmark, (p, a) => p.OpenFileBookmarkAsync(a));

public Task<IStorageBookmarkFolder?> OpenFolderBookmarkAsync(string bookmark) =>
FirstNotNull(bookmark, (p, a) => p.OpenFolderBookmarkAsync(a));

public Task<IStorageFile?> TryGetFileFromPathAsync(Uri filePath) =>
FirstNotNull(filePath, (p, a) => p.TryGetFileFromPathAsync(filePath));

public Task<IStorageFolder?> TryGetFolderFromPathAsync(Uri folderPath)
=> FirstNotNull(folderPath, (p, a) => p.TryGetFolderFromPathAsync(a));

public Task<IStorageFolder?> TryGetWellKnownFolderAsync(WellKnownFolder wellKnownFolder) =>
FirstNotNull(wellKnownFolder, (p, a) => p.TryGetWellKnownFolderAsync(a));

}
3 changes: 2 additions & 1 deletion src/Avalonia.Dialogs/Avalonia.Dialogs.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

<ItemGroup>
<!-- For managed dialogs dev testing -->
<InternalsVisibleTo Include="ControlCatalog, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="ControlCatalog, PublicKey=$(AvaloniaPublicKey)" />
<InternalsVisibleTo Include="Avalonia.X11, PublicKey=$(AvaloniaPublicKey)" />
</ItemGroup>

<Import Project="..\..\build\DevAnalyzers.props" />
Expand Down
82 changes: 0 additions & 82 deletions src/Avalonia.X11/NativeDialogs/CompositeStorageProvider.cs

This file was deleted.

12 changes: 9 additions & 3 deletions src/Avalonia.X11/X11Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
using static Avalonia.X11.XLib;
using Avalonia.Input.Platform;
using System.Runtime.InteropServices;
using Avalonia.Dialogs;
using Avalonia.Platform.Storage.FileIO;

// ReSharper disable IdentifierTypo
Expand Down Expand Up @@ -237,10 +238,15 @@ public X11Window(AvaloniaX11Platform platform, IWindowImpl? popupParent, bool ov
_x11.Atoms.XA_CARDINAL, 32, PropertyMode.Replace, ref _xSyncCounter, 1);
}

_storageProvider = new CompositeStorageProvider(new[]
_storageProvider = new FallbackStorageProvider(new[]
{
() => _platform.Options.UseDBusFilePicker ? DBusSystemDialog.TryCreateAsync(Handle) : Task.FromResult<IStorageProvider?>(null),
() => GtkSystemDialog.TryCreate(this)
() => _platform.Options.UseDBusFilePicker
? DBusSystemDialog.TryCreateAsync(Handle)
: Task.FromResult<IStorageProvider?>(null),
() => GtkSystemDialog.TryCreate(this),
() => Task.FromResult(InputRoot is TopLevel tl
? (IStorageProvider?)new ManagedStorageProvider(tl)
: null)
});

platform.X11Screens.Changed += OnScreensChanged;
Expand Down

0 comments on commit d2fbbc4

Please sign in to comment.