wabbajack/Wabbajack/View Models/MainWindowVM.cs
Justin Swanson 727fe19043 Removed unnecessary intervention lock
Only one intervention should be firing, even without the lock.  If multiple are being fired, then it's likely the UserIntervention.Handle isn't awaiting all its "goals" properly within its own call
2020-08-08 08:22:12 -05:00

188 lines
6.5 KiB
C#

using DynamicData;
using DynamicData.Binding;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using Alphaleonis.Win32.Filesystem;
using Wabbajack.Common;
using Wabbajack.Common.StatusFeed;
using Wabbajack.Lib;
namespace Wabbajack
{
/// <summary>
/// Main View Model for the application.
/// Keeps track of which sub view is being shown in the window, and has some singleton wiring like WorkQueue and Logging.
/// </summary>
public class MainWindowVM : ViewModel
{
public MainWindow MainWindow { get; }
public MainSettings Settings { get; }
[Reactive]
public ViewModel ActivePane { get; private set; }
public ObservableCollectionExtended<IStatusMessage> Log { get; } = new ObservableCollectionExtended<IStatusMessage>();
public readonly Lazy<CompilerVM> Compiler;
public readonly Lazy<InstallerVM> Installer;
public readonly Lazy<SettingsVM> SettingsPane;
public readonly Lazy<ModListGalleryVM> Gallery;
public readonly ModeSelectionVM ModeSelectionVM;
public readonly UserInterventionHandlers UserInterventionHandlers;
public ICommand CopyVersionCommand { get; }
public ICommand ShowLoginManagerVM { get; }
public ICommand OpenSettingsCommand { get; }
public string VersionDisplay { get; }
[Reactive]
public bool UpdateAvailable { get; private set; }
public MainWindowVM(MainWindow mainWindow, MainSettings settings)
{
ConverterRegistration.Register();
MainWindow = mainWindow;
Settings = settings;
Installer = new Lazy<InstallerVM>(() => new InstallerVM(this));
Compiler = new Lazy<CompilerVM>(() => new CompilerVM(this));
SettingsPane = new Lazy<SettingsVM>(() => new SettingsVM(this));
Gallery = new Lazy<ModListGalleryVM>(() => new ModListGalleryVM(this));
ModeSelectionVM = new ModeSelectionVM(this);
UserInterventionHandlers = new UserInterventionHandlers(this);
// Set up logging
Utils.LogMessages
.ObserveOn(RxApp.TaskpoolScheduler)
.ToObservableChangeSet()
.Buffer(TimeSpan.FromMilliseconds(250), RxApp.TaskpoolScheduler)
.Where(l => l.Count > 0)
.FlattenBufferResult()
.ObserveOnGuiThread()
.Bind(Log)
.Subscribe()
.DisposeWith(CompositeDisposable);
Utils.LogMessages
.OfType<IUserIntervention>()
.ObserveOnGuiThread()
.SelectTask(async msg =>
{
try
{
await UserInterventionHandlers.Handle(msg);
}
catch (Exception ex)
when (ex.GetType() != typeof(TaskCanceledException))
{
Utils.Error(ex, $"Error while handling user intervention of type {msg?.GetType()}");
try
{
if (!msg.Handled)
{
msg.Cancel();
}
}
catch (Exception cancelEx)
{
Utils.Error(cancelEx, $"Error while cancelling user intervention of type {msg?.GetType()}");
}
}
})
.Subscribe()
.DisposeWith(CompositeDisposable);
if (IsStartingFromModlist(out var path))
{
Installer.Value.ModListLocation.TargetPath = path;
NavigateTo(Installer.Value);
}
else
{
// Start on mode selection
NavigateTo(ModeSelectionVM);
}
try
{
var assembly = Assembly.GetExecutingAssembly();
var fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
VersionDisplay = $"v{fvi.FileVersion}";
Utils.Log($"Wabbajack Version: {fvi.FileVersion}");
Task.Run(() => Metrics.Send("started_wabbajack", fvi.FileVersion)).FireAndForget();
}
catch (Exception ex)
{
Utils.Error(ex);
VersionDisplay = "ERROR";
}
CopyVersionCommand = ReactiveCommand.Create(() =>
{
Clipboard.SetText($"Wabbajack {VersionDisplay}\n{ThisAssembly.Git.Sha}");
});
OpenSettingsCommand = ReactiveCommand.Create(
canExecute: this.WhenAny(x => x.ActivePane)
.Select(active => !SettingsPane.IsValueCreated || !object.ReferenceEquals(active, SettingsPane.Value)),
execute: () => NavigateTo(SettingsPane.Value));
}
private static bool IsStartingFromModlist(out AbsolutePath modlistPath)
{
if (CLIArguments.InstallPath == null)
{
modlistPath = default;
return false;
}
modlistPath = (AbsolutePath)CLIArguments.InstallPath;
return true;
}
public void OpenInstaller(AbsolutePath path)
{
if (path == default) return;
var installer = Installer.Value;
Settings.Installer.LastInstalledListLocation = path;
NavigateTo(installer);
installer.ModListLocation.TargetPath = path;
}
public void NavigateTo(ViewModel vm)
{
ActivePane = vm;
}
public void NavigateTo<T>(T vm)
where T : ViewModel, IBackNavigatingVM
{
vm.NavigateBackTarget = ActivePane;
ActivePane = vm;
}
public async Task ShutdownApplication()
{
Dispose();
Settings.PosX = MainWindow.Left;
Settings.PosY = MainWindow.Top;
Settings.Width = MainWindow.Width;
Settings.Height = MainWindow.Height;
await MainSettings.SaveSettings(Settings);
Application.Current.Shutdown();
}
}
}