using System; using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Threading.Tasks; using AsyncAwaitBestPractices; using AsyncImageLoader.Loaders; using Avalonia.Media.Imaging; using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; namespace StabilityMatrix.Avalonia; public readonly record struct ImageLoadFailedEventArgs(string Url, Exception Exception); [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public class FallbackRamCachedWebImageLoader : RamCachedWebImageLoader { private readonly WeakEventManager loadFailedEventManager = new(); public event EventHandler LoadFailed { add => loadFailedEventManager.AddEventHandler(value); remove => loadFailedEventManager.RemoveEventHandler(value); } protected void OnLoadFailed(string url, Exception exception) => loadFailedEventManager.RaiseEvent( this, new ImageLoadFailedEventArgs(url, exception), nameof(LoadFailed) ); /// /// Attempts to load bitmap /// /// Target url /// Bitmap protected override async Task LoadAsync(string url) { // Try to load from local file first if (File.Exists(url)) { try { if (!url.EndsWith("png", StringComparison.OrdinalIgnoreCase)) return new Bitmap(url); using var stream = ImageMetadata.BuildImageWithoutMetadata(url); return stream == null ? new Bitmap(url) : new Bitmap(stream); } catch (Exception e) { OnLoadFailed(url, e); return null; } } var internalOrCachedBitmap = await LoadFromInternalAsync(url).ConfigureAwait(false) ?? await LoadFromGlobalCache(url).ConfigureAwait(false); if (internalOrCachedBitmap != null) return internalOrCachedBitmap; try { var externalBytes = await LoadDataFromExternalAsync(url).ConfigureAwait(false); if (externalBytes == null) return null; using var memoryStream = new MemoryStream(externalBytes); var bitmap = new Bitmap(memoryStream); await SaveToGlobalCache(url, externalBytes).ConfigureAwait(false); return bitmap; } catch (Exception) { return null; } } public void RemovePathFromCache(string filePath) { var cache = this.GetPrivateField>>("_memoryCache") ?? throw new NullReferenceException("Memory cache not found"); cache.TryRemove(filePath, out _); } public void RemoveAllNamesFromCache(string fileName) { var cache = this.GetPrivateField>>("_memoryCache") ?? throw new NullReferenceException("Memory cache not found"); foreach (var (key, _) in cache) { if (Path.GetFileName(key) == fileName) { cache.TryRemove(key, out _); } } } public void ClearCache() { var cache = this.GetPrivateField>>("_memoryCache") ?? throw new NullReferenceException("Memory cache not found"); cache.Clear(); } }