|
@@ -7,6 +7,7 @@ using System.Text;
|
|
|
using System.Threading.Tasks;
|
|
|
using Avalonia;
|
|
|
using Avalonia.Controls.ApplicationLifetimes;
|
|
|
+using CommunityToolkit.Mvvm.Input;
|
|
|
using PixiEditor.Views.Dialogs;
|
|
|
using PixiEditor.Extensions.Common.Localization;
|
|
|
using PixiEditor.Extensions.CommonApi.UserPreferences.Settings.PixiEditor;
|
|
@@ -23,12 +24,28 @@ namespace PixiEditor.ViewModels.SubViewModels;
|
|
|
internal class UpdateViewModel : SubViewModel<ViewModelMain>
|
|
|
{
|
|
|
public const int MaxRetryCount = 3;
|
|
|
- private bool updateReadyToInstall = false;
|
|
|
-
|
|
|
public UpdateChecker UpdateChecker { get; set; }
|
|
|
|
|
|
public List<UpdateChannel> UpdateChannels { get; } = new List<UpdateChannel>();
|
|
|
|
|
|
+ private UpdateState _updateState = UpdateState.Checking;
|
|
|
+
|
|
|
+ public UpdateState UpdateState
|
|
|
+ {
|
|
|
+ get => _updateState;
|
|
|
+ set
|
|
|
+ {
|
|
|
+ _updateState = value;
|
|
|
+ OnPropertyChanged(nameof(UpdateState));
|
|
|
+ OnPropertyChanged(nameof(IsUpdateAvailable));
|
|
|
+ OnPropertyChanged(nameof(UpdateReadyToInstall));
|
|
|
+ OnPropertyChanged(nameof(IsDownloading));
|
|
|
+ OnPropertyChanged(nameof(IsUpToDate));
|
|
|
+ OnPropertyChanged(nameof(IsFailed));
|
|
|
+ OnPropertyChanged(nameof(UpdateStateString));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private string versionText;
|
|
|
|
|
|
public string VersionText
|
|
@@ -41,22 +58,52 @@ internal class UpdateViewModel : SubViewModel<ViewModelMain>
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public bool UpdateReadyToInstall
|
|
|
+
|
|
|
+ public string UpdateStateString
|
|
|
{
|
|
|
- get => updateReadyToInstall;
|
|
|
- set
|
|
|
+ get => _updateState switch
|
|
|
{
|
|
|
- updateReadyToInstall = value;
|
|
|
- OnPropertyChanged(nameof(UpdateReadyToInstall));
|
|
|
- if (value)
|
|
|
- {
|
|
|
- VersionText =
|
|
|
- new LocalizedString("TO_INSTALL_UPDATE",
|
|
|
- UpdateChecker.LatestReleaseInfo.TagName); // Button shows "Restart" before this text
|
|
|
- }
|
|
|
- }
|
|
|
+ UpdateState.UnableToCheck => new LocalizedString("UP_TO_DATE_UNKNOWN"),
|
|
|
+ UpdateState.Checking => new LocalizedString("CHECKING_FOR_UPDATES"),
|
|
|
+ UpdateState.FailedDownload => new LocalizedString("UPDATE_FAILED_DOWNLOAD"),
|
|
|
+ UpdateState.ReadyToInstall => new LocalizedString("UPDATE_READY_TO_INSTALL"),
|
|
|
+ UpdateState.Downloading => new LocalizedString("DOWNLOADING_UPDATE"),
|
|
|
+ UpdateState.UpdateAvailable => new LocalizedString("UPDATE_AVAILABLE",
|
|
|
+ UpdateChecker.LatestReleaseInfo.TagName),
|
|
|
+ UpdateState.UpToDate => new LocalizedString("UP_TO_DATE"),
|
|
|
+ UpdateState.Failed => new LocalizedString("UPDATE_FAILED"),
|
|
|
+ _ => new LocalizedString("UP_TO_DATE_UNKNOWN")
|
|
|
+ };
|
|
|
}
|
|
|
|
|
|
+ public bool IsUpdateAvailable
|
|
|
+ {
|
|
|
+ get => _updateState == UpdateState.UpdateAvailable;
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool UpdateReadyToInstall
|
|
|
+ {
|
|
|
+ get => _updateState == UpdateState.ReadyToInstall;
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool IsDownloading
|
|
|
+ {
|
|
|
+ get => _updateState == UpdateState.Downloading;
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool IsUpToDate
|
|
|
+ {
|
|
|
+ get => _updateState == UpdateState.UpToDate;
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool IsFailed
|
|
|
+ {
|
|
|
+ get => _updateState == UpdateState.Failed;
|
|
|
+ }
|
|
|
+
|
|
|
+ public AsyncRelayCommand DownloadCommand => new AsyncRelayCommand(Download);
|
|
|
+ public RelayCommand InstallCommand => new RelayCommand(Install);
|
|
|
+
|
|
|
public UpdateViewModel(ViewModelMain owner)
|
|
|
: base(owner)
|
|
|
{
|
|
@@ -73,33 +120,42 @@ internal class UpdateViewModel : SubViewModel<ViewModelMain>
|
|
|
InitUpdateChecker();
|
|
|
}
|
|
|
|
|
|
- public async Task<bool> CheckForUpdate()
|
|
|
+ public async Task CheckForUpdate()
|
|
|
{
|
|
|
if (!IOperatingSystem.Current.IsWindows)
|
|
|
{
|
|
|
- return false;
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
bool updateAvailable = await UpdateChecker.CheckUpdateAvailable();
|
|
|
if (!UpdateChecker.LatestReleaseInfo.WasDataFetchSuccessful ||
|
|
|
string.IsNullOrEmpty(UpdateChecker.LatestReleaseInfo.TagName))
|
|
|
{
|
|
|
- return false;
|
|
|
+ UpdateState = UpdateState.UnableToCheck;
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
+ UpdateState = updateAvailable ? UpdateState.UpdateAvailable : UpdateState.UpToDate;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task Download()
|
|
|
+ {
|
|
|
bool updateCompatible = await UpdateChecker.IsUpdateCompatible();
|
|
|
bool autoUpdateFailed = CheckAutoupdateFailed();
|
|
|
- bool updateFileDoesNotExists = !File.Exists(
|
|
|
- Path.Join(UpdateDownloader.DownloadLocation, $"update-{UpdateChecker.LatestReleaseInfo.TagName}.zip"));
|
|
|
+ bool updateFileDoesNotExists = !AutoUpdateFileExists();
|
|
|
+ bool updateExeDoesNotExists = !UpdateInstallerFileExists();
|
|
|
+
|
|
|
+ if(!updateExeDoesNotExists || !updateFileDoesNotExists)
|
|
|
+ {
|
|
|
+ UpdateState = UpdateState.ReadyToInstall;
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- bool updateExeDoesNotExists = !File.Exists(
|
|
|
- Path.Join(UpdateDownloader.DownloadLocation, $"update-{UpdateChecker.LatestReleaseInfo.TagName}.exe"));
|
|
|
- if (updateAvailable && (updateFileDoesNotExists && updateExeDoesNotExists) || autoUpdateFailed)
|
|
|
+ if ((updateFileDoesNotExists && updateExeDoesNotExists) || autoUpdateFailed)
|
|
|
{
|
|
|
- UpdateReadyToInstall = false;
|
|
|
- VersionText = new LocalizedString("DOWNLOADING_UPDATE");
|
|
|
try
|
|
|
{
|
|
|
+ UpdateState = UpdateState.Downloading;
|
|
|
if (updateCompatible && !autoUpdateFailed)
|
|
|
{
|
|
|
await UpdateDownloader.DownloadReleaseZip(UpdateChecker.LatestReleaseInfo);
|
|
@@ -113,39 +169,46 @@ internal class UpdateViewModel : SubViewModel<ViewModelMain>
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- UpdateReadyToInstall = true;
|
|
|
+ UpdateState = UpdateState.ReadyToInstall;
|
|
|
}
|
|
|
catch (IOException ex)
|
|
|
{
|
|
|
- NoticeDialog.Show("FAILED_DOWNLOADING", "FAILED_DOWNLOADING_TITLE");
|
|
|
- return false;
|
|
|
+ UpdateState = UpdateState.FailedDownload;
|
|
|
}
|
|
|
catch (TaskCanceledException ex)
|
|
|
{
|
|
|
- return false;
|
|
|
+ UpdateState = UpdateState.UpdateAvailable;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ UpdateState = UpdateState.FailedDownload;
|
|
|
}
|
|
|
-
|
|
|
- return true;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- return false;
|
|
|
+ private bool AutoUpdateFileExists()
|
|
|
+ {
|
|
|
+ string path = Path.Join(UpdateDownloader.DownloadLocation,
|
|
|
+ $"update-{UpdateChecker.LatestReleaseInfo.TagName}.zip");
|
|
|
+ return File.Exists(path);
|
|
|
}
|
|
|
|
|
|
- private async void Install()
|
|
|
+ private bool UpdateInstallerFileExists()
|
|
|
{
|
|
|
-#if RELEASE || DEVRELEASE
|
|
|
- if (!PixiEditorSettings.Update.CheckUpdatesOnStartup.Value)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
+ string path = Path.Join(UpdateDownloader.DownloadLocation,
|
|
|
+ $"update-{UpdateChecker.LatestReleaseInfo.TagName}.exe");
|
|
|
+ return File.Exists(path);
|
|
|
+ }
|
|
|
|
|
|
+ private void Install()
|
|
|
+ {
|
|
|
+#if RELEASE || DEVRELEASE
|
|
|
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"));
|
|
|
+ bool updateFileExists = AutoUpdateFileExists();
|
|
|
string exePath = Path.Join(UpdateDownloader.DownloadLocation,
|
|
|
$"update-{UpdateChecker.LatestReleaseInfo.TagName}.exe");
|
|
|
|
|
@@ -166,8 +229,7 @@ internal class UpdateViewModel : SubViewModel<ViewModelMain>
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- ViewModelMain.Current.UpdateSubViewModel.UpdateReadyToInstall = true;
|
|
|
- if (!UpdateInfoExists())
|
|
|
+ /*if (!UpdateInfoExists())
|
|
|
{
|
|
|
CreateUpdateInfo(UpdateChecker.LatestReleaseInfo.TagName);
|
|
|
return;
|
|
@@ -185,7 +247,7 @@ internal class UpdateViewModel : SubViewModel<ViewModelMain>
|
|
|
if (!CanInstallUpdate(UpdateChecker.LatestReleaseInfo.TagName, info) && !updateExeExists)
|
|
|
{
|
|
|
return;
|
|
|
- }
|
|
|
+ }*/
|
|
|
|
|
|
if (updateFileExists && File.Exists(updaterPath))
|
|
|
{
|
|
@@ -275,6 +337,15 @@ internal class UpdateViewModel : SubViewModel<ViewModelMain>
|
|
|
try
|
|
|
{
|
|
|
await CheckForUpdate();
|
|
|
+ if (UpdateState == UpdateState.UpdateAvailable)
|
|
|
+ {
|
|
|
+ bool updateFileExists = AutoUpdateFileExists() || UpdateInstallerFileExists();
|
|
|
+ if (updateFileExists)
|
|
|
+ {
|
|
|
+ UpdateState = UpdateState.ReadyToInstall;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (UpdateChecker.LatestReleaseInfo != null && UpdateChecker.LatestReleaseInfo.TagName ==
|
|
|
VersionHelpers.GetCurrentAssemblyVersionString())
|
|
|
{
|
|
@@ -283,15 +354,13 @@ internal class UpdateViewModel : SubViewModel<ViewModelMain>
|
|
|
}
|
|
|
catch (System.Net.Http.HttpRequestException)
|
|
|
{
|
|
|
- NoticeDialog.Show("COULD_NOT_CHECK_FOR_UPDATES", "UPDATE_CHECK_FAILED");
|
|
|
+ UpdateState = UpdateState.UnableToCheck;
|
|
|
}
|
|
|
catch (Exception e)
|
|
|
{
|
|
|
+ UpdateState = UpdateState.UnableToCheck;
|
|
|
CrashHelper.SendExceptionInfoAsync(e);
|
|
|
- NoticeDialog.Show("COULD_NOT_CHECK_FOR_UPDATES", "UPDATE_CHECK_FAILED");
|
|
|
}
|
|
|
-
|
|
|
- Install();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -397,3 +466,15 @@ internal class UpdateViewModel : SubViewModel<ViewModelMain>
|
|
|
return selectedChannel;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+public enum UpdateState
|
|
|
+{
|
|
|
+ Checking,
|
|
|
+ UnableToCheck,
|
|
|
+ UpdateAvailable,
|
|
|
+ Downloading,
|
|
|
+ FailedDownload,
|
|
|
+ ReadyToInstall,
|
|
|
+ UpToDate,
|
|
|
+ Failed,
|
|
|
+}
|