Added checking for updates
This commit is contained in:
parent
cc15863e81
commit
5ec6525257
19 changed files with 1231 additions and 100 deletions
364
ViewModels/MainViewModel.cs
Normal file
364
ViewModels/MainViewModel.cs
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Input;
|
||||
using MossyUpdater.Services;
|
||||
using Ookii.Dialogs.Wpf;
|
||||
|
||||
namespace MossyUpdater.ViewModels
|
||||
{
|
||||
public class MainViewModel : ViewModelBase, IDisposable
|
||||
{
|
||||
private readonly IDownloadService _downloadService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IQuotesService _quotesService;
|
||||
private CancellationTokenSource? _cancellationTokenSource;
|
||||
private System.Windows.Threading.DispatcherTimer? _quoteTimer;
|
||||
|
||||
private string _url = "https://git.snakedesert.se/SawatoMosswartsEnjoyersClub/MosswartMassacre/raw/branch/spawn-detection/MosswartMassacre/bin/Release/MosswartMassacre.dll";
|
||||
private string _folder = string.Empty;
|
||||
private string _filename = "MosswartMassacre.dll";
|
||||
private string _statusMessage = string.Empty;
|
||||
private System.Windows.Media.Brush _statusColor = System.Windows.Media.Brushes.Green;
|
||||
private double _progressValue = 0;
|
||||
private bool _isProgressVisible = false;
|
||||
private bool _isDownloading = false;
|
||||
private string _updateStatus = string.Empty;
|
||||
private bool _updateAvailable = false;
|
||||
private string _currentQuote = string.Empty;
|
||||
private double _quoteOpacity = 1.0;
|
||||
|
||||
public MainViewModel(IDownloadService downloadService, ISettingsService settingsService, ILogger logger, IQuotesService quotesService)
|
||||
{
|
||||
_downloadService = downloadService ?? throw new ArgumentNullException(nameof(downloadService));
|
||||
_settingsService = settingsService ?? throw new ArgumentNullException(nameof(settingsService));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_quotesService = quotesService ?? throw new ArgumentNullException(nameof(quotesService));
|
||||
|
||||
BrowseCommand = new RelayCommand(BrowseFolder);
|
||||
DownloadCommand = new AsyncRelayCommand(DownloadAndUnblock, CanDownload);
|
||||
CancelCommand = new RelayCommand(CancelDownload, () => IsDownloading);
|
||||
CheckUpdatesCommand = new AsyncRelayCommand(CheckForUpdates);
|
||||
|
||||
InitializeQuoteRotation();
|
||||
_ = LoadSettingsAsync();
|
||||
}
|
||||
|
||||
public string Url
|
||||
{
|
||||
get => _url;
|
||||
set => SetProperty(ref _url, value);
|
||||
}
|
||||
|
||||
public string Folder
|
||||
{
|
||||
get => _folder;
|
||||
set => SetProperty(ref _folder, value);
|
||||
}
|
||||
|
||||
public string Filename
|
||||
{
|
||||
get => _filename;
|
||||
set => SetProperty(ref _filename, value);
|
||||
}
|
||||
|
||||
public string StatusMessage
|
||||
{
|
||||
get => _statusMessage;
|
||||
set => SetProperty(ref _statusMessage, value);
|
||||
}
|
||||
|
||||
public System.Windows.Media.Brush StatusColor
|
||||
{
|
||||
get => _statusColor;
|
||||
set => SetProperty(ref _statusColor, value);
|
||||
}
|
||||
|
||||
public double ProgressValue
|
||||
{
|
||||
get => _progressValue;
|
||||
set => SetProperty(ref _progressValue, value);
|
||||
}
|
||||
|
||||
public bool IsProgressVisible
|
||||
{
|
||||
get => _isProgressVisible;
|
||||
set => SetProperty(ref _isProgressVisible, value);
|
||||
}
|
||||
|
||||
public bool IsDownloading
|
||||
{
|
||||
get => _isDownloading;
|
||||
set
|
||||
{
|
||||
SetProperty(ref _isDownloading, value);
|
||||
OnPropertyChanged(nameof(CanInteract));
|
||||
}
|
||||
}
|
||||
|
||||
public string UpdateStatus
|
||||
{
|
||||
get => _updateStatus;
|
||||
set => SetProperty(ref _updateStatus, value);
|
||||
}
|
||||
|
||||
public bool UpdateAvailable
|
||||
{
|
||||
get => _updateAvailable;
|
||||
set => SetProperty(ref _updateAvailable, value);
|
||||
}
|
||||
|
||||
public string CurrentQuote
|
||||
{
|
||||
get => _currentQuote;
|
||||
set => SetProperty(ref _currentQuote, value);
|
||||
}
|
||||
|
||||
public double QuoteOpacity
|
||||
{
|
||||
get => _quoteOpacity;
|
||||
set => SetProperty(ref _quoteOpacity, value);
|
||||
}
|
||||
|
||||
public bool CanInteract => !IsDownloading;
|
||||
|
||||
public ICommand BrowseCommand { get; }
|
||||
public ICommand DownloadCommand { get; }
|
||||
public ICommand CancelCommand { get; }
|
||||
public ICommand CheckUpdatesCommand { get; }
|
||||
|
||||
private void BrowseFolder()
|
||||
{
|
||||
var dialog = new VistaFolderBrowserDialog
|
||||
{
|
||||
Description = "Select a destination folder",
|
||||
UseDescriptionForTitle = true,
|
||||
SelectedPath = Folder
|
||||
};
|
||||
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
Folder = dialog.SelectedPath;
|
||||
_ = SaveSettingsAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanDownload()
|
||||
{
|
||||
return !IsDownloading &&
|
||||
!string.IsNullOrWhiteSpace(Url) &&
|
||||
!string.IsNullOrWhiteSpace(Folder) &&
|
||||
!string.IsNullOrWhiteSpace(Filename);
|
||||
}
|
||||
|
||||
private async Task DownloadAndUnblock()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Url) || string.IsNullOrWhiteSpace(Folder) || string.IsNullOrWhiteSpace(Filename))
|
||||
{
|
||||
SetStatus("Please fill in all fields.", System.Windows.Media.Brushes.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
var fullPath = Path.Combine(Folder, Filename);
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
try
|
||||
{
|
||||
IsDownloading = true;
|
||||
IsProgressVisible = true;
|
||||
ProgressValue = 0;
|
||||
|
||||
var progress = new Progress<DownloadProgress>(OnDownloadProgress);
|
||||
var result = await _downloadService.DownloadFileAsync(Url, fullPath, progress, _cancellationTokenSource.Token);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
_downloadService.UnblockFile(fullPath);
|
||||
SetStatus($"Downloaded and unblocked successfully!\n{fullPath}\nSize: {FormatBytes(result.BytesDownloaded)}, Duration: {result.Duration:mm\\:ss}", System.Windows.Media.Brushes.Green);
|
||||
ProgressValue = 100;
|
||||
|
||||
await CheckForUpdates();
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(result.ErrorMessage))
|
||||
{
|
||||
SetStatus($"Download failed: {result.ErrorMessage}", System.Windows.Media.Brushes.Red);
|
||||
ProgressValue = 0;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SetStatus($"Unexpected error: {ex.Message}", System.Windows.Media.Brushes.Red);
|
||||
ProgressValue = 0;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsDownloading = false;
|
||||
_cancellationTokenSource?.Dispose();
|
||||
_cancellationTokenSource = null;
|
||||
|
||||
await Task.Delay(3000);
|
||||
IsProgressVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelDownload()
|
||||
{
|
||||
_cancellationTokenSource?.Cancel();
|
||||
SetStatus("Download cancelled by user.", System.Windows.Media.Brushes.Orange);
|
||||
}
|
||||
|
||||
private async Task CheckForUpdates()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Url) || string.IsNullOrWhiteSpace(Folder) || string.IsNullOrWhiteSpace(Filename))
|
||||
{
|
||||
UpdateStatus = "";
|
||||
UpdateAvailable = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var localPath = Path.Combine(Folder, Filename);
|
||||
|
||||
try
|
||||
{
|
||||
var updateInfo = await _downloadService.CheckForUpdatesAsync(Url, localPath);
|
||||
|
||||
if (!string.IsNullOrEmpty(updateInfo.ErrorMessage))
|
||||
{
|
||||
UpdateStatus = $"Update check failed: {updateInfo.ErrorMessage}";
|
||||
UpdateAvailable = false;
|
||||
}
|
||||
else if (updateInfo.UpdateAvailable)
|
||||
{
|
||||
UpdateStatus = "Update available! Remote file is newer or different.";
|
||||
UpdateAvailable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateStatus = "File is up to date.";
|
||||
UpdateAvailable = false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateStatus = $"Update check error: {ex.Message}";
|
||||
UpdateAvailable = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDownloadProgress(DownloadProgress progress)
|
||||
{
|
||||
ProgressValue = progress.ProgressPercentage;
|
||||
SetStatus(progress.Status, System.Windows.Media.Brushes.Blue);
|
||||
}
|
||||
|
||||
private void SetStatus(string message, System.Windows.Media.Brush color)
|
||||
{
|
||||
StatusMessage = message;
|
||||
StatusColor = color;
|
||||
}
|
||||
|
||||
private async Task LoadSettingsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await _settingsService.LoadSettingsAsync();
|
||||
Url = settings.DefaultUrl;
|
||||
Folder = settings.LastUsedFolder;
|
||||
Filename = settings.DefaultFilename;
|
||||
|
||||
if (settings.CheckForUpdatesOnStartup && !string.IsNullOrWhiteSpace(Url) && !string.IsNullOrWhiteSpace(Folder) && !string.IsNullOrWhiteSpace(Filename))
|
||||
{
|
||||
await CheckForUpdates();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await _logger.LogErrorAsync("Failed to load settings", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveSettingsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = new AppSettings
|
||||
{
|
||||
DefaultUrl = Url,
|
||||
LastUsedFolder = Folder,
|
||||
DefaultFilename = Filename,
|
||||
CheckForUpdatesOnStartup = true,
|
||||
DownloadTimeoutMinutes = 10
|
||||
};
|
||||
|
||||
await _settingsService.SaveSettingsAsync(settings);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await _logger.LogErrorAsync("Failed to save settings", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatBytes(long bytes)
|
||||
{
|
||||
string[] suffixes = { "B", "KB", "MB", "GB", "TB" };
|
||||
int counter = 0;
|
||||
decimal number = bytes;
|
||||
|
||||
while (Math.Round(number / 1024) >= 1)
|
||||
{
|
||||
number /= 1024;
|
||||
counter++;
|
||||
}
|
||||
|
||||
return $"{number:n1} {suffixes[counter]}";
|
||||
}
|
||||
|
||||
private void InitializeQuoteRotation()
|
||||
{
|
||||
CurrentQuote = _quotesService.GetNextQuote();
|
||||
|
||||
_quoteTimer = new System.Windows.Threading.DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(5)
|
||||
};
|
||||
_quoteTimer.Tick += OnQuoteTimerTick;
|
||||
_quoteTimer.Start();
|
||||
}
|
||||
|
||||
private async void OnQuoteTimerTick(object? sender, EventArgs e)
|
||||
{
|
||||
await RotateQuoteWithFade();
|
||||
}
|
||||
|
||||
private async Task RotateQuoteWithFade()
|
||||
{
|
||||
const double fadeOutDuration = 300;
|
||||
const double fadeInDuration = 300;
|
||||
const int fadeSteps = 30;
|
||||
|
||||
var fadeOutDelay = TimeSpan.FromMilliseconds(fadeOutDuration / fadeSteps);
|
||||
var fadeInDelay = TimeSpan.FromMilliseconds(fadeInDuration / fadeSteps);
|
||||
|
||||
for (int i = fadeSteps; i >= 0; i--)
|
||||
{
|
||||
QuoteOpacity = (double)i / fadeSteps;
|
||||
await Task.Delay(fadeOutDelay);
|
||||
}
|
||||
|
||||
CurrentQuote = _quotesService.GetNextQuote();
|
||||
|
||||
for (int i = 0; i <= fadeSteps; i++)
|
||||
{
|
||||
QuoteOpacity = (double)i / fadeSteps;
|
||||
await Task.Delay(fadeInDelay);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_quoteTimer?.Stop();
|
||||
_quoteTimer = null;
|
||||
_cancellationTokenSource?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue