Skip to content

Commit 863071a

Browse files
authored
Merge pull request #27 from AvaloniaUtils/storageFileProviderSupport
Implement IAdvancedAsyncImageLoader with IStorageProvider support
2 parents 5836120 + 9b8e03a commit 863071a

5 files changed

Lines changed: 68 additions & 11 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ obj/
33
/packages/
44
riderModule.iml
55
/_ReSharper.Caches/
6-
.idea/
6+
.idea/
7+
*.DotSettings*

AsyncImageLoader.Avalonia/AdvancedImage.axaml.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,12 @@ private async void UpdateImage(string? source, IAsyncImageLoader? loader)
238238
}
239239

240240
loader ??= ImageLoader.AsyncImageLoader;
241+
242+
if (loader is IAdvancedAsyncImageLoader advancedLoader)
243+
{
244+
return await advancedLoader.ProvideImageAsync(source, TopLevel.GetTopLevel(this)?.StorageProvider);
245+
}
246+
241247
return await loader.ProvideImageAsync(source);
242248
}
243249
catch (TaskCanceledException)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Avalonia.Media.Imaging;
4+
using Avalonia.Platform.Storage;
5+
6+
namespace AsyncImageLoader;
7+
8+
public interface IAdvancedAsyncImageLoader : IDisposable
9+
{
10+
/// <summary>
11+
/// Loads image
12+
/// </summary>
13+
/// <param name="url">Target url</param>
14+
/// <param name="storageProvider">Avalonia's storage provider</param>
15+
/// <returns>Bitmap</returns>
16+
public Task<Bitmap?> ProvideImageAsync(string url, IStorageProvider? storageProvider = null);
17+
}

AsyncImageLoader.Avalonia/ImageLoader.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ private static async void OnSourceChanged(Image sender, AvaloniaPropertyChangedE
5858
// A small delay allows to cancel early if the image goes out of screen too fast (eg. scrolling)
5959
// The Bitmap constructor is expensive and cannot be cancelled
6060
await Task.Delay(10, cts.Token);
61+
62+
if (AsyncImageLoader is IAdvancedAsyncImageLoader advancedLoader)
63+
{
64+
return await advancedLoader.ProvideImageAsync(url, TopLevel.GetTopLevel(sender)?.StorageProvider);
65+
}
6166

6267
return await AsyncImageLoader.ProvideImageAsync(url);
6368
}

AsyncImageLoader.Avalonia/Loaders/BaseWebImageLoader.cs

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@
22
using System.IO;
33
using System.Net.Http;
44
using System.Threading.Tasks;
5+
using Avalonia;
6+
using Avalonia.Controls;
57
using Avalonia.Logging;
68
using Avalonia.Media.Imaging;
79
using Avalonia.Platform;
10+
using IStorageProvider = Avalonia.Platform.Storage.IStorageProvider;
811

912
namespace AsyncImageLoader.Loaders;
1013

1114
/// <summary>
1215
/// Provides non cached way to asynchronously load images for <see cref="ImageLoader" />
1316
/// Can be used as base class if you want to create custom caching mechanism
1417
/// </summary>
15-
public class BaseWebImageLoader : IAsyncImageLoader {
18+
public class BaseWebImageLoader : IAsyncImageLoader, IAdvancedAsyncImageLoader {
1619
private readonly ParametrizedLogger? _logger;
1720
private readonly bool _shouldDisposeHttpClient;
1821

@@ -48,16 +51,23 @@ public void Dispose() {
4851
GC.SuppressFinalize(this);
4952
}
5053

54+
/// <inheritdoc />
55+
public async Task<Bitmap?> ProvideImageAsync(string url, IStorageProvider? storageProvider = null)
56+
{
57+
return await LoadAsync(url, storageProvider).ConfigureAwait(false);
58+
}
59+
5160
/// <summary>
5261
/// Attempts to load bitmap
5362
/// </summary>
5463
/// <param name="url">Target url</param>
64+
/// <param name="storageProvider">Avalonia's storage provider</param>
5565
/// <returns>Bitmap</returns>
56-
protected virtual async Task<Bitmap?> LoadAsync(string url) {
66+
protected virtual async Task<Bitmap?> LoadAsync(string url, IStorageProvider? storageProvider) {
5767
var internalOrCachedBitmap =
58-
await LoadFromLocalAsync(url).ConfigureAwait(false)
59-
?? await LoadFromInternalAsync(url).ConfigureAwait(false)
60-
?? await LoadFromGlobalCache(url).ConfigureAwait(false);
68+
await LoadFromLocalAsync(url, storageProvider).ConfigureAwait(false)
69+
?? await LoadFromInternalAsync(url).ConfigureAwait(false)
70+
?? await LoadFromGlobalCache(url).ConfigureAwait(false);
6171
if (internalOrCachedBitmap != null) return internalOrCachedBitmap;
6272

6373
try {
@@ -78,12 +88,30 @@ await LoadFromLocalAsync(url).ConfigureAwait(false)
7888
}
7989

8090
/// <summary>
81-
/// the url maybe is local file url,so if file exists ,we got a Bitmap
91+
/// Attempts to load bitmap
92+
/// </summary>
93+
/// <param name="url">Target url</param>
94+
/// <returns>Bitmap</returns>
95+
protected virtual Task<Bitmap?> LoadAsync(string url)
96+
{
97+
return LoadAsync(url, null);
98+
}
99+
100+
/// <summary>
101+
/// The url maybe is local file url, so if file exists, we got a Bitmap
82102
/// </summary>
83-
/// <param name="url"></param>
84-
/// <returns></returns>
85-
private Task<Bitmap?> LoadFromLocalAsync(string url) {
86-
return Task.FromResult(File.Exists(url) ? new Bitmap(url) : null);
103+
/// <param name="url">Url to load</param>
104+
/// <param name="storageProvider">Avalonia's storage provider</param>
105+
private static async Task<Bitmap?> LoadFromLocalAsync(string url, IStorageProvider? storageProvider)
106+
{
107+
if (File.Exists(url))
108+
return new Bitmap(url);
109+
110+
if (storageProvider is null) return null;
111+
var fileInfo = await storageProvider.TryGetFileFromPathAsync(new Uri(url));
112+
if (fileInfo is null) return null;
113+
using var fileStream = await fileInfo.OpenReadAsync();
114+
return new Bitmap(fileStream);
87115
}
88116

89117
/// <summary>

0 commit comments

Comments
 (0)