wabbajack/Wabbajack.App.Wpf/View Models/Installers/InstallerVM.cs

297 lines
9.6 KiB
C#
Raw Normal View History

2021-12-26 21:56:44 +00:00
using System;
using ReactiveUI;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows.Media.Imaging;
using ReactiveUI.Fody.Helpers;
using System.Windows.Media;
using DynamicData;
using DynamicData.Binding;
using System.Reactive;
2021-12-31 00:50:38 +00:00
using System.Text;
using System.Threading;
2021-12-30 23:55:41 +00:00
using System.Threading.Tasks;
2021-12-31 23:58:09 +00:00
using System.Windows.Shell;
2021-12-28 00:53:14 +00:00
using Microsoft.Extensions.DependencyInjection;
2021-12-28 00:24:53 +00:00
using Microsoft.Extensions.Logging;
2021-12-26 21:56:44 +00:00
using Microsoft.WindowsAPICodePack.Dialogs;
using Microsoft.WindowsAPICodePack.Shell;
2021-12-30 23:55:41 +00:00
using Wabbajack.Common;
using Wabbajack.Downloaders.GameFile;
2021-12-30 23:55:41 +00:00
using Wabbajack.DTOs;
2021-12-28 00:53:14 +00:00
using Wabbajack.DTOs.JsonConverters;
2021-12-30 00:15:37 +00:00
using Wabbajack.Extensions;
2021-12-31 00:50:38 +00:00
using Wabbajack.Hashing.xxHash64;
2021-12-30 23:55:41 +00:00
using Wabbajack.Installer;
2021-12-30 00:15:37 +00:00
using Wabbajack.Interventions;
using Wabbajack.Messages;
using Wabbajack.Models;
2021-12-30 23:55:41 +00:00
using Wabbajack.Paths;
using Wabbajack.RateLimiter;
2021-12-27 05:13:28 +00:00
using Wabbajack.View_Models;
2021-12-28 06:11:39 +00:00
using Wabbajack.Paths.IO;
using Wabbajack.Services.OSIntegrated;
using Wabbajack.Util;
2021-12-30 00:15:37 +00:00
using Consts = Wabbajack.Consts;
2021-12-28 06:11:39 +00:00
using KnownFolders = Wabbajack.Paths.IO.KnownFolders;
2021-12-26 21:56:44 +00:00
2021-12-28 00:24:53 +00:00
namespace Wabbajack;
2021-12-28 00:54:56 +00:00
public enum ModManager
2021-12-26 21:56:44 +00:00
{
2021-12-28 00:24:53 +00:00
Standard
}
public enum InstallState
{
Configuration,
Installing,
Success,
Failure
}
2021-12-30 23:55:41 +00:00
public class InstallerVM : BackNavigatingVM, IBackNavigatingVM
2021-12-28 00:24:53 +00:00
{
private const string LastLoadedModlist = "last-loaded-modlist";
2021-12-31 00:50:38 +00:00
private const string InstallSettingsPrefix = "install-settings-";
2021-12-31 23:44:36 +00:00
[Reactive]
public Percent StatusProgress { get; set; }
[Reactive]
public string StatusText { get; set; }
2021-12-28 00:24:53 +00:00
[Reactive]
2021-12-30 23:55:41 +00:00
public ModList ModList { get; set; }
[Reactive]
public ModlistMetadata ModlistMetadata { get; set; }
2021-12-28 00:24:53 +00:00
[Reactive]
public ErrorResponse? Completed { get; set; }
2021-12-26 21:56:44 +00:00
2021-12-30 23:55:41 +00:00
[Reactive]
public FilePickerVM ModListLocation { get; set; }
[Reactive]
public MO2InstallerVM Installer { get; set; }
[Reactive]
public BitmapFrame ModListImage { get; set; }
[Reactive]
public BitmapFrame SlideShowImage { get; set; }
[Reactive]
public InstallState InstallState { get; set; }
2021-12-30 23:55:41 +00:00
/// <summary>
/// Slideshow Data
/// </summary>
[Reactive]
public string SlideShowTitle { get; set; }
[Reactive]
public string SlideShowAuthor { get; set; }
[Reactive]
public string SlideShowDescription { get; set; }
2021-12-26 21:56:44 +00:00
2021-12-30 23:55:41 +00:00
private readonly ObservableAsPropertyHelper<bool> _installing;
private readonly DTOSerializer _dtos;
2021-12-28 00:24:53 +00:00
private readonly ILogger<InstallerVM> _logger;
private readonly SettingsManager _settingsManager;
private readonly IServiceProvider _serviceProvider;
private readonly SystemParametersConstructor _parametersConstructor;
private readonly IGameLocator _gameLocator;
private readonly LoggerProvider _loggerProvider;
2021-12-30 23:55:41 +00:00
[Reactive]
public bool Installing { get; set; }
[Reactive]
public LoggerProvider LoggerProvider { get; set; }
2021-12-30 23:55:41 +00:00
2021-12-28 00:24:53 +00:00
// Command properties
public ReactiveCommand<Unit, Unit> ShowManifestCommand { get; }
public ReactiveCommand<Unit, Unit> OpenReadmeCommand { get; }
public ReactiveCommand<Unit, Unit> VisitModListWebsiteCommand { get; }
2021-12-26 21:56:44 +00:00
2021-12-28 00:24:53 +00:00
public ReactiveCommand<Unit, Unit> CloseWhenCompleteCommand { get; }
public ReactiveCommand<Unit, Unit> OpenLogsCommand { get; }
public ReactiveCommand<Unit, Unit> GoToInstallCommand { get; }
public ReactiveCommand<Unit, Unit> BeginCommand { get; }
2021-12-30 23:55:41 +00:00
public ReactiveCommand<Unit, Unit> BackCommand { get; }
2021-12-26 21:56:44 +00:00
public InstallerVM(ILogger<InstallerVM> logger, DTOSerializer dtos, SettingsManager settingsManager, IServiceProvider serviceProvider,
SystemParametersConstructor parametersConstructor, IGameLocator gameLocator, LoggerProvider loggerProvider) : base(logger)
2021-12-28 00:24:53 +00:00
{
_logger = logger;
LoggerProvider = loggerProvider;
_settingsManager = settingsManager;
2021-12-30 23:55:41 +00:00
_dtos = dtos;
_serviceProvider = serviceProvider;
_parametersConstructor = parametersConstructor;
_gameLocator = gameLocator;
2021-12-30 23:55:41 +00:00
Installer = new MO2InstallerVM(this);
BackCommand = ReactiveCommand.Create(() => NavigateToGlobal.Send(NavigateToGlobal.ScreenType.ModeSelectionView));
2021-12-31 00:50:38 +00:00
BeginCommand = ReactiveCommand.Create(() => BeginInstall().FireAndForget());
2021-12-30 23:55:41 +00:00
OpenReadmeCommand = ReactiveCommand.Create(() =>
2021-12-28 00:24:53 +00:00
{
2021-12-30 23:55:41 +00:00
UIUtils.OpenWebsite(new Uri(ModList!.Readme));
}, LoadingLock.IsNotLoadingObservable);
VisitModListWebsiteCommand = ReactiveCommand.Create(() =>
2021-12-28 00:24:53 +00:00
{
2021-12-30 23:55:41 +00:00
UIUtils.OpenWebsite(ModList!.Website);
}, LoadingLock.IsNotLoadingObservable);
2021-12-28 00:24:53 +00:00
ModListLocation = new FilePickerVM
{
ExistCheckOption = FilePickerVM.CheckOptions.On,
PathType = FilePickerVM.PathTypeOptions.File,
PromptTitle = "Select a ModList to install"
};
ModListLocation.Filters.Add(new CommonFileDialogFilter("Wabbajack Modlist", "*.wabbajack"));
2021-12-28 00:53:14 +00:00
2021-12-30 23:55:41 +00:00
MessageBus.Current.Listen<LoadModlistForInstalling>()
.Subscribe(msg => LoadModlist(msg.Path, msg.Metadata).FireAndForget())
2021-12-30 23:55:41 +00:00
.DisposeWith(CompositeDisposable);
2021-12-26 21:56:44 +00:00
MessageBus.Current.Listen<LoadLastLoadedModlist>()
.Subscribe(msg =>
{
LoadLastModlist().FireAndForget();
});
2021-12-30 23:55:41 +00:00
this.WhenActivated(disposables =>
{
2021-12-30 23:55:41 +00:00
ModListLocation.WhenAnyValue(l => l.TargetPath)
.Subscribe(p => LoadModlist(p, null).FireAndForget())
2021-12-30 23:55:41 +00:00
.DisposeWith(disposables);
2021-12-28 00:24:53 +00:00
2021-12-30 23:55:41 +00:00
});
2021-12-28 00:24:53 +00:00
2021-12-30 23:55:41 +00:00
}
2021-12-28 00:24:53 +00:00
private async Task LoadLastModlist()
{
var lst = await _settingsManager.Load<AbsolutePath>(LastLoadedModlist);
if (lst.FileExists())
await LoadModlist(lst, null);
}
private async Task LoadModlist(AbsolutePath path, ModlistMetadata? metadata)
2021-12-30 23:55:41 +00:00
{
using var ll = LoadingLock.WithLoading();
InstallState = InstallState.Configuration;
2021-12-30 23:55:41 +00:00
ModListLocation.TargetPath = path;
try
2021-12-28 00:24:53 +00:00
{
2021-12-30 23:55:41 +00:00
ModList = await StandardInstaller.LoadFromFile(_dtos, path);
ModListImage = BitmapFrame.Create(await StandardInstaller.ModListImageStream(path));
2021-12-31 00:50:38 +00:00
2021-12-31 23:44:36 +00:00
StatusText = $"Install configuration for {ModList.Name}";
2021-12-31 23:58:09 +00:00
TaskBarUpdate.Send($"Loaded {ModList.Name}", TaskbarItemProgressState.Normal);
2021-12-31 23:44:36 +00:00
2021-12-31 00:50:38 +00:00
var hex = (await ModListLocation.TargetPath.ToString().Hash()).ToHex();
var prevSettings = await _settingsManager.Load<SavedInstallSettings>(InstallSettingsPrefix + hex);
if (prevSettings.ModListLocation == path)
{
ModListLocation.TargetPath = prevSettings.ModListLocation;
Installer.Location.TargetPath = prevSettings.InstallLocation;
Installer.DownloadLocation.TargetPath = prevSettings.DownloadLoadction;
ModlistMetadata = metadata ?? prevSettings.Metadata;
2021-12-31 00:50:38 +00:00
}
2021-12-30 23:55:41 +00:00
PopulateSlideShow(ModList);
2021-12-26 21:56:44 +00:00
2021-12-30 23:55:41 +00:00
ll.Succeed();
await _settingsManager.Save(LastLoadedModlist, path);
2021-12-30 23:55:41 +00:00
}
catch (Exception ex)
{
_logger.LogError(ex, "While loading modlist");
ll.Fail();
}
}
2021-12-26 21:56:44 +00:00
private async Task BeginInstall()
2021-12-31 00:50:38 +00:00
{
InstallState = InstallState.Installing;
2021-12-31 00:50:38 +00:00
var postfix = (await ModListLocation.TargetPath.ToString().Hash()).ToHex();
await _settingsManager.Save(InstallSettingsPrefix + postfix, new SavedInstallSettings
{
ModListLocation = ModListLocation.TargetPath,
InstallLocation = Installer.Location.TargetPath,
DownloadLoadction = Installer.DownloadLocation.TargetPath,
Metadata = ModlistMetadata
2021-12-31 00:50:38 +00:00
});
try
{
var installer = StandardInstaller.Create(_serviceProvider, new InstallerConfiguration
{
Game = ModList.GameType,
Downloads = Installer.DownloadLocation.TargetPath,
Install = Installer.Location.TargetPath,
ModList = ModList,
ModlistArchive = ModListLocation.TargetPath,
SystemParameters = _parametersConstructor.Create(),
GameFolder = _gameLocator.GameLocation(ModList.GameType)
});
2021-12-31 23:44:36 +00:00
installer.OnStatusUpdate = update =>
{
StatusText = update.StatusText;
StatusProgress = update.StepsProgress;
2021-12-31 23:58:09 +00:00
TaskBarUpdate.Send(update.StatusText, TaskbarItemProgressState.Indeterminate, update.StepsProgress.Value);
2021-12-31 23:44:36 +00:00
};
await installer.Begin(CancellationToken.None);
2021-12-31 23:58:09 +00:00
TaskBarUpdate.Send($"Finished install of {ModList.Name}", TaskbarItemProgressState.Normal);
InstallState = InstallState.Success;
}
catch (Exception ex)
{
2021-12-31 23:58:09 +00:00
TaskBarUpdate.Send($"Error during install of {ModList.Name}", TaskbarItemProgressState.Error);
InstallState = InstallState.Failure;
}
2021-12-31 00:50:38 +00:00
}
2021-12-31 23:44:36 +00:00
2021-12-31 00:50:38 +00:00
class SavedInstallSettings
{
public AbsolutePath ModListLocation { get; set; }
public AbsolutePath InstallLocation { get; set; }
public AbsolutePath DownloadLoadction { get; set; }
public ModlistMetadata Metadata { get; set; }
2021-12-31 00:50:38 +00:00
}
2021-12-30 23:55:41 +00:00
private void PopulateSlideShow(ModList modList)
{
SlideShowTitle = modList.Name;
SlideShowAuthor = modList.Author;
SlideShowDescription = modList.Description;
SlideShowImage = ModListImage;
2021-12-26 21:56:44 +00:00
}
2021-12-30 23:55:41 +00:00
2021-12-28 00:24:53 +00:00
}