diff --git a/ReactWindows/ReactNative/Modules/Image/BitmapImageHelpers.cs b/ReactWindows/ReactNative/Modules/Image/BitmapImageHelpers.cs index 6f027fae4ae..60fe4e27619 100644 --- a/ReactWindows/ReactNative/Modules/Image/BitmapImageHelpers.cs +++ b/ReactWindows/ReactNative/Modules/Image/BitmapImageHelpers.cs @@ -55,16 +55,7 @@ public static IObservable GetStreamLoadObservable(this Bit .Merge(image.GetFailedObservable(), Scheduler.Default) .StartWith(new ImageStatusEventData(ImageLoadStatus.OnLoadStart)); } - - public static IObservable GetUriLoadObservable(this BitmapImage image) - { - return Observable.Merge( - Scheduler.Default, - image.GetDownloadingObservable(), - image.GetOpenedObservable(), - image.GetFailedObservable()); - } - + private static IObservable GetOpenedObservable(this BitmapImage image) { return Observable.FromEventPattern( @@ -101,14 +92,5 @@ private static IObservable GetFailedObservable(this Bitmap throw new InvalidOperationException(pattern.EventArgs.ErrorMessage); }); } - - private static IObservable GetDownloadingObservable(this BitmapImage image) - { - return Observable.FromEventPattern( - h => image.DownloadProgress += h, - h => image.DownloadProgress -= h) - .Take(1) - .Select(_ => new ImageStatusEventData(ImageLoadStatus.OnLoadStart)); - } } } diff --git a/ReactWindows/ReactNative/Modules/Image/ImageLoaderModule.cs b/ReactWindows/ReactNative/Modules/Image/ImageLoaderModule.cs index 47b9c8779c2..1d7a560fd2e 100644 --- a/ReactWindows/ReactNative/Modules/Image/ImageLoaderModule.cs +++ b/ReactWindows/ReactNative/Modules/Image/ImageLoaderModule.cs @@ -1,8 +1,7 @@ -using Newtonsoft.Json.Linq; +using Microsoft.Toolkit.Uwp.UI; +using Newtonsoft.Json.Linq; using ReactNative.Bridge; using System; -using System.Reactive.Linq; -using Windows.UI.Xaml.Media.Imaging; namespace ReactNative.Modules.Image { @@ -23,7 +22,26 @@ public override string Name [ReactMethod] public void prefetchImage(string uriString, IPromise promise) { - promise.Reject(ErrorPrefetchFailure, "Prefetch is not yet implemented."); + if (string.IsNullOrEmpty(uriString)) + { + promise.Reject(ErrorInvalidUri, "Cannot prefetch an image for an empty URI."); + return; + } + + DispatcherHelpers.RunOnDispatcher(async () => + { + try + { + // TODO: enable prefetch cancellation + var uri = new Uri(uriString); + await ImageCache.Instance.PreCacheAsync(uri, true, true).ConfigureAwait(false); + promise.Resolve(true); + } + catch (Exception ex) + { + promise.Reject(ErrorPrefetchFailure, ex.Message); + } + }); } [ReactMethod] @@ -39,27 +57,12 @@ public void getSize(string uriString, IPromise promise) { try { - var bitmapImage = new BitmapImage(); - var loadQuery = bitmapImage.GetStreamLoadObservable() - .Where(status => status.LoadStatus == ImageLoadStatus.OnLoadEnd) - .FirstAsync() - .Replay(1); - - using (loadQuery.Connect()) + var bitmapImage = await ImageCache.Instance.GetFromCacheAsync(new Uri(uriString), true); + promise.Resolve(new JObject { - using (var stream = await BitmapImageHelpers.GetStreamAsync(uriString)) - { - await bitmapImage.SetSourceAsync(stream); - } - - await loadQuery; - - promise.Resolve(new JObject - { - { "width", bitmapImage.PixelWidth }, - { "height", bitmapImage.PixelHeight }, - }); - } + { "width", bitmapImage.PixelWidth }, + { "height", bitmapImage.PixelHeight }, + }); } catch (Exception ex) { diff --git a/ReactWindows/ReactNative/Views/Image/ReactImageManager.cs b/ReactWindows/ReactNative/Views/Image/ReactImageManager.cs index 13a27573aa9..39805d53638 100644 --- a/ReactWindows/ReactNative/Views/Image/ReactImageManager.cs +++ b/ReactWindows/ReactNative/Views/Image/ReactImageManager.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json.Linq; +using Microsoft.Toolkit.Uwp.UI; +using Newtonsoft.Json.Linq; using ReactNative.Collections; using ReactNative.Modules.Image; using ReactNative.UIManager; @@ -254,7 +255,7 @@ private void OnImageFailed(Border view) ReactImageLoadEvent.OnLoadEnd)); } - private void OnImageStatusUpdate(Border view, ImageStatusEventData status) + private void OnImageStatusUpdate(Border view, ImageLoadStatus status, ImageMetadata metadata) { var eventDispatcher = view.GetReactContext() .GetNativeModule() @@ -263,10 +264,10 @@ private void OnImageStatusUpdate(Border view, ImageStatusEventData status) eventDispatcher.DispatchEvent( new ReactImageLoadEvent( view.GetTag(), - (int)status.LoadStatus, - status.Metadata.Uri, - status.Metadata.Width, - status.Metadata.Height)); + (int)status, + metadata.Uri, + metadata.Width, + metadata.Height)); } /// @@ -286,28 +287,37 @@ private async void SetUriFromSingleSource(Border view, string source) _disposables.Add(tag, disposable); } - var image = new BitmapImage(); if (BitmapImageHelpers.IsBase64Uri(source)) { + var image = new BitmapImage(); + disposable.Disposable = image.GetStreamLoadObservable().Subscribe( - status => OnImageStatusUpdate(view, status), + status => OnImageStatusUpdate(view, status.LoadStatus, status.Metadata), _ => OnImageFailed(view)); using (var stream = await BitmapImageHelpers.GetStreamAsync(source)) { await image.SetSourceAsync(stream); } + + imageBrush.ImageSource = image; } else { - disposable.Disposable = image.GetUriLoadObservable().Subscribe( - status => OnImageStatusUpdate(view, status), - _ => OnImageFailed(view)); - - image.UriSource = new Uri(source); + OnImageStatusUpdate(view, ImageLoadStatus.OnLoadStart, default(ImageMetadata)); + try + { + var image = await ImageCache.Instance.GetFromCacheAsync(new Uri(source), true); + var metadata = new ImageMetadata(source, image.PixelWidth, image.PixelHeight); + OnImageStatusUpdate(view, ImageLoadStatus.OnLoad, metadata); + imageBrush.ImageSource = image; + OnImageStatusUpdate(view, ImageLoadStatus.OnLoadEnd, metadata); + } + catch + { + OnImageFailed(view); + } } - - imageBrush.ImageSource = image; } /// diff --git a/ReactWindows/ReactNative/project.json b/ReactWindows/ReactNative/project.json index 5e4cae47926..ce6fb075e0a 100644 --- a/ReactWindows/ReactNative/project.json +++ b/ReactWindows/ReactNative/project.json @@ -2,6 +2,7 @@ "dependencies": { "Facebook.CSSLayout": "2.0.1-pre", "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2", + "Microsoft.Toolkit.Uwp.UI": "1.2.0", "Newtonsoft.Json": "9.0.1", "PCLStorage": "1.0.2", "System.Reactive": "3.0.0",