aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.UI/App.xaml.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.UI/App.xaml.cs')
-rw-r--r--MediaBrowser.UI/App.xaml.cs984
1 files changed, 771 insertions, 213 deletions
diff --git a/MediaBrowser.UI/App.xaml.cs b/MediaBrowser.UI/App.xaml.cs
index 6f2afa91c..7d627e0a9 100644
--- a/MediaBrowser.UI/App.xaml.cs
+++ b/MediaBrowser.UI/App.xaml.cs
@@ -1,213 +1,771 @@
-using MediaBrowser.Common.Kernel;
-using MediaBrowser.Common.Plugins;
-using MediaBrowser.Common.UI;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.DTO;
-using MediaBrowser.Model.Weather;
-using MediaBrowser.UI.Controller;
-using System;
-using System.ComponentModel;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Media.Imaging;
-
-namespace MediaBrowser.UI
-{
- /// <summary>
- /// Interaction logic for App.xaml
- /// </summary>
- public partial class App : BaseApplication, IApplication
- {
- private Timer ClockTimer { get; set; }
- private Timer ServerConfigurationTimer { get; set; }
-
- public static App Instance
- {
- get
- {
- return Application.Current as App;
- }
- }
-
- public DtoUser CurrentUser
- {
- get
- {
- return UIKernel.Instance.CurrentUser;
- }
- set
- {
- UIKernel.Instance.CurrentUser = value;
- OnPropertyChanged("CurrentUser");
- }
- }
-
- public ServerConfiguration ServerConfiguration
- {
- get
- {
- return UIKernel.Instance.ServerConfiguration;
- }
- set
- {
- UIKernel.Instance.ServerConfiguration = value;
- OnPropertyChanged("ServerConfiguration");
- }
- }
-
- private DateTime _currentTime = DateTime.Now;
- public DateTime CurrentTime
- {
- get
- {
- return _currentTime;
- }
- private set
- {
- _currentTime = value;
- OnPropertyChanged("CurrentTime");
- }
- }
-
- private WeatherInfo _currentWeather;
- public WeatherInfo CurrentWeather
- {
- get
- {
- return _currentWeather;
- }
- private set
- {
- _currentWeather = value;
- OnPropertyChanged("CurrentWeather");
- }
- }
-
- private BaseTheme _currentTheme;
- public BaseTheme CurrentTheme
- {
- get
- {
- return _currentTheme;
- }
- private set
- {
- _currentTheme = value;
- OnPropertyChanged("CurrentTheme");
- }
- }
-
- [STAThread]
- public static void Main()
- {
- RunApplication<App>("MediaBrowserUI");
- }
-
- #region BaseApplication Overrides
- protected override IKernel InstantiateKernel()
- {
- return new UIKernel();
- }
-
- protected override Window InstantiateMainWindow()
- {
- return new MainWindow();
- }
-
- protected override void OnKernelLoaded()
- {
- base.OnKernelLoaded();
-
- PropertyChanged += AppPropertyChanged;
-
- // Update every 10 seconds
- ClockTimer = new Timer(ClockTimerCallback, null, 0, 10000);
-
- // Update every 30 minutes
- ServerConfigurationTimer = new Timer(ServerConfigurationTimerCallback, null, 0, 1800000);
-
- CurrentTheme = UIKernel.Instance.Plugins.OfType<BaseTheme>().First();
-
- foreach (var resource in CurrentTheme.GlobalResources)
- {
- Resources.MergedDictionaries.Add(resource);
- }
- }
- #endregion
-
- async void AppPropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- if (e.PropertyName.Equals("ServerConfiguration"))
- {
- if (string.IsNullOrEmpty(ServerConfiguration.WeatherZipCode))
- {
- CurrentWeather = null;
- }
- else
- {
- CurrentWeather = await UIKernel.Instance.ApiClient.GetWeatherInfoAsync(ServerConfiguration.WeatherZipCode);
- }
- }
- }
-
- private void ClockTimerCallback(object stateInfo)
- {
- CurrentTime = DateTime.Now;
- }
-
- private async void ServerConfigurationTimerCallback(object stateInfo)
- {
- ServerConfiguration = await UIKernel.Instance.ApiClient.GetServerConfigurationAsync();
- }
-
- public async Task<Image> GetImage(string url)
- {
- var image = new Image();
-
- image.Source = await GetBitmapImage(url);
-
- return image;
- }
-
- public async Task<BitmapImage> GetBitmapImage(string url)
- {
- Stream stream = await UIKernel.Instance.ApiClient.GetImageStreamAsync(url);
-
- BitmapImage bitmap = new BitmapImage();
-
- bitmap.CacheOption = BitmapCacheOption.Default;
-
- bitmap.BeginInit();
- bitmap.StreamSource = stream;
- bitmap.EndInit();
-
- return bitmap;
- }
-
- public async Task LogoutUser()
- {
- CurrentUser = null;
-
- if (ServerConfiguration.EnableUserProfiles)
- {
- Navigate(CurrentTheme.LoginPageUri);
- }
- else
- {
- DtoUser defaultUser = await UIKernel.Instance.ApiClient.GetDefaultUserAsync();
- CurrentUser = defaultUser;
-
- Navigate(new Uri("/Pages/HomePage.xaml", UriKind.Relative));
- }
- }
-
- public void Navigate(Uri uri)
- {
- (MainWindow as MainWindow).Navigate(uri);
- }
- }
-}
+using MediaBrowser.ApiInteraction;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Kernel;
+using MediaBrowser.Common.Logging;
+using MediaBrowser.Common.UI;
+using MediaBrowser.IsoMounter;
+using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.DTO;
+using MediaBrowser.Model.Net;
+using MediaBrowser.Model.Weather;
+using MediaBrowser.UI.Controller;
+using MediaBrowser.UI.Controls;
+using MediaBrowser.UI.Pages;
+using MediaBrowser.UI.Uninstall;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media.Imaging;
+
+namespace MediaBrowser.UI
+{
+ /// <summary>
+ /// Interaction logic for App.xaml
+ /// </summary>
+ public partial class App : BaseApplication, IApplication
+ {
+ /// <summary>
+ /// Gets or sets the clock timer.
+ /// </summary>
+ /// <value>The clock timer.</value>
+ private Timer ClockTimer { get; set; }
+ /// <summary>
+ /// Gets or sets the server configuration timer.
+ /// </summary>
+ /// <value>The server configuration timer.</value>
+ private Timer ServerConfigurationTimer { get; set; }
+
+ /// <summary>
+ /// Gets the name of the product.
+ /// </summary>
+ /// <value>The name of the product.</value>
+ protected override string ProductName
+ {
+ get { return Globals.ProductName; }
+ }
+
+ /// <summary>
+ /// Gets the name of the publisher.
+ /// </summary>
+ /// <value>The name of the publisher.</value>
+ protected override string PublisherName
+ {
+ get { return Globals.PublisherName; }
+ }
+
+ /// <summary>
+ /// Gets the name of the suite.
+ /// </summary>
+ /// <value>The name of the suite.</value>
+ protected override string SuiteName
+ {
+ get { return Globals.SuiteName; }
+ }
+
+ /// <summary>
+ /// Gets the name of the uninstaller file.
+ /// </summary>
+ /// <value>The name of the uninstaller file.</value>
+ protected override string UninstallerFileName
+ {
+ get { return "MediaBrowser.UI.Uninstall.exe"; }
+ }
+
+ /// <summary>
+ /// Gets the instance.
+ /// </summary>
+ /// <value>The instance.</value>
+ public static App Instance
+ {
+ get
+ {
+ return Current as App;
+ }
+ }
+
+ /// <summary>
+ /// Gets the API client.
+ /// </summary>
+ /// <value>The API client.</value>
+ public ApiClient ApiClient
+ {
+ get { return UIKernel.Instance.ApiClient; }
+ }
+
+ /// <summary>
+ /// Gets the application window.
+ /// </summary>
+ /// <value>The application window.</value>
+ public MainWindow ApplicationWindow { get; private set; }
+
+ /// <summary>
+ /// Gets the hidden window.
+ /// </summary>
+ /// <value>The hidden window.</value>
+ public HiddenWindow HiddenWindow { get; private set; }
+
+ /// <summary>
+ /// The _current user
+ /// </summary>
+ private DtoUser _currentUser;
+ /// <summary>
+ /// Gets or sets the current user.
+ /// </summary>
+ /// <value>The current user.</value>
+ public DtoUser CurrentUser
+ {
+ get
+ {
+ return _currentUser;
+ }
+ set
+ {
+ _currentUser = value;
+
+ if (UIKernel.Instance.ApiClient != null)
+ {
+ if (value == null)
+ {
+ UIKernel.Instance.ApiClient.CurrentUserId = null;
+ }
+ else
+ {
+ UIKernel.Instance.ApiClient.CurrentUserId = value.Id;
+ }
+ }
+
+ OnPropertyChanged("CurrentUser");
+ }
+ }
+
+ /// <summary>
+ /// The _server configuration
+ /// </summary>
+ private ServerConfiguration _serverConfiguration;
+ /// <summary>
+ /// Gets or sets the server configuration.
+ /// </summary>
+ /// <value>The server configuration.</value>
+ public ServerConfiguration ServerConfiguration
+ {
+ get
+ {
+ return _serverConfiguration;
+ }
+ set
+ {
+ _serverConfiguration = value;
+ OnPropertyChanged("ServerConfiguration");
+ }
+ }
+
+ /// <summary>
+ /// The _current time
+ /// </summary>
+ private DateTime _currentTime = DateTime.Now;
+ /// <summary>
+ /// Gets the current time.
+ /// </summary>
+ /// <value>The current time.</value>
+ public DateTime CurrentTime
+ {
+ get
+ {
+ return _currentTime;
+ }
+ private set
+ {
+ _currentTime = value;
+ OnPropertyChanged("CurrentTime");
+ }
+ }
+
+ /// <summary>
+ /// The _current weather
+ /// </summary>
+ private WeatherInfo _currentWeather;
+ /// <summary>
+ /// Gets the current weather.
+ /// </summary>
+ /// <value>The current weather.</value>
+ public WeatherInfo CurrentWeather
+ {
+ get
+ {
+ return _currentWeather;
+ }
+ private set
+ {
+ _currentWeather = value;
+ OnPropertyChanged("CurrentWeather");
+ }
+ }
+
+ /// <summary>
+ /// The _current theme
+ /// </summary>
+ private BaseTheme _currentTheme;
+ /// <summary>
+ /// Gets the current theme.
+ /// </summary>
+ /// <value>The current theme.</value>
+ public BaseTheme CurrentTheme
+ {
+ get
+ {
+ return _currentTheme;
+ }
+ private set
+ {
+ _currentTheme = value;
+ OnPropertyChanged("CurrentTheme");
+ }
+ }
+
+ /// <summary>
+ /// Defines the entry point of the application.
+ /// </summary>
+ [STAThread]
+ public static void Main()
+ {
+ RunApplication<App>("MediaBrowserUI");
+ }
+
+ /// <summary>
+ /// Instantiates the kernel.
+ /// </summary>
+ /// <returns>IKernel.</returns>
+ protected override IKernel InstantiateKernel()
+ {
+ return new UIKernel();
+ }
+
+ /// <summary>
+ /// Instantiates the main window.
+ /// </summary>
+ /// <returns>Window.</returns>
+ protected override Window InstantiateMainWindow()
+ {
+ HiddenWindow = new HiddenWindow { };
+
+ return HiddenWindow;
+ }
+
+ /// <summary>
+ /// Instantiates the iso manager.
+ /// </summary>
+ /// <param name="kernel">The kernel.</param>
+ /// <returns>IIsoManager.</returns>
+ protected override IIsoManager InstantiateIsoManager(IKernel kernel)
+ {
+ return new IsoManager(kernel);
+ }
+
+ /// <summary>
+ /// Shows the application window.
+ /// </summary>
+ private void ShowApplicationWindow()
+ {
+ var win = new MainWindow { };
+
+ var config = UIKernel.Instance.Configuration;
+
+ // Restore window position/size
+ if (config.WindowState.HasValue)
+ {
+ // Set window state
+ win.WindowState = config.WindowState.Value;
+
+ // Set position if not maximized
+ if (config.WindowState.Value != WindowState.Maximized)
+ {
+ double left = 0;
+ double top = 0;
+
+ // Set left
+ if (config.WindowLeft.HasValue)
+ {
+ win.WindowStartupLocation = WindowStartupLocation.Manual;
+ win.Left = left = Math.Max(config.WindowLeft.Value, 0);
+ }
+
+ // Set top
+ if (config.WindowTop.HasValue)
+ {
+ win.WindowStartupLocation = WindowStartupLocation.Manual;
+ win.Top = top = Math.Max(config.WindowTop.Value, 0);
+ }
+
+ // Set width
+ if (config.WindowWidth.HasValue)
+ {
+ win.Width = Math.Min(config.WindowWidth.Value, SystemParameters.VirtualScreenWidth - left);
+ }
+
+ // Set height
+ if (config.WindowHeight.HasValue)
+ {
+ win.Height = Math.Min(config.WindowHeight.Value, SystemParameters.VirtualScreenHeight - top);
+ }
+ }
+ }
+
+ win.LocationChanged += ApplicationWindow_LocationChanged;
+ win.StateChanged += ApplicationWindow_LocationChanged;
+ win.SizeChanged += ApplicationWindow_LocationChanged;
+
+ ApplicationWindow = win;
+
+ ApplicationWindow.Show();
+
+ ApplicationWindow.Owner = HiddenWindow;
+
+ SyncHiddenWindowLocation();
+ }
+
+ /// <summary>
+ /// Handles the LocationChanged event of the ApplicationWindow control.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
+ void ApplicationWindow_LocationChanged(object sender, EventArgs e)
+ {
+ SyncHiddenWindowLocation();
+ }
+
+ /// <summary>
+ /// Syncs the hidden window location.
+ /// </summary>
+ public void SyncHiddenWindowLocation()
+ {
+ HiddenWindow.Width = ApplicationWindow.Width;
+ HiddenWindow.Height = ApplicationWindow.Height;
+ HiddenWindow.Top = ApplicationWindow.Top;
+ HiddenWindow.Left = ApplicationWindow.Left;
+ HiddenWindow.WindowState = ApplicationWindow.WindowState;
+
+ ApplicationWindow.Activate();
+ }
+
+ /// <summary>
+ /// Loads the kernel.
+ /// </summary>
+ protected override async void LoadKernel()
+ {
+ // Without this the app will shutdown after the splash screen closes
+ ShutdownMode = ShutdownMode.OnExplicitShutdown;
+
+ Kernel = InstantiateKernel();
+
+ try
+ {
+ var now = DateTime.UtcNow;
+
+ await Kernel.Init(InstantiateIsoManager(Kernel));
+
+ Logger.Info("Kernel.Init completed in {0} seconds.", (DateTime.UtcNow - now).TotalSeconds);
+
+ ShutdownMode = System.Windows.ShutdownMode.OnLastWindowClose;
+
+ await OnKernelLoaded();
+
+ InstantiateMainWindow().Show();
+
+ ShowApplicationWindow();
+
+ await ApplicationWindow.LoadInitialUI().ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error launching application", ex);
+
+ MessageBox.Show("There was an error launching Media Browser: " + ex.Message);
+
+ // Shutdown the app with an error code
+ Shutdown(1);
+ }
+ }
+
+ /// <summary>
+ /// Called when [kernel loaded].
+ /// </summary>
+ /// <returns>Task.</returns>
+ protected override async Task OnKernelLoaded()
+ {
+ await base.OnKernelLoaded().ConfigureAwait(false);
+
+ PropertyChanged += AppPropertyChanged;
+
+ // Update every 10 seconds
+ ClockTimer = new Timer(ClockTimerCallback, null, 0, 10000);
+
+ // Update every 30 minutes
+ ServerConfigurationTimer = new Timer(ServerConfigurationTimerCallback, null, 0, 1800000);
+
+ CurrentTheme = UIKernel.Instance.Themes.First();
+
+ foreach (var resource in CurrentTheme.GetGlobalResources())
+ {
+ Resources.MergedDictionaries.Add(resource);
+ }
+ }
+
+ /// <summary>
+ /// Raises the <see cref="E:System.Windows.Application.Exit" /> event.
+ /// </summary>
+ /// <param name="e">An <see cref="T:System.Windows.ExitEventArgs" /> that contains the event data.</param>
+ protected override void OnExit(ExitEventArgs e)
+ {
+ var win = ApplicationWindow;
+
+ if (win != null)
+ {
+ // Save window position
+ var config = UIKernel.Instance.Configuration;
+ config.WindowState = win.WindowState;
+ config.WindowTop = win.Top;
+ config.WindowLeft = win.Left;
+ config.WindowWidth = win.Width;
+ config.WindowHeight = win.Height;
+ UIKernel.Instance.SaveConfiguration();
+ }
+
+ base.OnExit(e);
+ }
+
+ /// <summary>
+ /// Apps the property changed.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="e">The <see cref="PropertyChangedEventArgs" /> instance containing the event data.</param>
+ async void AppPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName.Equals("ServerConfiguration"))
+ {
+ if (string.IsNullOrEmpty(ServerConfiguration.WeatherLocation))
+ {
+ CurrentWeather = null;
+ }
+ else
+ {
+ try
+ {
+ CurrentWeather = await ApiClient.GetWeatherInfoAsync(ServerConfiguration.WeatherLocation);
+ }
+ catch (HttpException ex)
+ {
+ Logger.ErrorException("Error downloading weather information", ex);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Clocks the timer callback.
+ /// </summary>
+ /// <param name="stateInfo">The state info.</param>
+ private void ClockTimerCallback(object stateInfo)
+ {
+ CurrentTime = DateTime.Now;
+ }
+
+ /// <summary>
+ /// Servers the configuration timer callback.
+ /// </summary>
+ /// <param name="stateInfo">The state info.</param>
+ private async void ServerConfigurationTimerCallback(object stateInfo)
+ {
+ try
+ {
+ ServerConfiguration = await ApiClient.GetServerConfigurationAsync();
+ }
+ catch (HttpException ex)
+ {
+ Logger.ErrorException("Error refreshing server configuration", ex);
+ }
+ }
+
+ /// <summary>
+ /// Logouts the user.
+ /// </summary>
+ /// <returns>Task.</returns>
+ public async Task LogoutUser()
+ {
+ CurrentUser = null;
+
+ await Dispatcher.InvokeAsync(() => Navigate(CurrentTheme.GetLoginPage()));
+ }
+
+ /// <summary>
+ /// Navigates the specified page.
+ /// </summary>
+ /// <param name="page">The page.</param>
+ public void Navigate(Page page)
+ {
+ _remoteImageCache = new FileSystemRepository(UIKernel.Instance.ApplicationPaths.RemoteImageCachePath);
+
+ ApplicationWindow.Navigate(page);
+ }
+
+ /// <summary>
+ /// Navigates to settings page.
+ /// </summary>
+ public void NavigateToSettingsPage()
+ {
+ Navigate(new SettingsPage());
+ }
+
+ /// <summary>
+ /// Navigates to internal player page.
+ /// </summary>
+ public void NavigateToInternalPlayerPage()
+ {
+ Navigate(CurrentTheme.GetInternalPlayerPage());
+ }
+
+ /// <summary>
+ /// Navigates to image viewer.
+ /// </summary>
+ /// <param name="imageUrl">The image URL.</param>
+ /// <param name="caption">The caption.</param>
+ public void OpenImageViewer(Uri imageUrl, string caption)
+ {
+ var tuple = new Tuple<Uri, string>(imageUrl, caption);
+
+ OpenImageViewer(new[] { tuple });
+ }
+
+ /// <summary>
+ /// Navigates to image viewer.
+ /// </summary>
+ /// <param name="images">The images.</param>
+ public void OpenImageViewer(IEnumerable<Tuple<Uri, string>> images)
+ {
+ new ImageViewerWindow(images).ShowModal(ApplicationWindow);
+ }
+
+ /// <summary>
+ /// Navigates to item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ public void NavigateToItem(DtoBaseItem item)
+ {
+ if (item.IsRoot.HasValue && item.IsRoot.Value)
+ {
+ NavigateToHomePage();
+ }
+ else if (item.IsFolder)
+ {
+ Navigate(CurrentTheme.GetListPage(item));
+ }
+ else
+ {
+ Navigate(CurrentTheme.GetDetailPage(item));
+ }
+ }
+
+ /// <summary>
+ /// Displays the weather.
+ /// </summary>
+ public void DisplayWeather()
+ {
+ CurrentTheme.DisplayWeather();
+ }
+
+ /// <summary>
+ /// Navigates to home page.
+ /// </summary>
+ public void NavigateToHomePage()
+ {
+ Navigate(CurrentTheme.GetHomePage());
+ }
+
+ /// <summary>
+ /// Shows a notification message that will disappear on it's own
+ /// </summary>
+ /// <param name="text">The text.</param>
+ /// <param name="caption">The caption.</param>
+ /// <param name="icon">The icon.</param>
+ public void ShowNotificationMessage(string text, string caption = null, MessageBoxIcon icon = MessageBoxIcon.None)
+ {
+ ApplicationWindow.ShowModalMessage(text, caption: caption, icon: icon);
+ }
+
+ /// <summary>
+ /// Shows a notification message that will disappear on it's own
+ /// </summary>
+ /// <param name="text">The text.</param>
+ /// <param name="caption">The caption.</param>
+ /// <param name="icon">The icon.</param>
+ public void ShowNotificationMessage(UIElement text, string caption = null, MessageBoxIcon icon = MessageBoxIcon.None)
+ {
+ ApplicationWindow.ShowModalMessage(text, caption: caption, icon: icon);
+ }
+
+ /// <summary>
+ /// Shows a modal message box and asynchronously returns a MessageBoxResult
+ /// </summary>
+ /// <param name="text">The text.</param>
+ /// <param name="caption">The caption.</param>
+ /// <param name="button">The button.</param>
+ /// <param name="icon">The icon.</param>
+ /// <returns>MessageBoxResult.</returns>
+ public MessageBoxResult ShowModalMessage(string text, string caption = null, MessageBoxButton button = MessageBoxButton.OK, MessageBoxIcon icon = MessageBoxIcon.None)
+ {
+ return ApplicationWindow.ShowModalMessage(text, caption: caption, button: button, icon: icon);
+ }
+
+ /// <summary>
+ /// Shows a modal message box and asynchronously returns a MessageBoxResult
+ /// </summary>
+ /// <param name="text">The text.</param>
+ /// <param name="caption">The caption.</param>
+ /// <param name="button">The button.</param>
+ /// <param name="icon">The icon.</param>
+ /// <returns>MessageBoxResult.</returns>
+ public MessageBoxResult ShowModalMessage(UIElement text, string caption = null, MessageBoxButton button = MessageBoxButton.OK, MessageBoxIcon icon = MessageBoxIcon.None)
+ {
+ return ApplicationWindow.ShowModalMessage(text, caption: caption, button: button, icon: icon);
+ }
+
+ /// <summary>
+ /// Shows the error message.
+ /// </summary>
+ /// <param name="message">The message.</param>
+ /// <param name="caption">The caption.</param>
+ public void ShowErrorMessage(string message, string caption = null)
+ {
+ caption = caption ?? "Error";
+ ShowModalMessage(message, caption: caption, button: MessageBoxButton.OK, icon: MessageBoxIcon.Error);
+ }
+
+ /// <summary>
+ /// Shows the default error message.
+ /// </summary>
+ public void ShowDefaultErrorMessage()
+ {
+ ShowErrorMessage("There was an error processing the request", "Error");
+ }
+
+ /// <summary>
+ /// The _remote image cache
+ /// </summary>
+ private FileSystemRepository _remoteImageCache;
+
+ /// <summary>
+ /// Gets the remote image async.
+ /// </summary>
+ /// <param name="url">The URL.</param>
+ /// <returns>Task{Image}.</returns>
+ public async Task<Image> GetRemoteImageAsync(string url)
+ {
+ var bitmap = await GetRemoteBitmapAsync(url);
+
+ return new Image { Source = bitmap };
+ }
+
+ /// <summary>
+ /// Gets the remote image async.
+ /// </summary>
+ /// <param name="url">The URL.</param>
+ /// <returns>Task{BitmapImage}.</returns>
+ /// <exception cref="System.ArgumentNullException">url</exception>
+ public Task<BitmapImage> GetRemoteBitmapAsync(string url)
+ {
+ if (string.IsNullOrEmpty(url))
+ {
+ throw new ArgumentNullException("url");
+ }
+
+ Logger.Info("Image url: " + url);
+
+ return Task.Run(async () =>
+ {
+ var cachePath = _remoteImageCache.GetResourcePath(url.GetMD5().ToString());
+
+ await _remoteImageCache.WaitForLockAsync(cachePath).ConfigureAwait(false);
+
+ var releaseLock = true;
+ try
+ {
+ using (var stream = new FileStream(cachePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
+ {
+ return await GetRemoteBitmapAsync(stream).ConfigureAwait(false);
+ }
+ }
+ catch (FileNotFoundException)
+ {
+ // Doesn't exist. No biggie
+ releaseLock = false;
+ }
+ finally
+ {
+ if (releaseLock)
+ {
+ _remoteImageCache.ReleaseLock(cachePath);
+ }
+ }
+
+ try
+ {
+ using (var httpStream = await UIKernel.Instance.ApiClient.GetImageStreamAsync(url + "&x=1"))
+ {
+ return await GetRemoteBitmapAsync(httpStream, cachePath);
+ }
+ }
+ finally
+ {
+ _remoteImageCache.ReleaseLock(cachePath);
+ }
+ });
+ }
+
+ /// <summary>
+ /// Gets the image async.
+ /// </summary>
+ /// <param name="sourceStream">The source stream.</param>
+ /// <param name="cachePath">The cache path.</param>
+ /// <returns>Task{BitmapImage}.</returns>
+ private async Task<BitmapImage> GetRemoteBitmapAsync(Stream sourceStream, string cachePath = null)
+ {
+ byte[] bytes;
+
+ using (var ms = new MemoryStream())
+ {
+ await sourceStream.CopyToAsync(ms).ConfigureAwait(false);
+
+ bytes = ms.ToArray();
+ }
+
+ if (!string.IsNullOrEmpty(cachePath))
+ {
+ using (var fileStream = new FileStream(cachePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
+ {
+ await fileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+ }
+ }
+
+ using (Stream stream = new MemoryStream(bytes))
+ {
+ var bitmapImage = new BitmapImage
+ {
+ CreateOptions = BitmapCreateOptions.DelayCreation
+ };
+
+ bitmapImage.BeginInit();
+ bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
+ bitmapImage.StreamSource = stream;
+ bitmapImage.EndInit();
+ bitmapImage.Freeze();
+ return bitmapImage;
+ }
+ }
+ }
+}