- UpdateService (Core): проверка Gitea releases/latest + скачивание установщика с CDN - UpdateWindow/VM: уведомление «доступно обновление», тихая установка поверх с перезапуском - ShellView: проверка при старте (один раз, офлайн/ошибки игнорируются) Закрывает пробел: Avalonia-клиент раньше не умел обновляться (апдейтер был только в WinForms). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
96 lines
3.2 KiB
C#
96 lines
3.2 KiB
C#
using System;
|
||
using System.Diagnostics;
|
||
using System.Threading.Tasks;
|
||
using Avalonia.Controls.ApplicationLifetimes;
|
||
using CommunityToolkit.Mvvm.ComponentModel;
|
||
using CommunityToolkit.Mvvm.Input;
|
||
using Elfisa.Core;
|
||
|
||
namespace Elfisa.Avalonia.ViewModels;
|
||
|
||
/// <summary>Окно «Доступно обновление»: скачивает установщик и запускает его.</summary>
|
||
public partial class UpdateViewModel : ViewModelBase
|
||
{
|
||
private readonly UpdateInfo _info;
|
||
private readonly Action _close;
|
||
|
||
public UpdateViewModel(UpdateInfo info, Action close)
|
||
{
|
||
_info = info;
|
||
_close = close;
|
||
}
|
||
|
||
public string Message =>
|
||
$"Установлена версия {_info.CurrentVersion}.\nДоступна новая версия {_info.LatestVersion}.";
|
||
|
||
[ObservableProperty] private bool _busy;
|
||
[ObservableProperty] private double _progress;
|
||
[ObservableProperty] private string _status = "";
|
||
|
||
[RelayCommand]
|
||
private void Later() => _close();
|
||
|
||
[RelayCommand]
|
||
private async Task UpdateAsync()
|
||
{
|
||
// Не-Windows: установщика нет — открываем страницу релиза в браузере.
|
||
if (!OperatingSystem.IsWindows())
|
||
{
|
||
OpenUrl(string.IsNullOrWhiteSpace(_info.ReleaseUrl) ? "https://cdn.24pharmdata.ru" : _info.ReleaseUrl);
|
||
_close();
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
Busy = true;
|
||
Status = "Скачивание обновления…";
|
||
var progress = new Progress<double>(p =>
|
||
{
|
||
Progress = p;
|
||
Status = $"Скачивание обновления… {p:0}%";
|
||
});
|
||
var setupPath = await UpdateService.DownloadSetupAsync(progress);
|
||
|
||
Status = "Запуск установки…";
|
||
LaunchInstallerAndExit(setupPath);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Busy = false;
|
||
Status = "Не удалось обновить: " + ex.Message;
|
||
}
|
||
}
|
||
|
||
/// <summary>Тихая установка поверх + перезапуск приложения, затем закрываем себя.</summary>
|
||
private void LaunchInstallerAndExit(string setupPath)
|
||
{
|
||
var exe = Process.GetCurrentProcess().MainModule?.FileName;
|
||
var inner = $"\"{setupPath}\" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART";
|
||
if (!string.IsNullOrEmpty(exe))
|
||
inner += $" && start \"\" \"{exe}\"";
|
||
|
||
Process.Start(new ProcessStartInfo("cmd.exe")
|
||
{
|
||
Arguments = "/c \"" + inner + "\"",
|
||
UseShellExecute = false,
|
||
CreateNoWindow = true,
|
||
});
|
||
|
||
// Закрываем приложение, чтобы установщик заменил файлы (CloseApplications=yes).
|
||
if (global::Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime d)
|
||
d.Shutdown();
|
||
else
|
||
Environment.Exit(0);
|
||
}
|
||
|
||
private static void OpenUrl(string url)
|
||
{
|
||
try
|
||
{
|
||
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
|
||
}
|
||
catch { /* игнорируем */ }
|
||
}
|
||
}
|