Files
2026-09-14 21:02:45 +02:00

376 lines
8.7 KiB
C#

using System;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using SpotXInstaller.Models;
using SpotXInstaller.Services;
namespace SpotXInstaller.ViewModels;
public partial class MainViewModel : ViewModelBase
{
private readonly InstallerService _installer = new();
private CancellationTokenSource? _cts;
// ---------------------------------------------------------
// SCREEN STATES
// ---------------------------------------------------------
[ObservableProperty]
private bool _isStepLoading = true;
[ObservableProperty]
private bool _isStepHome;
[ObservableProperty]
private bool _isStepSettings;
[ObservableProperty]
private bool _isStepProgress;
// ---------------------------------------------------------
// POPUP
// ---------------------------------------------------------
[ObservableProperty]
private bool _showPopup;
[ObservableProperty]
private string _popupTitle = "";
[ObservableProperty]
private string _popupMessage = "";
[ObservableProperty]
private string _popupColor = "#8B5CF6";
// ---------------------------------------------------------
// SETTINGS
// ---------------------------------------------------------
[ObservableProperty]
private bool _blockUpdates = true;
[ObservableProperty]
private bool _hidePodcasts = true;
[ObservableProperty]
private bool _hidePremium = true;
[ObservableProperty]
private bool _clearCache;
// ---------------------------------------------------------
// PROGRESS
// ---------------------------------------------------------
[ObservableProperty]
private double _progressValue;
[ObservableProperty]
private string _progressStatus = "Подготовка...";
[ObservableProperty]
private string _miniLog = "";
// ---------------------------------------------------------
// STATE
// ---------------------------------------------------------
[ObservableProperty]
private bool _isInstalling;
public MainViewModel()
{
_ = BootAsync();
}
// ---------------------------------------------------------
// BOOT
// ---------------------------------------------------------
private async Task BootAsync()
{
await Task.Delay(3000);
SwitchTo(home: true);
}
// ---------------------------------------------------------
// NAVIGATION
// ---------------------------------------------------------
private void SwitchTo(
bool loading = false,
bool home = false,
bool settings = false,
bool progress = false)
{
IsStepLoading = loading;
IsStepHome = home;
IsStepSettings = settings;
IsStepProgress = progress;
}
[RelayCommand]
private void GoToSettings()
{
if (IsInstalling)
return;
SwitchTo(settings: true);
}
[RelayCommand]
private void GoBackToHome()
{
if (IsInstalling)
return;
SwitchTo(home: true);
}
[RelayCommand]
private void ClosePopup()
{
ShowPopup = false;
}
// ---------------------------------------------------------
// INSTALL
// ---------------------------------------------------------
[RelayCommand]
private async Task StartInstallAsync()
{
await RunInstallerAsync(isUninstall: false);
}
// ---------------------------------------------------------
// UNINSTALL
// ---------------------------------------------------------
[RelayCommand]
private async Task StartUninstallAsync()
{
await RunInstallerAsync(isUninstall: true);
}
// ---------------------------------------------------------
// CANCEL BUTTON
// ---------------------------------------------------------
[RelayCommand]
private async Task CancelInstallAsync()
{
if (!IsInstalling)
return;
ProgressStatus = "Отмена установки...";
try
{
_cts?.Cancel();
}
catch
{
// Ignore.
}
await Task.CompletedTask;
}
// ---------------------------------------------------------
// WINDOW CLOSE
// ---------------------------------------------------------
public async Task CancelInstallationAsync()
{
if (!IsInstalling)
return;
try
{
ProgressStatus = "Завершение процессов...";
_cts?.Cancel();
// Даём process tree время корректно завершиться.
await Task.Delay(150);
}
catch
{
// Ignore.
}
}
// ---------------------------------------------------------
// MAIN INSTALLER
// ---------------------------------------------------------
private async Task RunInstallerAsync(bool isUninstall)
{
if (IsInstalling)
return;
ProgressValue = 0;
MiniLog = "";
ProgressStatus = isUninstall
? "Подготовка восстановления..."
: "Подготовка установки...";
SwitchTo(progress: true);
_cts?.Dispose();
_cts = new CancellationTokenSource();
IsInstalling = true;
var progress =
new Progress<(int Percent, string Status)>(
p =>
{
ProgressValue = p.Percent;
ProgressStatus = p.Status;
});
var log =
new Progress<string>(
line =>
{
MiniLog = line;
});
try
{
int code;
if (isUninstall)
{
code = await _installer.UninstallAsync(
progress,
log,
_cts.Token);
}
else
{
code = await _installer.InstallAsync(
new InstallOptions(
BlockUpdates,
HidePodcasts,
HidePremium,
ClearCache),
progress,
log,
_cts.Token);
}
IsInstalling = false;
SwitchTo(home: true);
if (code == 0)
{
ShowNotification(
isUninstall
? "ГОТОВО"
: "УСПЕХ",
isUninstall
? "Оригинальный клиент Spotify восстановлен."
: "SpotX успешно установлен.",
isUninstall
? "#8B5CF6"
: "#00E676");
}
else
{
string errorText =
MiniLog.Length > 500
? MiniLog[..500]
: MiniLog;
ShowNotification(
"ОШИБКА",
$"Скрипт завершился с кодом {code}.\n\n{errorText}",
"#FF3B30");
}
}
catch (OperationCanceledException)
{
IsInstalling = false;
SwitchTo(home: true);
ShowNotification(
"ОТМЕНЕНО",
"Установка была отменена.",
"#FFB300");
}
catch (Exception ex)
{
IsInstalling = false;
SwitchTo(home: true);
ShowNotification(
"ОШИБКА",
ex.Message,
"#FF3B30");
}
finally
{
IsInstalling = false;
_cts?.Dispose();
_cts = null;
}
}
// ---------------------------------------------------------
// POPUP
// ---------------------------------------------------------
private void ShowNotification(
string title,
string message,
string hexColor)
{
PopupTitle = title;
PopupMessage = message;
PopupColor = hexColor;
ShowPopup = true;
}
// ---------------------------------------------------------
// DISPOSE
// ---------------------------------------------------------
public async Task DisposeAsync()
{
if (!IsInstalling)
return;
try
{
_cts?.Cancel();
await Task.Delay(150);
}
catch
{
// Ignore.
}
_cts?.Dispose();
_cts = null;
IsInstalling = false;
}
}