Skip to content

Commit a3c400f

Browse files
Merge pull request #76 from TheEightBot/feature/better-android-image-loading
2 parents 9ec268d + c3161a5 commit a3c400f

File tree

11 files changed

+279
-103
lines changed

11 files changed

+279
-103
lines changed

AuroraControls.TestApp/MainPage.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public MainPage(ILogger<TestRxViewModel> logger)
104104
Children =
105105
{
106106
new Button { BackgroundColor = Colors.Fuchsia, }
107-
.SetSvgIcon("splatoon.svg", colorOverride: Colors.White),
107+
.SetSvgIcon("splatoon.svg", 40, colorOverride: Colors.White),
108108

109109
new Button { Text = "View Image Processing", }
110110
.BindClicked(async () => await this.Navigation.PushAsync(new ImageProcessing()))
@@ -264,7 +264,7 @@ await this.Navigation.PushAsync(new ConfettiViewTestPage())),
264264
{
265265
Opacity = .25d,
266266
BackgroundColor = Colors.Fuchsia,
267-
ActiveColor = Colors.Red,
267+
ActiveColor = Colors.Transparent,
268268
InactiveColor = Colors.Green,
269269
PlaceholderColor = Colors.Purple,
270270
BorderStyle = ContainerBorderStyle.RoundedRectanglePlaceholderThrough,
@@ -492,8 +492,10 @@ await this.Navigation.PushAsync(new ConfettiViewTestPage())),
492492
},
493493
}),
494494
new Tile { EmbeddedImageName = "triforce.svg", ButtonBackgroundColor = Colors.Fuchsia, },
495-
new SvgImageView { EmbeddedImageName = "splatoon.svg", OverlayColor = Colors.Chartreuse, }
495+
new SvgImageView { EmbeddedImageName = "splatoon.svg", HeightRequest = 66, OverlayColor = Colors.Chartreuse, }
496496
.Assign(out _svgImageView),
497+
new Image { HeightRequest = 66, }
498+
.SetSvgIcon("splatoon.svg", 66, Colors.Fuchsia),
497499
new Button { Text = "Update Effects" }
498500
.Assign(out _svgImageViewTapped),
499501
new GradientPillButton
@@ -505,8 +507,6 @@ await this.Navigation.PushAsync(new ConfettiViewTestPage())),
505507
FontFamily = "Clathing",
506508
}
507509
.Assign(out _pillButton),
508-
new Image()
509-
.SetSvgIcon("splatoon.svg", 66, Colors.Red),
510510
new CupertinoToggleSwitch(),
511511
},
512512
},

AuroraControlsMaui/AuroraControlBuilder.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Reflection;
2+
using Microsoft.Extensions.Logging;
23
using SkiaSharp.Views.Maui.Controls.Hosting;
34

45
namespace AuroraControls;
@@ -36,6 +37,11 @@ public static MauiAppBuilder UseAuroraControls(this MauiAppBuilder mauiAppBuilde
3637
.Add<Effects.RoundedCornersEffect, RoundedCornersPlatformEffect>()
3738
.Add<Effects.SafeAreaEffect, SafeAreaPlatformEffect>();
3839
#endif
40+
})
41+
.ConfigureImageSources(
42+
services =>
43+
{
44+
services.AddService<NoCacheFileImageSource>(svcs => new NoCacheFileImageSourceService(svcs.GetService<ILogger<NoCacheFileImageSourceService>>()));
3945
});
4046

4147
foreach (var assembly in resourceAssemblies)

AuroraControlsMaui/Extensions/ImageSourceExtensions.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public static Image AsAsyncSourceFor<T>(this Task<T> imageSourceTask, Image imag
4444
return image;
4545
}
4646

47-
public static ToolbarItem AsAsyncSourceFor(this Task<FileImageSource> imageSourceTask, ToolbarItem toolbarItem)
47+
public static ToolbarItem AsAsyncSourceFor(this Task<ImageSource> imageSourceTask, ToolbarItem toolbarItem)
4848
{
4949
imageSourceTask
5050
.ContinueWith(
@@ -60,7 +60,7 @@ public static ToolbarItem AsAsyncSourceFor(this Task<FileImageSource> imageSourc
6060
return toolbarItem;
6161
}
6262

63-
public static MenuItem AsAsyncSourceFor(this Task<FileImageSource> imageSourceTask, MenuItem menuItem)
63+
public static MenuItem AsAsyncSourceFor(this Task<ImageSource> imageSourceTask, MenuItem menuItem)
6464
{
6565
imageSourceTask
6666
.ContinueWith(
@@ -92,7 +92,7 @@ public static Page AsAsyncSourceFor(this Task<FileImageSource> imageSourceTask,
9292
return page;
9393
}
9494

95-
public static Button AsAsyncSourceFor(this Task<FileImageSource> imageSourceTask, Button button)
95+
public static Button AsAsyncSourceFor(this Task<ImageSource> imageSourceTask, Button button)
9696
{
9797
imageSourceTask
9898
.ContinueWith(
@@ -108,7 +108,7 @@ public static Button AsAsyncSourceFor(this Task<FileImageSource> imageSourceTask
108108
return button;
109109
}
110110

111-
public static ImageButton AsAsyncSourceFor(this Task<FileImageSource> imageSourceTask, ImageButton button)
111+
public static ImageButton AsAsyncSourceFor(this Task<ImageSource> imageSourceTask, ImageButton button)
112112
{
113113
imageSourceTask
114114
.ContinueWith(
@@ -124,7 +124,7 @@ public static ImageButton AsAsyncSourceFor(this Task<FileImageSource> imageSourc
124124
return button;
125125
}
126126

127-
public static ImageCell AsAsyncSourceFor(this Task<FileImageSource> imageSourceTask, ImageCell imageCell)
127+
public static ImageCell AsAsyncSourceFor(this Task<ImageSource> imageSourceTask, ImageCell imageCell)
128128
{
129129
imageSourceTask
130130
.ContinueWith(
@@ -140,7 +140,7 @@ public static ImageCell AsAsyncSourceFor(this Task<FileImageSource> imageSourceT
140140
return imageCell;
141141
}
142142

143-
public static void AsAsyncSourceFor(this Task<FileImageSource> imageSourceTask, Action<ImageSource> assignImageSource) =>
143+
public static void AsAsyncSourceFor(this Task<ImageSource> imageSourceTask, Action<ImageSource> assignImageSource) =>
144144
imageSourceTask
145145
.ContinueWith(
146146
async result =>
@@ -210,7 +210,7 @@ public static T AsAsyncSourceFor<T>(this Task<T> imageSourceTask, Action<T, T> a
210210
return imageSource;
211211
}
212212

213-
public static FileImageSource AsAsyncFileImageSource(this Task<FileImageSource> imageSourceTask)
213+
public static FileImageSource AsAsyncImageSource(this Task<FileImageSource> imageSourceTask)
214214
{
215215
var imageSource = new FileImageSource();
216216

@@ -228,7 +228,7 @@ public static FileImageSource AsAsyncFileImageSource(this Task<FileImageSource>
228228
return imageSource;
229229
}
230230

231-
public static FileImageSource AsAsyncFileImageSource(this Task<FileImageSource> imageSourceTask, FileImageSource updatableSource)
231+
public static ImageSource AsAsyncImageSource(this Task<FileImageSource> imageSourceTask, FileImageSource updatableSource)
232232
{
233233
imageSourceTask
234234
.ContinueWith(
@@ -264,31 +264,31 @@ public static UriImageSource AsAsyncUriImageSource(this Task<UriImageSource> ima
264264

265265
public static Button SetSvgIcon(this Button imageElement, string svgName, double squareSize = 24d, Color? colorOverride = null) =>
266266
IconCache
267-
.FileImageSourceFromSvg(svgName, squareSize, colorOverride: colorOverride)
267+
.ImageSourceFromSvg(svgName, squareSize, colorOverride: colorOverride)
268268
.AsAsyncSourceFor(imageElement);
269269

270270
public static ImageButton SetSvgIcon(this ImageButton imageButton, string svgName, double squareSize = 24d, Color? colorOverride = null)
271271
{
272272
IconCache
273-
.FileImageSourceFromSvg(svgName, squareSize, colorOverride: colorOverride)
273+
.ImageSourceFromSvg(svgName, squareSize, colorOverride: colorOverride)
274274
.AsAsyncSourceFor(x => imageButton.Source = x);
275275

276276
return imageButton;
277277
}
278278

279279
public static ToolbarItem SetSvgIcon(this ToolbarItem toolbarItem, string svgName, double squareSize = 24d, Color? colorOverride = null) =>
280280
IconCache
281-
.FileImageSourceFromSvg(svgName, squareSize, colorOverride: colorOverride)
281+
.ImageSourceFromSvg(svgName, squareSize, colorOverride: colorOverride)
282282
.AsAsyncSourceFor(toolbarItem);
283283

284284
public static MenuItem SetSvgIcon(this MenuItem menuItem, string svgName, double squareSize = 24d, Color? colorOverride = null) =>
285285
IconCache
286-
.FileImageSourceFromSvg(svgName, squareSize, colorOverride: colorOverride)
286+
.ImageSourceFromSvg(svgName, squareSize, colorOverride: colorOverride)
287287
.AsAsyncSourceFor(menuItem);
288288

289289
public static Image SetSvgIcon(this Image image, string svgName, double squareSize = 24d, Color? colorOverride = null) =>
290290
IconCache
291-
.FileImageSourceFromSvg(svgName, squareSize, colorOverride: colorOverride)
291+
.ImageSourceFromSvg(svgName, squareSize, colorOverride: colorOverride)
292292
.AsAsyncSourceFor(image);
293293

294294
public static Task<SKBitmap> BitmapFromSource(this ImageSource imageSource) => IconCache.SKBitmapFromSource(imageSource);

AuroraControlsMaui/IIconCache.cs

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public interface IIconCache
3535
/// <param name="squareSize">The square size of the icon.</param>
3636
/// <param name="additionalCacheKey">Allows for setting an addiitonal cache key.</param>
3737
/// <param name="colorOverride">Allows for setting the color of the icon.</param>
38-
Task<ImageSource> SourceFromSvg(string svgName, double squareSize = 22d, string additionalCacheKey = "", Color? colorOverride = default(Color));
38+
Task<ImageSource> ImageSourceFromSvg(string svgName, double squareSize = 22d, string additionalCacheKey = "", Color? colorOverride = default(Color));
3939

4040
/// <summary>
4141
/// Fetches an SVG icon by name.
@@ -45,7 +45,7 @@ public interface IIconCache
4545
/// <param name="size">A Xamarin.Forms.Size representing the desired size of the icon.</param>
4646
/// <param name="additionalCacheKey">Allows for setting an addiitonal cache key.</param>
4747
/// <param name="colorOverride">Allows for setting the color of the icon.</param>
48-
Task<ImageSource> SourceFromSvg(string svgName, Size size, string additionalCacheKey = "", Color? colorOverride = default(Color));
48+
Task<ImageSource> ImageSourceFromSvg(string svgName, Size size, string additionalCacheKey = "", Color? colorOverride = default(Color));
4949

5050
/// <summary>
5151
/// Fetches an SVG icon by name.
@@ -56,7 +56,7 @@ public interface IIconCache
5656
/// <param name="squareSize">A double representing the desired size of the icon.</param>
5757
/// <param name="additionalCacheKey">Allows for setting an addiitonal cache key.</param>
5858
/// <param name="colorOverride">Allows for setting the color of the icon.</param>
59-
Task<ImageSource> SourceFromRawSvg(string svgName, string svgValue, double squareSize = 22d, string additionalCacheKey = "", Color? colorOverride = default(Color));
59+
Task<ImageSource> ImageSourceFromRawSvg(string svgName, string svgValue, double squareSize = 22d, string additionalCacheKey = "", Color? colorOverride = default(Color));
6060

6161
/// <summary>
6262
/// Fetches an SVG icon by name.
@@ -67,27 +67,7 @@ public interface IIconCache
6767
/// <param name="size">A Xamarin.Forms.Size representing the desired size of the icon.</param>
6868
/// <param name="additionalCacheKey">Allows for setting an addiitonal cache key.</param>
6969
/// <param name="colorOverride">Allows for setting the color of the icon.</param>
70-
Task<ImageSource> SourceFromRawSvg(string svgName, string svgValue, Size size, string additionalCacheKey = "", Color? colorOverride = default(Color));
71-
72-
/// <summary>
73-
/// Fetches an SVG file image source by name.
74-
/// </summary>
75-
/// <returns>The Icon as a FileImageSource.</returns>
76-
/// <param name="svgName">The name of the SVG.</param>
77-
/// <param name="squareSize">The square size of the icon.</param>
78-
/// <param name="additionalCacheKey">Allows for setting an addiitonal cache key.</param>
79-
/// <param name="colorOverride">Allows for setting the color of the icon.</param>
80-
Task<FileImageSource> FileImageSourceFromSvg(string svgName, double squareSize = 22d, string additionalCacheKey = "", Color? colorOverride = default(Color));
81-
82-
/// <summary>
83-
/// Fetches an SVG icon by name.
84-
/// </summary>
85-
/// <returns>The Icon as a FileImageSource.</returns>
86-
/// <param name="svgName">The name of the SVG.</param>
87-
/// <param name="size">A Xamarin.Forms.Size representing the desired size of the icon.</param>
88-
/// <param name="additionalCacheKey">Allows for setting an addiitonal cache key.</param>
89-
/// <param name="colorOverride">Allows for setting the color of the icon.</param>
90-
Task<FileImageSource> FileImageSourceFromSvg(string svgName, Size size, string additionalCacheKey = "", Color? colorOverride = default(Color));
70+
Task<ImageSource> ImageSourceFromRawSvg(string svgName, string svgValue, Size size, string additionalCacheKey = "", Color? colorOverride = default(Color));
9171

9272
/// <summary>
9373
/// Loads the assembly.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace AuroraControls;
2+
3+
internal interface INoCacheFileImageSource : IImageSource
4+
{
5+
string File { get; }
6+
}

AuroraControlsMaui/IconCacheBase.cs

Lines changed: 23 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -33,55 +33,12 @@ public IconCacheBase()
3333
public async Task<Image> IconFromSvg(string svgName, Size size, string additionalCacheKey = "", Color? colorOverride = null) =>
3434
new()
3535
{
36-
Source = await SourceFromSvg(svgName, size, additionalCacheKey, colorOverride),
36+
Source = await ImageSourceFromSvg(svgName, size, additionalCacheKey, colorOverride),
3737
};
3838

39-
public Task<ImageSource> SourceFromSvg(string svgName, double squareSize = 22d, string additionalCacheKey = "", Color? colorOverride = null) => SourceFromSvg(svgName, new Size(squareSize, squareSize), additionalCacheKey, colorOverride);
39+
public Task<ImageSource> ImageSourceFromRawSvg(string svgName, string svgValue, double squareSize = 22d, string additionalCacheKey = "", Color? colorOverride = null) => ImageSourceFromRawSvg(svgName, svgValue, new Size(squareSize, squareSize), additionalCacheKey, colorOverride);
4040

41-
public async Task<ImageSource> SourceFromSvg(string svgName, Size size, string additionalCacheKey = "", Color? colorOverride = null)
42-
{
43-
string key = CreateIconKey(svgName, size, additionalCacheKey, colorOverride);
44-
45-
try
46-
{
47-
await _iconLock.WaitAsync().ConfigureAwait(false);
48-
49-
if (_resolvedIcons.ContainsKey(key))
50-
{
51-
return new FileImageSource { File = _resolvedIcons[key] };
52-
}
53-
54-
string? diskCachedImage = GetImagePathFromDiskCache(key);
55-
56-
if (!string.IsNullOrEmpty(diskCachedImage))
57-
{
58-
_resolvedIcons[key] = diskCachedImage;
59-
return new FileImageSource { File = diskCachedImage };
60-
}
61-
62-
await GenerateImageFromEmbedded(key, svgName, size, colorOverride).ConfigureAwait(false);
63-
64-
diskCachedImage = GetImagePathFromDiskCache(key);
65-
66-
_resolvedIcons[key] = diskCachedImage;
67-
68-
return new FileImageSource { File = diskCachedImage };
69-
}
70-
catch (Exception ex)
71-
{
72-
Console.WriteLine($"[SVG Exception]\t {ex}");
73-
74-
return new FileImageSource();
75-
}
76-
finally
77-
{
78-
_iconLock.Release();
79-
}
80-
}
81-
82-
public Task<ImageSource> SourceFromRawSvg(string svgName, string svgValue, double squareSize = 22d, string additionalCacheKey = "", Color? colorOverride = null) => SourceFromRawSvg(svgName, svgValue, new Size(squareSize, squareSize), additionalCacheKey, colorOverride);
83-
84-
public async Task<ImageSource> SourceFromRawSvg(string svgName, string svgValue, Size size, string additionalCacheKey = "", Color? colorOverride = null)
41+
public async Task<ImageSource> ImageSourceFromRawSvg(string svgName, string svgValue, Size size, string additionalCacheKey = "", Color? colorOverride = null)
8542
{
8643
try
8744
{
@@ -91,15 +48,15 @@ public async Task<ImageSource> SourceFromRawSvg(string svgName, string svgValue,
9148

9249
if (_resolvedIcons.ContainsKey(key))
9350
{
94-
return new FileImageSource { File = _resolvedIcons[key] };
51+
return GetPlatformImageSource(_resolvedIcons[key]);
9552
}
9653

9754
string? diskCachedImage = GetImagePathFromDiskCache(key);
9855

9956
if (!string.IsNullOrEmpty(diskCachedImage))
10057
{
10158
_resolvedIcons[key] = diskCachedImage;
102-
return new FileImageSource { File = diskCachedImage };
59+
return GetPlatformImageSource(diskCachedImage);
10360
}
10461

10562
await GenerateImageFromRaw(key, svgValue, size, colorOverride).ConfigureAwait(false);
@@ -108,18 +65,18 @@ public async Task<ImageSource> SourceFromRawSvg(string svgName, string svgValue,
10865

10966
_resolvedIcons[key] = diskCachedImage;
11067

111-
return new FileImageSource { File = diskCachedImage };
68+
return GetPlatformImageSource(diskCachedImage);
11269
}
11370
finally
11471
{
11572
_iconLock.Release();
11673
}
11774
}
11875

119-
public Task<FileImageSource> FileImageSourceFromSvg(string svgName, double squareSize = 22d, string additionalCacheKey = "", Color? colorOverride = null) =>
120-
FileImageSourceFromSvg(svgName, new Size(squareSize, squareSize), additionalCacheKey, colorOverride);
76+
public Task<ImageSource> ImageSourceFromSvg(string svgName, double squareSize = 22d, string additionalCacheKey = "", Color? colorOverride = null) =>
77+
ImageSourceFromSvg(svgName, new Size(squareSize, squareSize), additionalCacheKey, colorOverride);
12178

122-
public async Task<FileImageSource> FileImageSourceFromSvg(string svgName, Size size, string additionalCacheKey = "", Color? colorOverride = null)
79+
public async Task<ImageSource> ImageSourceFromSvg(string svgName, Size size, string additionalCacheKey = "", Color? colorOverride = null)
12380
{
12481
try
12582
{
@@ -129,15 +86,15 @@ public async Task<FileImageSource> FileImageSourceFromSvg(string svgName, Size s
12986

13087
if (_resolvedIcons.ContainsKey(key))
13188
{
132-
return new FileImageSource { File = _resolvedIcons[key] };
89+
return GetPlatformImageSource(_resolvedIcons[key]);
13390
}
13491

13592
string? diskCachedImage = GetImagePathFromDiskCache(key);
13693

13794
if (!string.IsNullOrEmpty(diskCachedImage))
13895
{
13996
_resolvedIcons[key] = diskCachedImage;
140-
return new FileImageSource { File = diskCachedImage };
97+
return GetPlatformImageSource(diskCachedImage);
14198
}
14299

143100
await GenerateImageFromEmbedded(key, svgName, size, colorOverride).ConfigureAwait(false);
@@ -146,25 +103,30 @@ public async Task<FileImageSource> FileImageSourceFromSvg(string svgName, Size s
146103

147104
_resolvedIcons[key] = diskCachedImage;
148105

149-
if (DeviceInfo.Current.Platform == DevicePlatform.iOS)
150-
{
151-
return new FileImageSource { File = diskCachedImage };
152-
}
153-
154-
return new FileImageSource { File = diskCachedImage };
106+
return GetPlatformImageSource(diskCachedImage);
155107
}
156108
catch (Exception ex)
157109
{
158110
Console.WriteLine($"[SVG Exception]\t {ex}");
159111

160-
return new FileImageSource();
112+
return GetPlatformImageSource();
161113
}
162114
finally
163115
{
164116
_iconLock.Release();
165117
}
166118
}
167119

120+
private ImageSource GetPlatformImageSource(string? file = null)
121+
{
122+
if (DeviceInfo.Current.Platform == DevicePlatform.Android)
123+
{
124+
return new NoCacheFileImageSource { File = file };
125+
}
126+
127+
return new FileImageSource { File = file };
128+
}
129+
168130
private string? GetImagePathFromDiskCache(string key)
169131
{
170132
if (!Directory.Exists(PlatformInfo.IconCacheDirectory))

0 commit comments

Comments
 (0)