123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Diagnostics;
- using System.IO;
- using System.Linq;
- using System.Threading.Tasks;
- using Avalonia;
- using Avalonia.Controls.ApplicationLifetimes;
- using PixiEditor.AvaloniaUI.Helpers;
- using PixiEditor.AvaloniaUI.Models.Commands.Attributes.Commands;
- using PixiEditor.AvaloniaUI.Models.Dialogs;
- using PixiEditor.AvaloniaUI.Views.Dialogs;
- using PixiEditor.Extensions.Common.Localization;
- using PixiEditor.Extensions.CommonApi.UserPreferences;
- using PixiEditor.Platform;
- using PixiEditor.UpdateModule;
- namespace PixiEditor.AvaloniaUI.ViewModels.SubViewModels;
- internal class UpdateViewModel : SubViewModel<ViewModelMain>
- {
- private bool updateReadyToInstall = false;
- public UpdateChecker UpdateChecker { get; set; }
- public List<UpdateChannel> UpdateChannels { get; } = new List<UpdateChannel>();
- private string versionText;
- public string VersionText
- {
- get => versionText;
- set
- {
- versionText = value;
- OnPropertyChanged(nameof(VersionText));
- }
- }
- public bool UpdateReadyToInstall
- {
- get => updateReadyToInstall;
- set
- {
- updateReadyToInstall = value;
- OnPropertyChanged(nameof(UpdateReadyToInstall));
- if (value)
- {
- VersionText = new LocalizedString("TO_INSTALL_UPDATE", UpdateChecker.LatestReleaseInfo.TagName); // Button shows "Restart" before this text
- }
- }
- }
- public UpdateViewModel(ViewModelMain owner)
- : base(owner)
- {
- Owner.OnStartupEvent += Owner_OnStartupEvent;
- IPreferences.Current.AddCallback<string>("UpdateChannel", val =>
- {
- string prevChannel = UpdateChecker.Channel.ApiUrl;
- UpdateChecker.Channel = GetUpdateChannel(val);
- if (prevChannel != UpdateChecker.Channel.ApiUrl)
- {
- ConditionalUPDATE();
- }
- });
- InitUpdateChecker();
- }
- public async Task<bool> CheckForUpdate()
- {
- bool updateAvailable = await UpdateChecker.CheckUpdateAvailable();
- bool updateCompatible = await UpdateChecker.IsUpdateCompatible();
- bool updateFileDoesNotExists = !File.Exists(
- Path.Join(UpdateDownloader.DownloadLocation, $"update-{UpdateChecker.LatestReleaseInfo.TagName}.zip"));
- bool updateExeDoesNotExists = !File.Exists(
- Path.Join(UpdateDownloader.DownloadLocation, $"update-{UpdateChecker.LatestReleaseInfo.TagName}.exe"));
- if (updateAvailable && updateFileDoesNotExists && updateExeDoesNotExists)
- {
- UpdateReadyToInstall = false;
- VersionText = new LocalizedString("DOWNLOADING_UPDATE");
- try
- {
- if (updateCompatible)
- {
- await UpdateDownloader.DownloadReleaseZip(UpdateChecker.LatestReleaseInfo);
- }
- else
- {
- await UpdateDownloader.DownloadInstaller(UpdateChecker.LatestReleaseInfo);
- }
- UpdateReadyToInstall = true;
- }
- catch (IOException ex)
- {
- NoticeDialog.Show("FAILED_DOWNLOADING_TITLE", "FAILED_DOWNLOADING");
- return false;
- }
- catch(TaskCanceledException ex)
- {
- return false;
- }
- return true;
- }
- return false;
- }
- private void AskToInstall()
- {
- #if RELEASE || DEVRELEASE
- if (IPreferences.Current.GetPreference("CheckUpdatesOnStartup", true))
- {
- string dir = AppDomain.CurrentDomain.BaseDirectory;
-
- UpdateDownloader.CreateTempDirectory();
- if(UpdateChecker.LatestReleaseInfo == null || string.IsNullOrEmpty(UpdateChecker.LatestReleaseInfo.TagName)) return;
- bool updateFileExists = File.Exists(
- Path.Join(UpdateDownloader.DownloadLocation, $"update-{UpdateChecker.LatestReleaseInfo.TagName}.zip"));
- string exePath = Path.Join(UpdateDownloader.DownloadLocation,
- $"update-{UpdateChecker.LatestReleaseInfo.TagName}.exe");
- bool updateExeExists = File.Exists(exePath);
- if (updateExeExists && !UpdateChecker.VersionDifferent(UpdateChecker.LatestReleaseInfo.TagName, UpdateChecker.CurrentVersionTag))
- {
- File.Delete(exePath);
- updateExeExists = false;
- }
- string updaterPath = Path.Join(dir, "PixiEditor.UpdateInstaller.exe");
- if (updateFileExists || updateExeExists)
- {
- ViewModelMain.Current.UpdateSubViewModel.UpdateReadyToInstall = true;
- var result = ConfirmationDialog.Show("UPDATE_READY", "NEW_UPDATE");
- result.Wait();
- if (result.Result == ConfirmationType.Yes)
- {
- if (updateFileExists && File.Exists(updaterPath))
- {
- InstallHeadless(updaterPath);
- }
- else if (updateExeExists)
- {
- OpenExeInstaller(exePath);
- }
- }
- }
- }
- #endif
- }
- private static void InstallHeadless(string updaterPath)
- {
- try
- {
- ProcessHelper.RunAsAdmin(updaterPath);
- Shutdown();
- }
- catch (Win32Exception)
- {
- NoticeDialog.Show(
- "COULD_NOT_UPDATE_WITHOUT_ADMIN",
- "INSUFFICIENT_PERMISSIONS");
- }
- }
- private static void OpenExeInstaller(string updateExeFile)
- {
- bool alreadyUpdated = VersionHelpers.GetCurrentAssemblyVersion().ToString() ==
- updateExeFile.Split('-')[1].Split(".exe")[0];
- if (!alreadyUpdated)
- {
- RestartToUpdate(updateExeFile);
- }
- else
- {
- File.Delete(updateExeFile);
- }
- }
- private static void RestartToUpdate(string updateExeFile)
- {
- Process.Start(updateExeFile);
- Shutdown();
- }
- private static void Shutdown()
- {
- if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
- desktop.Shutdown();
- }
- [Command.Internal("PixiEditor.Restart")]
- public static void RestartApplication()
- {
- try
- {
- ProcessHelper.RunAsAdmin(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "PixiEditor.UpdateInstaller.exe"));
- Shutdown();
- }
- catch (Win32Exception)
- {
- NoticeDialog.Show("COULD_NOT_UPDATE_WITHOUT_ADMIN", "INSUFFICIENT_PERMISSIONS");
- }
- }
- private void Owner_OnStartupEvent(object sender, EventArgs e)
- {
- ConditionalUPDATE();
- }
- [Conditional("UPDATE")]
- private async void ConditionalUPDATE()
- {
- if (IPreferences.Current.GetPreference("CheckUpdatesOnStartup", true))
- {
- try
- {
- await CheckForUpdate();
- }
- catch (System.Net.Http.HttpRequestException)
- {
- NoticeDialog.Show("COULD_NOT_CHECK_FOR_UPDATES", "UPDATE_CHECK_FAILED");
- }
- catch (Exception e)
- {
- CrashHelper.SendExceptionInfoToWebhookAsync(e);
- NoticeDialog.Show("COULD_NOT_CHECK_FOR_UPDATES", "UPDATE_CHECK_FAILED");
- }
- AskToInstall();
- }
- }
- private void InitUpdateChecker()
- {
- #if UPDATE
- UpdateChannels.Add(new UpdateChannel("Release", "PixiEditor", "PixiEditor"));
- UpdateChannels.Add(new UpdateChannel("Development", "PixiEditor", "PixiEditor-development-channel"));
- #else
- string platformName = IPlatform.Current.Name;
- UpdateChannels.Add(new UpdateChannel(platformName, "", ""));
- #endif
- string updateChannel = IPreferences.Current.GetPreference<string>("UpdateChannel");
- string version = VersionHelpers.GetCurrentAssemblyVersionString();
- UpdateChecker = new UpdateChecker(version, GetUpdateChannel(updateChannel));
- VersionText = new LocalizedString("VERSION", version);
- }
- private UpdateChannel GetUpdateChannel(string channelName)
- {
- UpdateChannel selectedChannel = UpdateChannels.FirstOrDefault(x => x.Name == channelName, UpdateChannels[0]);
- return selectedChannel;
- }
- }
|