2
0

App.xaml.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098
  1. using MediaBrowser.ApiInteraction;
  2. using MediaBrowser.ClickOnce;
  3. using MediaBrowser.Common.Extensions;
  4. using MediaBrowser.Common.IO;
  5. using MediaBrowser.Common.Kernel;
  6. using MediaBrowser.IsoMounter;
  7. using MediaBrowser.Logging.Nlog;
  8. using MediaBrowser.Model.Configuration;
  9. using MediaBrowser.Model.Dto;
  10. using MediaBrowser.Model.Logging;
  11. using MediaBrowser.Model.Net;
  12. using MediaBrowser.Model.Updates;
  13. using MediaBrowser.Model.Weather;
  14. using MediaBrowser.UI.Controller;
  15. using MediaBrowser.UI.Controls;
  16. using MediaBrowser.UI.Pages;
  17. using MediaBrowser.UI.Uninstall;
  18. using Microsoft.Win32;
  19. using System;
  20. using System.Collections.Generic;
  21. using System.ComponentModel;
  22. using System.IO;
  23. using System.Linq;
  24. using System.Net.Cache;
  25. using System.Threading;
  26. using System.Threading.Tasks;
  27. using System.Windows;
  28. using System.Windows.Controls;
  29. using System.Windows.Media;
  30. using System.Windows.Media.Imaging;
  31. namespace MediaBrowser.UI
  32. {
  33. /// <summary>
  34. /// Interaction logic for App.xaml
  35. /// </summary>
  36. public partial class App : Application, IApplicationHost
  37. {
  38. /// <summary>
  39. /// Gets or sets a value indicating whether [last run at startup value].
  40. /// </summary>
  41. /// <value><c>null</c> if [last run at startup value] contains no value, <c>true</c> if [last run at startup value]; otherwise, <c>false</c>.</value>
  42. private bool? LastRunAtStartupValue { get; set; }
  43. /// <summary>
  44. /// Gets or sets the clock timer.
  45. /// </summary>
  46. /// <value>The clock timer.</value>
  47. private Timer ClockTimer { get; set; }
  48. /// <summary>
  49. /// Gets or sets the server configuration timer.
  50. /// </summary>
  51. /// <value>The server configuration timer.</value>
  52. private Timer ServerConfigurationTimer { get; set; }
  53. /// <summary>
  54. /// The single instance mutex
  55. /// </summary>
  56. private Mutex SingleInstanceMutex;
  57. /// <summary>
  58. /// Gets or sets the kernel.
  59. /// </summary>
  60. /// <value>The kernel.</value>
  61. protected IKernel Kernel { get; set; }
  62. /// <summary>
  63. /// Gets or sets the logger.
  64. /// </summary>
  65. /// <value>The logger.</value>
  66. protected ILogger Logger { get; set; }
  67. /// <summary>
  68. /// Gets or sets the log file path.
  69. /// </summary>
  70. /// <value>The log file path.</value>
  71. public string LogFilePath { get; private set; }
  72. /// <summary>
  73. /// Occurs when [property changed].
  74. /// </summary>
  75. public event PropertyChangedEventHandler PropertyChanged;
  76. /// <summary>
  77. /// Gets the name of the product.
  78. /// </summary>
  79. /// <value>The name of the product.</value>
  80. protected string ProductName
  81. {
  82. get { return Globals.ProductName; }
  83. }
  84. /// <summary>
  85. /// Gets the name of the publisher.
  86. /// </summary>
  87. /// <value>The name of the publisher.</value>
  88. protected string PublisherName
  89. {
  90. get { return Globals.PublisherName; }
  91. }
  92. /// <summary>
  93. /// Gets the name of the suite.
  94. /// </summary>
  95. /// <value>The name of the suite.</value>
  96. protected string SuiteName
  97. {
  98. get { return Globals.SuiteName; }
  99. }
  100. /// <summary>
  101. /// Gets the name of the uninstaller file.
  102. /// </summary>
  103. /// <value>The name of the uninstaller file.</value>
  104. protected string UninstallerFileName
  105. {
  106. get { return "MediaBrowser.UI.Uninstall.exe"; }
  107. }
  108. /// <summary>
  109. /// The container
  110. /// </summary>
  111. private SimpleInjector.Container _container = new SimpleInjector.Container();
  112. /// <summary>
  113. /// Gets or sets the iso manager.
  114. /// </summary>
  115. /// <value>The iso manager.</value>
  116. private IIsoManager IsoManager { get; set; }
  117. /// <summary>
  118. /// Gets the instance.
  119. /// </summary>
  120. /// <value>The instance.</value>
  121. public static App Instance
  122. {
  123. get
  124. {
  125. return Current as App;
  126. }
  127. }
  128. /// <summary>
  129. /// Gets the API client.
  130. /// </summary>
  131. /// <value>The API client.</value>
  132. public ApiClient ApiClient
  133. {
  134. get { return UIKernel.Instance.ApiClient; }
  135. }
  136. /// <summary>
  137. /// Gets the application window.
  138. /// </summary>
  139. /// <value>The application window.</value>
  140. public MainWindow ApplicationWindow { get; private set; }
  141. /// <summary>
  142. /// Gets the hidden window.
  143. /// </summary>
  144. /// <value>The hidden window.</value>
  145. public HiddenWindow HiddenWindow { get; private set; }
  146. /// <summary>
  147. /// The _current user
  148. /// </summary>
  149. private UserDto _currentUser;
  150. /// <summary>
  151. /// Gets or sets the current user.
  152. /// </summary>
  153. /// <value>The current user.</value>
  154. public UserDto CurrentUser
  155. {
  156. get
  157. {
  158. return _currentUser;
  159. }
  160. set
  161. {
  162. _currentUser = value;
  163. if (UIKernel.Instance.ApiClient != null)
  164. {
  165. if (value == null)
  166. {
  167. UIKernel.Instance.ApiClient.CurrentUserId = null;
  168. }
  169. else
  170. {
  171. UIKernel.Instance.ApiClient.CurrentUserId = value.Id;
  172. }
  173. }
  174. OnPropertyChanged("CurrentUser");
  175. }
  176. }
  177. /// <summary>
  178. /// The _server configuration
  179. /// </summary>
  180. private ServerConfiguration _serverConfiguration;
  181. /// <summary>
  182. /// Gets or sets the server configuration.
  183. /// </summary>
  184. /// <value>The server configuration.</value>
  185. public ServerConfiguration ServerConfiguration
  186. {
  187. get
  188. {
  189. return _serverConfiguration;
  190. }
  191. set
  192. {
  193. _serverConfiguration = value;
  194. OnPropertyChanged("ServerConfiguration");
  195. }
  196. }
  197. /// <summary>
  198. /// The _current time
  199. /// </summary>
  200. private DateTime _currentTime = DateTime.Now;
  201. /// <summary>
  202. /// Gets the current time.
  203. /// </summary>
  204. /// <value>The current time.</value>
  205. public DateTime CurrentTime
  206. {
  207. get
  208. {
  209. return _currentTime;
  210. }
  211. private set
  212. {
  213. _currentTime = value;
  214. OnPropertyChanged("CurrentTime");
  215. }
  216. }
  217. /// <summary>
  218. /// The _current weather
  219. /// </summary>
  220. private WeatherInfo _currentWeather;
  221. /// <summary>
  222. /// Gets the current weather.
  223. /// </summary>
  224. /// <value>The current weather.</value>
  225. public WeatherInfo CurrentWeather
  226. {
  227. get
  228. {
  229. return _currentWeather;
  230. }
  231. private set
  232. {
  233. _currentWeather = value;
  234. OnPropertyChanged("CurrentWeather");
  235. }
  236. }
  237. /// <summary>
  238. /// The _current theme
  239. /// </summary>
  240. private BaseTheme _currentTheme;
  241. /// <summary>
  242. /// Gets the current theme.
  243. /// </summary>
  244. /// <value>The current theme.</value>
  245. public BaseTheme CurrentTheme
  246. {
  247. get
  248. {
  249. return _currentTheme;
  250. }
  251. private set
  252. {
  253. _currentTheme = value;
  254. OnPropertyChanged("CurrentTheme");
  255. }
  256. }
  257. /// <summary>
  258. /// Defines the entry point of the application.
  259. /// </summary>
  260. [STAThread]
  261. public static void Main()
  262. {
  263. var application = new App(new NLogger("App"));
  264. application.InitializeComponent();
  265. application.Run();
  266. }
  267. /// <summary>
  268. /// Initializes a new instance of the <see cref="App" /> class.
  269. /// </summary>
  270. /// <param name="logger">The logger.</param>
  271. public App(ILogger logger)
  272. {
  273. Logger = logger;
  274. InitializeComponent();
  275. }
  276. /// <summary>
  277. /// Instantiates the main window.
  278. /// </summary>
  279. /// <returns>Window.</returns>
  280. protected Window InstantiateMainWindow()
  281. {
  282. HiddenWindow = new HiddenWindow { };
  283. return HiddenWindow;
  284. }
  285. /// <summary>
  286. /// Shows the application window.
  287. /// </summary>
  288. private void ShowApplicationWindow()
  289. {
  290. var win = new MainWindow(Logger);
  291. var config = UIKernel.Instance.Configuration;
  292. // Restore window position/size
  293. if (config.WindowState.HasValue)
  294. {
  295. // Set window state
  296. win.WindowState = config.WindowState.Value;
  297. // Set position if not maximized
  298. if (config.WindowState.Value != WindowState.Maximized)
  299. {
  300. double left = 0;
  301. double top = 0;
  302. // Set left
  303. if (config.WindowLeft.HasValue)
  304. {
  305. win.WindowStartupLocation = WindowStartupLocation.Manual;
  306. win.Left = left = Math.Max(config.WindowLeft.Value, 0);
  307. }
  308. // Set top
  309. if (config.WindowTop.HasValue)
  310. {
  311. win.WindowStartupLocation = WindowStartupLocation.Manual;
  312. win.Top = top = Math.Max(config.WindowTop.Value, 0);
  313. }
  314. // Set width
  315. if (config.WindowWidth.HasValue)
  316. {
  317. win.Width = Math.Min(config.WindowWidth.Value, SystemParameters.VirtualScreenWidth - left);
  318. }
  319. // Set height
  320. if (config.WindowHeight.HasValue)
  321. {
  322. win.Height = Math.Min(config.WindowHeight.Value, SystemParameters.VirtualScreenHeight - top);
  323. }
  324. }
  325. }
  326. win.LocationChanged += ApplicationWindow_LocationChanged;
  327. win.StateChanged += ApplicationWindow_LocationChanged;
  328. win.SizeChanged += ApplicationWindow_LocationChanged;
  329. ApplicationWindow = win;
  330. ApplicationWindow.Show();
  331. ApplicationWindow.Owner = HiddenWindow;
  332. SyncHiddenWindowLocation();
  333. }
  334. /// <summary>
  335. /// Handles the LocationChanged event of the ApplicationWindow control.
  336. /// </summary>
  337. /// <param name="sender">The source of the event.</param>
  338. /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
  339. void ApplicationWindow_LocationChanged(object sender, EventArgs e)
  340. {
  341. SyncHiddenWindowLocation();
  342. }
  343. /// <summary>
  344. /// Syncs the hidden window location.
  345. /// </summary>
  346. public void SyncHiddenWindowLocation()
  347. {
  348. HiddenWindow.Width = ApplicationWindow.Width;
  349. HiddenWindow.Height = ApplicationWindow.Height;
  350. HiddenWindow.Top = ApplicationWindow.Top;
  351. HiddenWindow.Left = ApplicationWindow.Left;
  352. HiddenWindow.WindowState = ApplicationWindow.WindowState;
  353. ApplicationWindow.Activate();
  354. }
  355. /// <summary>
  356. /// Loads the kernel.
  357. /// </summary>
  358. protected async void LoadKernel()
  359. {
  360. // Without this the app will shutdown after the splash screen closes
  361. ShutdownMode = ShutdownMode.OnExplicitShutdown;
  362. RegisterResources();
  363. Kernel = new UIKernel(this, Logger);
  364. try
  365. {
  366. var now = DateTime.UtcNow;
  367. await Kernel.Init();
  368. Logger.Info("Kernel.Init completed in {0} seconds.", (DateTime.UtcNow - now).TotalSeconds);
  369. ShutdownMode = System.Windows.ShutdownMode.OnLastWindowClose;
  370. OnKernelLoaded();
  371. InstantiateMainWindow().Show();
  372. ShowApplicationWindow();
  373. await ApplicationWindow.LoadInitialUI().ConfigureAwait(false);
  374. }
  375. catch (Exception ex)
  376. {
  377. Logger.ErrorException("Error launching application", ex);
  378. MessageBox.Show("There was an error launching Media Browser: " + ex.Message);
  379. // Shutdown the app with an error code
  380. Shutdown(1);
  381. }
  382. }
  383. /// <summary>
  384. /// Called when [kernel loaded].
  385. /// </summary>
  386. /// <returns>Task.</returns>
  387. protected void OnKernelLoaded()
  388. {
  389. Kernel.ConfigurationUpdated += Kernel_ConfigurationUpdated;
  390. ConfigureClickOnceStartup();
  391. PropertyChanged += AppPropertyChanged;
  392. // Update every 10 seconds
  393. ClockTimer = new Timer(ClockTimerCallback, null, 0, 10000);
  394. // Update every 30 minutes
  395. ServerConfigurationTimer = new Timer(ServerConfigurationTimerCallback, null, 0, 1800000);
  396. CurrentTheme = UIKernel.Instance.Themes.First();
  397. foreach (var resource in CurrentTheme.GetGlobalResources())
  398. {
  399. Resources.MergedDictionaries.Add(resource);
  400. }
  401. }
  402. /// <summary>
  403. /// Raises the <see cref="E:System.Windows.Application.Startup" /> event.
  404. /// </summary>
  405. /// <param name="e">A <see cref="T:System.Windows.StartupEventArgs" /> that contains the event data.</param>
  406. protected override void OnStartup(StartupEventArgs e)
  407. {
  408. bool createdNew;
  409. SingleInstanceMutex = new Mutex(true, @"Local\" + GetType().Assembly.GetName().Name, out createdNew);
  410. if (!createdNew)
  411. {
  412. SingleInstanceMutex = null;
  413. Shutdown();
  414. return;
  415. }
  416. AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
  417. LoadKernel();
  418. SystemEvents.SessionEnding += SystemEvents_SessionEnding;
  419. }
  420. /// <summary>
  421. /// Handles the UnhandledException event of the CurrentDomain control.
  422. /// </summary>
  423. /// <param name="sender">The source of the event.</param>
  424. /// <param name="e">The <see cref="UnhandledExceptionEventArgs" /> instance containing the event data.</param>
  425. void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
  426. {
  427. var exception = (Exception)e.ExceptionObject;
  428. Logger.ErrorException("UnhandledException", exception);
  429. MessageBox.Show("Unhandled exception: " + exception.Message);
  430. }
  431. /// <summary>
  432. /// Called when [property changed].
  433. /// </summary>
  434. /// <param name="info">The info.</param>
  435. public void OnPropertyChanged(String info)
  436. {
  437. if (PropertyChanged != null)
  438. {
  439. try
  440. {
  441. PropertyChanged(this, new PropertyChangedEventArgs(info));
  442. }
  443. catch (Exception ex)
  444. {
  445. Logger.ErrorException("Error in event handler", ex);
  446. }
  447. }
  448. }
  449. /// <summary>
  450. /// Handles the SessionEnding event of the SystemEvents control.
  451. /// </summary>
  452. /// <param name="sender">The source of the event.</param>
  453. /// <param name="e">The <see cref="SessionEndingEventArgs" /> instance containing the event data.</param>
  454. void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
  455. {
  456. // Try to shut down gracefully
  457. Shutdown();
  458. }
  459. /// <summary>
  460. /// Raises the <see cref="E:System.Windows.Application.Exit" /> event.
  461. /// </summary>
  462. /// <param name="e">An <see cref="T:System.Windows.ExitEventArgs" /> that contains the event data.</param>
  463. protected override void OnExit(ExitEventArgs e)
  464. {
  465. var win = ApplicationWindow;
  466. if (win != null)
  467. {
  468. // Save window position
  469. var config = UIKernel.Instance.Configuration;
  470. config.WindowState = win.WindowState;
  471. config.WindowTop = win.Top;
  472. config.WindowLeft = win.Left;
  473. config.WindowWidth = win.Width;
  474. config.WindowHeight = win.Height;
  475. UIKernel.Instance.SaveConfiguration();
  476. }
  477. ReleaseMutex();
  478. base.OnExit(e);
  479. Kernel.Dispose();
  480. }
  481. /// <summary>
  482. /// Releases the mutex.
  483. /// </summary>
  484. private void ReleaseMutex()
  485. {
  486. if (SingleInstanceMutex == null)
  487. {
  488. return;
  489. }
  490. SingleInstanceMutex.ReleaseMutex();
  491. SingleInstanceMutex.Close();
  492. SingleInstanceMutex.Dispose();
  493. SingleInstanceMutex = null;
  494. }
  495. /// <summary>
  496. /// Apps the property changed.
  497. /// </summary>
  498. /// <param name="sender">The sender.</param>
  499. /// <param name="e">The <see cref="PropertyChangedEventArgs" /> instance containing the event data.</param>
  500. async void AppPropertyChanged(object sender, PropertyChangedEventArgs e)
  501. {
  502. if (e.PropertyName.Equals("ServerConfiguration"))
  503. {
  504. if (string.IsNullOrEmpty(ServerConfiguration.WeatherLocation))
  505. {
  506. CurrentWeather = null;
  507. }
  508. else
  509. {
  510. try
  511. {
  512. CurrentWeather = await ApiClient.GetWeatherInfoAsync(ServerConfiguration.WeatherLocation);
  513. }
  514. catch (HttpException ex)
  515. {
  516. Logger.ErrorException("Error downloading weather information", ex);
  517. }
  518. }
  519. }
  520. }
  521. /// <summary>
  522. /// Clocks the timer callback.
  523. /// </summary>
  524. /// <param name="stateInfo">The state info.</param>
  525. private void ClockTimerCallback(object stateInfo)
  526. {
  527. CurrentTime = DateTime.Now;
  528. }
  529. /// <summary>
  530. /// Servers the configuration timer callback.
  531. /// </summary>
  532. /// <param name="stateInfo">The state info.</param>
  533. private async void ServerConfigurationTimerCallback(object stateInfo)
  534. {
  535. try
  536. {
  537. var b = Kernel;
  538. //ServerConfiguration = await ApiClient.GetServerConfigurationAsync();
  539. }
  540. catch (HttpException ex)
  541. {
  542. Logger.ErrorException("Error refreshing server configuration", ex);
  543. }
  544. }
  545. /// <summary>
  546. /// Logouts the user.
  547. /// </summary>
  548. /// <returns>Task.</returns>
  549. public async Task LogoutUser()
  550. {
  551. CurrentUser = null;
  552. await Dispatcher.InvokeAsync(() => Navigate(CurrentTheme.GetLoginPage()));
  553. }
  554. /// <summary>
  555. /// Navigates the specified page.
  556. /// </summary>
  557. /// <param name="page">The page.</param>
  558. public void Navigate(Page page)
  559. {
  560. _remoteImageCache = new FileSystemRepository(UIKernel.Instance.ApplicationPaths.RemoteImageCachePath);
  561. ApplicationWindow.Navigate(page);
  562. }
  563. /// <summary>
  564. /// Navigates to settings page.
  565. /// </summary>
  566. public void NavigateToSettingsPage()
  567. {
  568. Navigate(new SettingsPage());
  569. }
  570. /// <summary>
  571. /// Navigates to internal player page.
  572. /// </summary>
  573. public void NavigateToInternalPlayerPage()
  574. {
  575. Navigate(CurrentTheme.GetInternalPlayerPage());
  576. }
  577. /// <summary>
  578. /// Navigates to image viewer.
  579. /// </summary>
  580. /// <param name="imageUrl">The image URL.</param>
  581. /// <param name="caption">The caption.</param>
  582. public void OpenImageViewer(Uri imageUrl, string caption)
  583. {
  584. var tuple = new Tuple<Uri, string>(imageUrl, caption);
  585. OpenImageViewer(new[] { tuple });
  586. }
  587. /// <summary>
  588. /// Navigates to image viewer.
  589. /// </summary>
  590. /// <param name="images">The images.</param>
  591. public void OpenImageViewer(IEnumerable<Tuple<Uri, string>> images)
  592. {
  593. new ImageViewerWindow(images).ShowModal(ApplicationWindow);
  594. }
  595. /// <summary>
  596. /// Navigates to item.
  597. /// </summary>
  598. /// <param name="item">The item.</param>
  599. public void NavigateToItem(BaseItemDto item)
  600. {
  601. if (item.IsRoot.HasValue && item.IsRoot.Value)
  602. {
  603. NavigateToHomePage();
  604. }
  605. else if (item.IsFolder)
  606. {
  607. Navigate(CurrentTheme.GetListPage(item));
  608. }
  609. else
  610. {
  611. Navigate(CurrentTheme.GetDetailPage(item));
  612. }
  613. }
  614. /// <summary>
  615. /// Displays the weather.
  616. /// </summary>
  617. public void DisplayWeather()
  618. {
  619. CurrentTheme.DisplayWeather();
  620. }
  621. /// <summary>
  622. /// Navigates to home page.
  623. /// </summary>
  624. public void NavigateToHomePage()
  625. {
  626. Navigate(CurrentTheme.GetHomePage());
  627. }
  628. /// <summary>
  629. /// Shows a notification message that will disappear on it's own
  630. /// </summary>
  631. /// <param name="text">The text.</param>
  632. /// <param name="caption">The caption.</param>
  633. /// <param name="icon">The icon.</param>
  634. public void ShowNotificationMessage(string text, string caption = null, MessageBoxIcon icon = MessageBoxIcon.None)
  635. {
  636. ApplicationWindow.ShowModalMessage(text, caption: caption, icon: icon);
  637. }
  638. /// <summary>
  639. /// Shows a notification message that will disappear on it's own
  640. /// </summary>
  641. /// <param name="text">The text.</param>
  642. /// <param name="caption">The caption.</param>
  643. /// <param name="icon">The icon.</param>
  644. public void ShowNotificationMessage(UIElement text, string caption = null, MessageBoxIcon icon = MessageBoxIcon.None)
  645. {
  646. ApplicationWindow.ShowModalMessage(text, caption: caption, icon: icon);
  647. }
  648. /// <summary>
  649. /// Shows a modal message box and asynchronously returns a MessageBoxResult
  650. /// </summary>
  651. /// <param name="text">The text.</param>
  652. /// <param name="caption">The caption.</param>
  653. /// <param name="button">The button.</param>
  654. /// <param name="icon">The icon.</param>
  655. /// <returns>MessageBoxResult.</returns>
  656. public MessageBoxResult ShowModalMessage(string text, string caption = null, MessageBoxButton button = MessageBoxButton.OK, MessageBoxIcon icon = MessageBoxIcon.None)
  657. {
  658. return ApplicationWindow.ShowModalMessage(text, caption: caption, button: button, icon: icon);
  659. }
  660. /// <summary>
  661. /// Shows a modal message box and asynchronously returns a MessageBoxResult
  662. /// </summary>
  663. /// <param name="text">The text.</param>
  664. /// <param name="caption">The caption.</param>
  665. /// <param name="button">The button.</param>
  666. /// <param name="icon">The icon.</param>
  667. /// <returns>MessageBoxResult.</returns>
  668. public MessageBoxResult ShowModalMessage(UIElement text, string caption = null, MessageBoxButton button = MessageBoxButton.OK, MessageBoxIcon icon = MessageBoxIcon.None)
  669. {
  670. return ApplicationWindow.ShowModalMessage(text, caption: caption, button: button, icon: icon);
  671. }
  672. /// <summary>
  673. /// Shows the error message.
  674. /// </summary>
  675. /// <param name="message">The message.</param>
  676. /// <param name="caption">The caption.</param>
  677. public void ShowErrorMessage(string message, string caption = null)
  678. {
  679. caption = caption ?? "Error";
  680. ShowModalMessage(message, caption: caption, button: MessageBoxButton.OK, icon: MessageBoxIcon.Error);
  681. }
  682. /// <summary>
  683. /// Shows the default error message.
  684. /// </summary>
  685. public void ShowDefaultErrorMessage()
  686. {
  687. ShowErrorMessage("There was an error processing the request", "Error");
  688. }
  689. /// <summary>
  690. /// The _remote image cache
  691. /// </summary>
  692. private FileSystemRepository _remoteImageCache;
  693. /// <summary>
  694. /// Gets the remote image async.
  695. /// </summary>
  696. /// <param name="url">The URL.</param>
  697. /// <returns>Task{Image}.</returns>
  698. public async Task<Image> GetRemoteImageAsync(string url)
  699. {
  700. var bitmap = await GetRemoteBitmapAsync(url);
  701. return new Image { Source = bitmap };
  702. }
  703. /// <summary>
  704. /// Gets the remote image async.
  705. /// </summary>
  706. /// <param name="url">The URL.</param>
  707. /// <returns>Task{BitmapImage}.</returns>
  708. /// <exception cref="System.ArgumentNullException">url</exception>
  709. public Task<BitmapImage> GetRemoteBitmapAsync(string url)
  710. {
  711. if (string.IsNullOrEmpty(url))
  712. {
  713. throw new ArgumentNullException("url");
  714. }
  715. Logger.Info("Image url: " + url);
  716. return Task.Run(async () =>
  717. {
  718. var cachePath = _remoteImageCache.GetResourcePath(url.GetMD5().ToString());
  719. await _remoteImageCache.WaitForLockAsync(cachePath).ConfigureAwait(false);
  720. var releaseLock = true;
  721. try
  722. {
  723. using (var stream = new FileStream(cachePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
  724. {
  725. return await GetRemoteBitmapAsync(stream).ConfigureAwait(false);
  726. }
  727. }
  728. catch (FileNotFoundException)
  729. {
  730. // Doesn't exist. No biggie
  731. releaseLock = false;
  732. }
  733. finally
  734. {
  735. if (releaseLock)
  736. {
  737. _remoteImageCache.ReleaseLock(cachePath);
  738. }
  739. }
  740. try
  741. {
  742. using (var httpStream = await UIKernel.Instance.ApiClient.GetImageStreamAsync(url + "&x=1"))
  743. {
  744. return await GetRemoteBitmapAsync(httpStream, cachePath);
  745. }
  746. }
  747. finally
  748. {
  749. _remoteImageCache.ReleaseLock(cachePath);
  750. }
  751. });
  752. }
  753. /// <summary>
  754. /// Gets the image async.
  755. /// </summary>
  756. /// <param name="sourceStream">The source stream.</param>
  757. /// <param name="cachePath">The cache path.</param>
  758. /// <returns>Task{BitmapImage}.</returns>
  759. private async Task<BitmapImage> GetRemoteBitmapAsync(Stream sourceStream, string cachePath = null)
  760. {
  761. byte[] bytes;
  762. using (var ms = new MemoryStream())
  763. {
  764. await sourceStream.CopyToAsync(ms).ConfigureAwait(false);
  765. bytes = ms.ToArray();
  766. }
  767. if (!string.IsNullOrEmpty(cachePath))
  768. {
  769. using (var fileStream = new FileStream(cachePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
  770. {
  771. await fileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
  772. }
  773. }
  774. using (Stream stream = new MemoryStream(bytes))
  775. {
  776. var bitmapImage = new BitmapImage
  777. {
  778. CreateOptions = BitmapCreateOptions.DelayCreation
  779. };
  780. bitmapImage.BeginInit();
  781. bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
  782. bitmapImage.StreamSource = stream;
  783. bitmapImage.EndInit();
  784. bitmapImage.Freeze();
  785. return bitmapImage;
  786. }
  787. }
  788. /// <summary>
  789. /// Handles the ConfigurationUpdated event of the Kernel control.
  790. /// </summary>
  791. /// <param name="sender">The source of the event.</param>
  792. /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
  793. void Kernel_ConfigurationUpdated(object sender, EventArgs e)
  794. {
  795. if (!LastRunAtStartupValue.HasValue || LastRunAtStartupValue.Value != Kernel.Configuration.RunAtStartup)
  796. {
  797. ConfigureClickOnceStartup();
  798. }
  799. }
  800. /// <summary>
  801. /// Configures the click once startup.
  802. /// </summary>
  803. private void ConfigureClickOnceStartup()
  804. {
  805. try
  806. {
  807. ClickOnceHelper.ConfigureClickOnceStartupIfInstalled(PublisherName, ProductName, SuiteName, Kernel.Configuration.RunAtStartup, UninstallerFileName);
  808. LastRunAtStartupValue = Kernel.Configuration.RunAtStartup;
  809. }
  810. catch (Exception ex)
  811. {
  812. Logger.ErrorException("Error configuring ClickOnce", ex);
  813. }
  814. }
  815. public void Restart()
  816. {
  817. Dispatcher.Invoke(ReleaseMutex);
  818. Kernel.Dispose();
  819. System.Windows.Forms.Application.Restart();
  820. Dispatcher.Invoke(Shutdown);
  821. }
  822. public void ReloadLogger()
  823. {
  824. LogFilePath = Path.Combine(Kernel.ApplicationPaths.LogDirectoryPath, "Server-" + DateTime.Now.Ticks + ".log");
  825. NlogManager.AddFileTarget(LogFilePath, Kernel.Configuration.EnableDebugLevelLogging);
  826. }
  827. /// <summary>
  828. /// Gets the bitmap image.
  829. /// </summary>
  830. /// <param name="uri">The URI.</param>
  831. /// <returns>BitmapImage.</returns>
  832. /// <exception cref="System.ArgumentNullException">uri</exception>
  833. public BitmapImage GetBitmapImage(string uri)
  834. {
  835. if (string.IsNullOrEmpty(uri))
  836. {
  837. throw new ArgumentNullException("uri");
  838. }
  839. return GetBitmapImage(new Uri(uri));
  840. }
  841. /// <summary>
  842. /// Gets the bitmap image.
  843. /// </summary>
  844. /// <param name="uri">The URI.</param>
  845. /// <returns>BitmapImage.</returns>
  846. /// <exception cref="System.ArgumentNullException">uri</exception>
  847. public BitmapImage GetBitmapImage(Uri uri)
  848. {
  849. if (uri == null)
  850. {
  851. throw new ArgumentNullException("uri");
  852. }
  853. var bitmap = new BitmapImage
  854. {
  855. CreateOptions = BitmapCreateOptions.DelayCreation,
  856. CacheOption = BitmapCacheOption.OnDemand,
  857. UriCachePolicy = new RequestCachePolicy(RequestCacheLevel.CacheIfAvailable)
  858. };
  859. bitmap.BeginInit();
  860. bitmap.UriSource = uri;
  861. bitmap.EndInit();
  862. RenderOptions.SetBitmapScalingMode(bitmap, BitmapScalingMode.Fant);
  863. return bitmap;
  864. }
  865. /// <summary>
  866. /// Gets or sets a value indicating whether this instance can self update.
  867. /// </summary>
  868. /// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
  869. public bool CanSelfUpdate
  870. {
  871. get { return ClickOnceHelper.IsNetworkDeployed; }
  872. }
  873. /// <summary>
  874. /// Checks for update.
  875. /// </summary>
  876. /// <param name="cancellationToken">The cancellation token.</param>
  877. /// <param name="progress">The progress.</param>
  878. /// <returns>Task{CheckForUpdateResult}.</returns>
  879. public Task<CheckForUpdateResult> CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress<double> progress)
  880. {
  881. return new ApplicationUpdateCheck().CheckForApplicationUpdate(cancellationToken, progress);
  882. }
  883. /// <summary>
  884. /// Registers resources that classes will depend on
  885. /// </summary>
  886. private void RegisterResources()
  887. {
  888. Register<IApplicationHost>(this);
  889. Register(Logger);
  890. IsoManager = new PismoIsoManager(Logger);
  891. Register<IIsoManager>(IsoManager);
  892. }
  893. /// <summary>
  894. /// Updates the application.
  895. /// </summary>
  896. /// <param name="cancellationToken">The cancellation token.</param>
  897. /// <param name="progress">The progress.</param>
  898. /// <returns>Task.</returns>
  899. public Task UpdateApplication(CancellationToken cancellationToken, IProgress<double> progress)
  900. {
  901. return new ApplicationUpdater().UpdateApplication(cancellationToken, progress);
  902. }
  903. /// <summary>
  904. /// Creates an instance of type and resolves all constructor dependancies
  905. /// </summary>
  906. /// <param name="type">The type.</param>
  907. /// <returns>System.Object.</returns>
  908. public object CreateInstance(Type type)
  909. {
  910. try
  911. {
  912. return _container.GetInstance(type);
  913. }
  914. catch
  915. {
  916. Logger.Error("Error creating {0}", type.Name);
  917. throw;
  918. }
  919. }
  920. /// <summary>
  921. /// Registers the specified obj.
  922. /// </summary>
  923. /// <typeparam name="T"></typeparam>
  924. /// <param name="obj">The obj.</param>
  925. public void Register<T>(T obj)
  926. where T : class
  927. {
  928. _container.RegisterSingle(obj);
  929. }
  930. /// <summary>
  931. /// Resolves this instance.
  932. /// </summary>
  933. /// <typeparam name="T"></typeparam>
  934. /// <returns>``0.</returns>
  935. public T Resolve<T>()
  936. {
  937. return (T)_container.GetRegistration(typeof(T), true).GetInstance();
  938. }
  939. /// <summary>
  940. /// Resolves this instance.
  941. /// </summary>
  942. /// <typeparam name="T"></typeparam>
  943. /// <returns>``0.</returns>
  944. public T TryResolve<T>()
  945. {
  946. var result = _container.GetRegistration(typeof(T), false);
  947. if (result == null)
  948. {
  949. return default(T);
  950. }
  951. return (T)result.GetInstance();
  952. }
  953. }
  954. }