UpdateViewModel.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. using System;
  2. using System.ComponentModel;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Threading.Tasks;
  7. using System.Windows;
  8. using PixiEditor.Helpers;
  9. using PixiEditor.Models.Dialogs;
  10. using PixiEditor.Models.Processes;
  11. using PixiEditor.Models.UserPreferences;
  12. using PixiEditor.UpdateModule;
  13. namespace PixiEditor.ViewModels.SubViewModels.Main
  14. {
  15. public class UpdateViewModel : SubViewModel<ViewModelMain>
  16. {
  17. private bool updateReadyToInstall = false;
  18. public UpdateChecker UpdateChecker { get; set; }
  19. public UpdateChannel[] UpdateChannels { get; } = new UpdateChannel[2];
  20. public RelayCommand RestartApplicationCommand { get; set; }
  21. private string versionText;
  22. public string VersionText
  23. {
  24. get => versionText;
  25. set
  26. {
  27. versionText = value;
  28. RaisePropertyChanged(nameof(VersionText));
  29. }
  30. }
  31. public bool UpdateReadyToInstall
  32. {
  33. get => updateReadyToInstall;
  34. set
  35. {
  36. updateReadyToInstall = value;
  37. RaisePropertyChanged(nameof(UpdateReadyToInstall));
  38. if (value)
  39. {
  40. VersionText = $"to install update (current {VersionHelpers.GetCurrentAssemblyVersionString()})"; // Button shows "Restart" before this text
  41. }
  42. }
  43. }
  44. public UpdateViewModel(ViewModelMain owner)
  45. : base(owner)
  46. {
  47. Owner.OnStartupEvent += Owner_OnStartupEvent;
  48. RestartApplicationCommand = new RelayCommand(RestartApplication);
  49. IPreferences.Current.AddCallback<string>("UpdateChannel", (val) => UpdateChecker.Channel = GetUpdateChannel(val));
  50. InitUpdateChecker();
  51. }
  52. public async Task<bool> CheckForUpdate()
  53. {
  54. bool updateAvailable = await UpdateChecker.CheckUpdateAvailable();
  55. bool updateCompatible = await UpdateChecker.IsUpdateCompatible();
  56. bool updateFileDoesNotExists = !File.Exists(
  57. Path.Join(UpdateDownloader.DownloadLocation, $"update-{UpdateChecker.LatestReleaseInfo.TagName}.zip"));
  58. bool updateExeDoesNotExists = !File.Exists(
  59. Path.Join(UpdateDownloader.DownloadLocation, $"update-{UpdateChecker.LatestReleaseInfo.TagName}.exe"));
  60. if (updateAvailable && updateFileDoesNotExists && updateExeDoesNotExists)
  61. {
  62. VersionText = "Downloading update...";
  63. if (updateCompatible)
  64. {
  65. await UpdateDownloader.DownloadReleaseZip(UpdateChecker.LatestReleaseInfo);
  66. }
  67. else
  68. {
  69. await UpdateDownloader.DownloadInstaller(UpdateChecker.LatestReleaseInfo);
  70. }
  71. UpdateReadyToInstall = true;
  72. return true;
  73. }
  74. return false;
  75. }
  76. private static void AskToInstall()
  77. {
  78. #if RELEASE
  79. if (IPreferences.Current.GetPreference("CheckUpdatesOnStartup", true))
  80. {
  81. string dir = AppDomain.CurrentDomain.BaseDirectory;
  82. UpdateDownloader.CreateTempDirectory();
  83. bool updateZipExists = Directory.GetFiles(UpdateDownloader.DownloadLocation, "update-*.zip").Length > 0;
  84. string[] updateExeFiles = Directory.GetFiles(UpdateDownloader.DownloadLocation, "update-*.exe");
  85. bool updateExeExists = updateExeFiles.Length > 0;
  86. string updaterPath = Path.Join(dir, "PixiEditor.UpdateInstaller.exe");
  87. if (updateZipExists || updateExeExists)
  88. {
  89. ViewModelMain.Current.UpdateSubViewModel.UpdateReadyToInstall = true;
  90. var result = ConfirmationDialog.Show("Update is ready to install. Do you want to install it now?");
  91. if (result == Models.Enums.ConfirmationType.Yes)
  92. {
  93. if (updateZipExists && File.Exists(updaterPath))
  94. {
  95. InstallHeadless(updaterPath);
  96. }
  97. else if (updateExeExists)
  98. {
  99. OpenExeInstaller(updateExeFiles[0]);
  100. }
  101. }
  102. }
  103. }
  104. #endif
  105. }
  106. private static void InstallHeadless(string updaterPath)
  107. {
  108. try
  109. {
  110. ProcessHelper.RunAsAdmin(updaterPath);
  111. Application.Current.Shutdown();
  112. }
  113. catch (Win32Exception)
  114. {
  115. MessageBox.Show(
  116. "Couldn't update without administrator rights.",
  117. "Insufficient permissions",
  118. MessageBoxButton.OK,
  119. MessageBoxImage.Error);
  120. }
  121. }
  122. private static void OpenExeInstaller(string updateExeFile)
  123. {
  124. bool alreadyUpdated = VersionHelpers.GetCurrentAssemblyVersion().ToString() ==
  125. updateExeFile.Split('-')[1].Split(".exe")[0];
  126. if (!alreadyUpdated)
  127. {
  128. RestartToUpdate(updateExeFile);
  129. }
  130. else
  131. {
  132. File.Delete(updateExeFile);
  133. }
  134. }
  135. private static void RestartToUpdate(string updateExeFile)
  136. {
  137. Process.Start(updateExeFile);
  138. Application.Current.Shutdown();
  139. }
  140. private static void RestartApplication(object parameter)
  141. {
  142. try
  143. {
  144. ProcessHelper.RunAsAdmin(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "PixiEditor.UpdateInstaller.exe"));
  145. Application.Current.Shutdown();
  146. }
  147. catch (Win32Exception)
  148. {
  149. NoticeDialog.Show("Couldn't update without administrator rights.", "Insufficient permissions");
  150. }
  151. }
  152. private void Owner_OnStartupEvent(object sender, EventArgs e)
  153. {
  154. ConditionalUPDATE();
  155. }
  156. [Conditional("UPDATE")]
  157. private async void ConditionalUPDATE()
  158. {
  159. if (IPreferences.Current.GetPreference("CheckUpdatesOnStartup", true))
  160. {
  161. try
  162. {
  163. await CheckForUpdate();
  164. }
  165. catch (System.Net.Http.HttpRequestException)
  166. {
  167. NoticeDialog.Show("Could not check if there's an update available");
  168. }
  169. AskToInstall();
  170. }
  171. }
  172. private void InitUpdateChecker()
  173. {
  174. UpdateChannels[0] = new UpdateChannel("Release", "PixiEditor", "PixiEditor");
  175. UpdateChannels[1] = new UpdateChannel("Development", "PixiEditor", "PixiEditor-development-channel");
  176. string updateChannel = IPreferences.Current.GetPreference<string>("UpdateChannel");
  177. string version = VersionHelpers.GetCurrentAssemblyVersionString();
  178. UpdateChecker = new UpdateChecker(version, GetUpdateChannel(updateChannel));
  179. VersionText = $"Version {version}";
  180. }
  181. private UpdateChannel GetUpdateChannel(string channelName)
  182. {
  183. UpdateChannel selectedChannel = UpdateChannels.FirstOrDefault(x => x.Name == channelName, UpdateChannels[0]);
  184. return selectedChannel;
  185. }
  186. }
  187. }