using System.Collections.Generic; using RSG; using System.Net; using System; using System.IO; using UIWidgets.lib.cache_manager; using UIWidgets.ui; namespace UIWidgets.painting { public abstract class ImageProvider { public abstract ImageStream resolve(ImageConfiguration configuration); } public abstract class ImageProvider : ImageProvider { public override ImageStream resolve(ImageConfiguration configuration) { ImageStream stream = new ImageStream(); T obtainedKey; obtainedKey = obtainKey(configuration); stream.setCompleter(PaintingBinding.instance.imageCache.putIfAbsent(obtainedKey, () => load(obtainedKey))); return stream; } public abstract ImageStreamCompleter load(T key); public abstract T obtainKey(ImageConfiguration configuration); } public class NetworkImage : ImageProvider { public NetworkImage(string url, Dictionary headers, double scale = 1.0) { this.url = url; this.headers = headers; this.scale = scale; } /// The URL from which the image will be fetched. string url; /// The scale to place in the [ImageInfo] object of the image. double scale; /// The HTTP headers that will be used with [HttpClient.get] to fetch image from network. Dictionary headers; public override NetworkImage obtainKey(ImageConfiguration configuration) { return this; } public override ImageStreamCompleter load(NetworkImage key) { // return new OneFrameImageStreamCompleter(_loadAsync(key)); return new OneFrameImageStreamCompleter(_loadAsyncWithCache(key)); } public static IPromise _loadAsync(NetworkImage key) { var promise = new Promise(); // Create promise. using (var client = new WebClient()) { client.DownloadDataCompleted += // Monitor event for download completed. (s, ev) => { if (ev.Error != null) { promise.Reject(ev.Error); // Error during download, reject the promise. } else { var bytes = ev.Result; var imageInfo = new ImageInfo(new ui.Image( bytes )); promise.Resolve(imageInfo); // Downloaded completed successfully, resolve the promise. } }; client.DownloadDataAsync(new Uri(key.url)); // Initiate async op. } return promise; // Return the promise so the caller can await resolution (or error). } public static IPromise _loadAsyncWithCache(NetworkImage key) { var cache = CacheManager.getInstance(); var result = cache.getMeta(key.url). Then(meta => cache.downloadFileIfNeeded(meta)). Then(meta => cache.updateMeta(meta)). Then(path => cache.loadCacheFile(path)); return result; } public override string ToString() { return "NetworkImage with Url: " + this.url; } public bool Equals(NetworkImage other) { return this.url.Equals(other.url) && this.scale.Equals(other.scale); } public override bool Equals(object obj) { if (object.ReferenceEquals(null, obj)) return false; if (object.ReferenceEquals(this, obj)) return true; return obj is NetworkImage && this.Equals((NetworkImage) obj); } public override int GetHashCode() { unchecked { var hashCode = this.url.GetHashCode(); hashCode = (hashCode * 397) ^ this.scale.GetHashCode(); return hashCode; } } } public class FileImage : ImageProvider { public FileImage(string path, double scale = 1.0) { this.path = path; this.scale = scale; } public string path; public double scale; public override FileImage obtainKey(ImageConfiguration configuration) { return this; } public override ImageStreamCompleter load(FileImage key) { return new OneFrameImageStreamCompleter(_loadAsync(key)); } public static IPromise _loadAsync(FileImage key) { var promise = new Promise(); var bytes = File.ReadAllBytes(key.path); var imageInfo = new ImageInfo(new ui.Image( bytes )); promise.Resolve(imageInfo); return promise; } public override string ToString() { return "FileImage with Path: " + this.path; } public bool Equals(FileImage other) { return this.path.Equals(other.path) && this.scale.Equals(other.scale); } public override bool Equals(object obj) { if (object.ReferenceEquals(null, obj)) return false; if (object.ReferenceEquals(this, obj)) return true; return obj is FileImage && this.Equals((FileImage) obj); } public override int GetHashCode() { unchecked { var hashCode = this.path.GetHashCode(); hashCode = (hashCode * 397) ^ this.scale.GetHashCode(); return hashCode; } } } public class ImageConfiguration { public ImageConfiguration(Size size = null) { this.size = size; } public static readonly ImageConfiguration empty = new ImageConfiguration(); public ImageConfiguration copyWith(Size size = null) { return new ImageConfiguration( size: size ?? this.size ); } public readonly Size size; } }