mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
186 lines
6.6 KiB
C#
186 lines
6.6 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Net.Http;
|
|
using System.Reactive;
|
|
using System.Reactive.Disposables;
|
|
using System.Reactive.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Avalonia.Media;
|
|
using Avalonia.Threading;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
using ReactiveUI;
|
|
using ReactiveUI.Fody.Helpers;
|
|
using Wabbajack.App.Messages;
|
|
using Wabbajack.App.ViewModels.SubViewModels;
|
|
using Wabbajack.Common;
|
|
using Wabbajack.DTOs;
|
|
using Wabbajack.DTOs.DownloadStates;
|
|
using Wabbajack.DTOs.JsonConverters;
|
|
using Wabbajack.Installer;
|
|
using Wabbajack.RateLimiter;
|
|
|
|
namespace Wabbajack.App.ViewModels
|
|
{
|
|
public class StandardInstallationViewModel : ViewModelBase, IReceiver<StartInstallation>
|
|
{
|
|
private readonly IServiceProvider _provider;
|
|
private readonly GameLocator _locator;
|
|
private IServiceScope _scope;
|
|
private InstallerConfiguration _config;
|
|
private StandardInstaller _installer;
|
|
private readonly ILogger<StandardInstallationViewModel> _logger;
|
|
private readonly DTOSerializer _dtos;
|
|
private SlideViewModel[] _slides = Array.Empty<SlideViewModel>();
|
|
private readonly HttpClient _httpClient;
|
|
private Timer _slideTimer;
|
|
private int _currentSlideIndex;
|
|
|
|
[Reactive]
|
|
public SlideViewModel Slide { get; set; }
|
|
|
|
[Reactive]
|
|
public ReactiveCommand<Unit,Unit> NextCommand { get; set; }
|
|
|
|
[Reactive]
|
|
public ReactiveCommand<Unit, Unit> PrevCommand { get; set; }
|
|
|
|
[Reactive]
|
|
public ReactiveCommand<Unit, bool> PauseCommand { get; set; }
|
|
|
|
[Reactive]
|
|
public ReactiveCommand<Unit, bool> PlayCommand { get; set; }
|
|
|
|
[Reactive] public bool IsPlaying { get; set; } = true;
|
|
|
|
[Reactive] public string StatusText { get; set; } = "";
|
|
[Reactive] public Percent StepsProgress { get; set; } = Percent.Zero;
|
|
[Reactive] public Percent StepProgress { get; set; } = Percent.Zero;
|
|
|
|
public StandardInstallationViewModel(ILogger<StandardInstallationViewModel> logger, IServiceProvider provider, GameLocator locator, DTOSerializer dtos, HttpClient httpClient)
|
|
{
|
|
_provider = provider;
|
|
_locator = locator;
|
|
_logger = logger;
|
|
_dtos = dtos;
|
|
_httpClient = httpClient;
|
|
Activator = new ViewModelActivator();
|
|
|
|
this.WhenActivated(disposables => {
|
|
_slideTimer = new Timer(_ =>
|
|
{
|
|
if (IsPlaying) NextSlide(1);
|
|
}, null, TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(5));
|
|
|
|
_currentSlideIndex = 0;
|
|
_slideTimer.DisposeWith(disposables);
|
|
|
|
NextCommand = ReactiveCommand.Create(() => NextSlide(1))
|
|
.DisposeWith(disposables);
|
|
PrevCommand = ReactiveCommand.Create(() => NextSlide(-1))
|
|
.DisposeWith(disposables);
|
|
PauseCommand = ReactiveCommand.Create(() => IsPlaying = false,
|
|
this.ObservableForProperty(vm => vm.IsPlaying, skipInitial:false)
|
|
.Select(v => v.Value))
|
|
.DisposeWith(disposables);
|
|
|
|
PlayCommand = ReactiveCommand.Create(() => IsPlaying = true,
|
|
this.ObservableForProperty(vm => vm.IsPlaying, skipInitial:false)
|
|
.Select(v => !v.Value))
|
|
.DisposeWith(disposables);
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
private void NextSlide(int direction)
|
|
{
|
|
if (_slides.Length == 0) return;
|
|
_currentSlideIndex = InSlideRange(_currentSlideIndex + direction);
|
|
|
|
var thisSlide = _slides[_currentSlideIndex];
|
|
|
|
if (thisSlide.Image == null)
|
|
thisSlide.PreCache(_httpClient).FireAndForget();
|
|
|
|
// Cache the next image
|
|
_slides[InSlideRange(_currentSlideIndex + 1)].PreCache(_httpClient).FireAndForget();
|
|
|
|
var prevSlide = _slides[InSlideRange(_currentSlideIndex - 2)];
|
|
if (prevSlide.Image != null)
|
|
prevSlide.Image = null;
|
|
|
|
Dispatcher.UIThread.InvokeAsync(() =>
|
|
{
|
|
Slide = thisSlide;
|
|
});
|
|
}
|
|
|
|
private int InSlideRange(int i)
|
|
{
|
|
while (!(i >= 0 && i <= _slides.Length))
|
|
{
|
|
if (i >= _slides.Length) i -= _slides.Length;
|
|
if (i < 0) i += _slides.Length;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
public void Receive(StartInstallation msg)
|
|
{
|
|
|
|
Install(msg).FireAndForget();
|
|
}
|
|
|
|
private async Task Install(StartInstallation msg)
|
|
{
|
|
_scope = _provider.CreateScope();
|
|
_config = _provider.GetService<InstallerConfiguration>()!;
|
|
_config.Downloads = msg.Download;
|
|
_config.Install = msg.Install;
|
|
_config.ModlistArchive = msg.ModListPath;
|
|
|
|
_logger.LogInformation("Loading ModList Data");
|
|
_config.ModList = await StandardInstaller.LoadFromFile(_dtos, msg.ModListPath);
|
|
_config.Game = _config.ModList.GameType;
|
|
|
|
_slides = _config.ModList.Archives.Select(a => a.State).OfType<IMetaState>()
|
|
.Select(m => new SlideViewModel { MetaState = m })
|
|
.Shuffle()
|
|
.ToArray();
|
|
|
|
_slides[1].PreCache(_httpClient).FireAndForget();
|
|
Slide = _slides[1];
|
|
|
|
if (_config.GameFolder == default)
|
|
{
|
|
if (!_locator.TryFindLocation(_config.Game, out var found))
|
|
{
|
|
_logger.LogCritical("Game {game} is not installed on this system",
|
|
_config.Game.MetaData().HumanFriendlyGameName);
|
|
throw new Exception("Game not found");
|
|
}
|
|
|
|
_config.GameFolder = found;
|
|
}
|
|
|
|
_installer = _provider.GetService<StandardInstaller>()!;
|
|
|
|
_installer.OnStatusUpdate += (_, update) =>
|
|
{
|
|
Dispatcher.UIThread.InvokeAsync(() =>
|
|
{
|
|
StatusText = update.StatusText;
|
|
StepsProgress = update.StepsProgress;
|
|
StepProgress = update.StepProgress;
|
|
});
|
|
};
|
|
|
|
_logger.LogInformation("Installer created, starting the installation process");
|
|
await _installer.Begin(CancellationToken.None);
|
|
}
|
|
}
|
|
} |