Merge pull request #255 from Noggog/intervention-frontend

Intervention frontend
This commit is contained in:
Timothy Baldridge 2019-12-10 22:55:34 -07:00 committed by GitHub
commit 073d02061a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 916 additions and 183 deletions

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Wabbajack.Common.StatusFeed
{
/// <summary>
/// Defines a message that requires user interaction. The user must perform some action
/// or make a choice.
/// </summary>
public interface IUserIntervention : IStatusMessage
{
/// <summary>
/// The user didn't make a choice, so this action should be aborted
/// </summary>
void Cancel();
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using ReactiveUI;
namespace Wabbajack.Common
{
public abstract class AUserIntervention : ReactiveObject, IUserIntervention
{
public DateTime Timestamp { get; } = DateTime.Now;
public abstract string ShortDescription { get; }
public abstract string ExtendedDescription { get; }
private bool _handled;
public bool Handled { get => _handled; set => this.RaiseAndSetIfChanged(ref _handled, value); }
public int CpuID { get; } = WorkQueue.CpuId;
public abstract void Cancel();
public ICommand CancelCommand { get; }
public AUserIntervention()
{
CancelCommand = ReactiveCommand.Create(() => Cancel());
}
}
}

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using ReactiveUI;
namespace Wabbajack.Common
{
public abstract class ConfirmationIntervention : AUserIntervention
{
public enum Choice
{
Continue,
Abort
}
private TaskCompletionSource<Choice> _source = new TaskCompletionSource<Choice>();
public Task<Choice> Task => _source.Task;
public ICommand ConfirmCommand { get; }
public ConfirmationIntervention()
{
ConfirmCommand = ReactiveCommand.Create(() => Confirm());
}
public override void Cancel()
{
Handled = true;
_source.SetResult(Choice.Abort);
}
public void Confirm()
{
Handled = true;
_source.SetResult(Choice.Continue);
}
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ReactiveUI;
using Wabbajack.Common.StatusFeed;
namespace Wabbajack.Common
{
/// <summary>
/// Defines a message that requires user interaction. The user must perform some action
/// or make a choice.
/// </summary>
public interface IUserIntervention : IStatusMessage, IReactiveObject
{
/// <summary>
/// The user didn't make a choice, so this action should be aborted
/// </summary>
void Cancel();
/// <summary>
/// Whether the interaction has been handled and no longer needs attention
/// Note: This needs to be Reactive so that users can monitor its status
/// </summary>
bool Handled { get; }
/// <summary>
/// WorkQueue job ID that is blocking on this intervention
/// </summary>
int CpuID { get; }
}
}

View File

@ -114,6 +114,7 @@
<Compile Include="SplittingStream.cs" />
<Compile Include="StatusFeed\AErrorMessage.cs" />
<Compile Include="StatusFeed\AStatusMessage.cs" />
<Compile Include="StatusFeed\Interventions\AUserIntervention.cs" />
<Compile Include="StatusFeed\Errors\7zipReturnError.cs" />
<Compile Include="StatusFeed\Errors\FileExtractionError.cs" />
<Compile Include="StatusFeed\Errors\GenericException.cs" />
@ -122,8 +123,9 @@
<Compile Include="StatusFeed\IError.cs" />
<Compile Include="StatusFeed\IException.cs" />
<Compile Include="StatusFeed\IInfo.cs" />
<Compile Include="StatusFeed\Interventions\ConfirmationIntervention.cs" />
<Compile Include="StatusFeed\IStatusMessage.cs" />
<Compile Include="StatusFeed\IUserIntervention.cs" />
<Compile Include="StatusFeed\Interventions\IUserIntervention.cs" />
<Compile Include="StatusFileStream.cs" />
<Compile Include="StatusUpdate.cs" />
<Compile Include="SteamHandler.cs" />

View File

@ -14,7 +14,10 @@ namespace Wabbajack.Common
internal BlockingCollection<Action>
Queue = new BlockingCollection<Action>(new ConcurrentStack<Action>());
[ThreadStatic] private static int CpuId;
public const int UnassignedCpuId = -1;
[ThreadStatic] private static int _cpuId = UnassignedCpuId;
public static int CpuId => _cpuId;
internal static bool WorkerThread => CurrentQueue != null;
[ThreadStatic] internal static WorkQueue CurrentQueue;
@ -24,6 +27,11 @@ namespace Wabbajack.Common
public static List<Thread> Threads { get; private set; }
// This is currently a lie, as it wires to the Utils singleton stream This is still good to have,
// so that logic related to a single WorkQueue can subscribe to this dummy member so that If/when we
// implement log messages in a non-singleton fashion, they will already be wired up properly.
public IObservable<IStatusMessage> LogMessages => Utils.LogMessages;
public WorkQueue(int threadCount = 0)
{
StartThreads(threadCount == 0 ? Environment.ProcessorCount : threadCount);
@ -48,7 +56,7 @@ namespace Wabbajack.Common
private void ThreadBody(int idx)
{
CpuId = idx;
_cpuId = idx;
CurrentQueue = this;
while (true)
@ -67,7 +75,7 @@ namespace Wabbajack.Common
Progress = progress,
ProgressPercent = progress / 100f,
Msg = msg,
ID = CpuId,
ID = _cpuId,
IsWorking = isWorking
});
}

View File

@ -1,9 +1,11 @@
using System;
using System.IO;
using System.Reactive.Disposables;
using System.Reactive.Subjects;
using System.Threading;
using System.Threading.Tasks;
using Wabbajack.Common;
using Wabbajack.Common.StatusFeed;
using Wabbajack.VirtualFileSystem;
namespace Wabbajack.Lib
@ -15,6 +17,7 @@ namespace Wabbajack.Lib
public void Dispose()
{
Queue?.Shutdown();
_subs.Dispose();
}
public Context VFS { get; private set; }
@ -38,6 +41,9 @@ namespace Wabbajack.Lib
private Subject<CPUStatus> _queueStatus { get; } = new Subject<CPUStatus>();
public IObservable<CPUStatus> QueueStatus => _queueStatus;
private Subject<IStatusMessage> _logMessages { get; } = new Subject<IStatusMessage>();
public IObservable<IStatusMessage> LogMessages => _logMessages;
private Subject<bool> _isRunning { get; } = new Subject<bool>();
public IObservable<bool> IsRunning => _isRunning;
@ -46,6 +52,8 @@ namespace Wabbajack.Lib
private int _configured;
private int _started;
private readonly CompositeDisposable _subs = new CompositeDisposable();
protected void ConfigureProcessor(int steps, int threads = 0)
{
if (1 == Interlocked.CompareExchange(ref _configured, 1, 1))
@ -54,7 +62,10 @@ namespace Wabbajack.Lib
}
Queue = new WorkQueue(threads);
UpdateTracker = new StatusUpdateTracker(steps);
Queue.Status.Subscribe(_queueStatus);
Queue.Status.Subscribe(_queueStatus)
.DisposeWith(_subs);
Queue.LogMessages.Subscribe(_logMessages)
.DisposeWith(_subs);
UpdateTracker.Progress.Subscribe(_percentCompleted);
UpdateTracker.StepName.Subscribe(_textStatus);
VFS = new Context(Queue) { UpdateTracker = UpdateTracker };

View File

@ -9,11 +9,8 @@ using System.Threading;
using System.Threading.Tasks;
using System.Web;
using Wabbajack.Common;
using Wabbajack.Common.StatusFeed;
using Wabbajack.Common.StatusFeed.Errors;
using Wabbajack.Lib.LibCefHelpers;
using Wabbajack.Lib.Validation;
using Wabbajack.Lib.WebAutomation;
using Xilium.CefGlue.Common;
using File = Alphaleonis.Win32.Filesystem.File;
@ -183,7 +180,7 @@ namespace Wabbajack.Lib.Downloaders
}
}
public class RequestLoversLabLogin : AStatusMessage, IUserIntervention
public class RequestLoversLabLogin : AUserIntervention
{
public override string ShortDescription => "Getting LoversLab information";
public override string ExtendedDescription { get; }
@ -193,10 +190,13 @@ namespace Wabbajack.Lib.Downloaders
public void Resume(Helpers.Cookie[] cookies)
{
Handled = true;
_source.SetResult(cookies);
}
public void Cancel()
public override void Cancel()
{
Handled = true;
_source.SetCanceled();
}
}

View File

@ -10,7 +10,6 @@ using Wabbajack.Common;
using Wabbajack.Lib.CompilationSteps.CompilationErrors;
using Wabbajack.Lib.Downloaders;
using Wabbajack.Lib.NexusApi;
using Wabbajack.Lib.StatusMessages;
using Wabbajack.Lib.Validation;
using Directory = Alphaleonis.Win32.Filesystem.Directory;
using File = Alphaleonis.Win32.Filesystem.File;

View File

@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wabbajack.Common.StatusFeed;
using Wabbajack.Common;
namespace Wabbajack.Lib.NexusApi
{
public class RequestNexusAuthorization : AStatusMessage, IUserIntervention
public class RequestNexusAuthorization : AUserIntervention
{
public override string ShortDescription => "Getting User's Nexus API Key";
public override string ExtendedDescription { get; }
@ -17,10 +17,13 @@ namespace Wabbajack.Lib.NexusApi
public void Resume(string apikey)
{
Handled = true;
_source.SetResult(apikey);
}
public void Cancel()
public override void Cancel()
{
Handled = true;
_source.SetCanceled();
}
}

View File

@ -3,24 +3,16 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wabbajack.Common.StatusFeed;
using Wabbajack.Common;
namespace Wabbajack.Lib.StatusMessages
namespace Wabbajack.Lib
{
public class ConfirmUpdateOfExistingInstall : AStatusMessage, IUserIntervention
public class ConfirmUpdateOfExistingInstall : ConfirmationIntervention
{
public enum Choice
{
Continue,
Abort
}
public string OutputFolder { get; set; }
public string ModListName { get; set; }
public override string ShortDescription { get; } = "Do you want to overwrite existing files?";
private TaskCompletionSource<Choice> _source = new TaskCompletionSource<Choice>();
public Task<Choice> Task => _source.Task;
public override string ShortDescription { get; } = "Do you want to overwrite existing files?";
public override string ExtendedDescription
{
@ -29,15 +21,5 @@ namespace Wabbajack.Lib.StatusMessages
Any files that exist in {OutputFolder} will be changed to match the files found in the {ModListName} modlist. This means that save games will be removed, custom settings
will be reverted. Are you sure you wish to continue?";
}
public void Cancel()
{
_source.SetResult(Choice.Abort);
}
public void Confirm()
{
_source.SetResult(Choice.Continue);
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
namespace Wabbajack
{
public class IsTypeVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType != typeof(Visibility))
throw new InvalidOperationException($"The target must be of type {nameof(Visibility)}");
if (!(parameter is Type paramType))
{
throw new ArgumentException();
}
if (value == null) return Visibility.Collapsed;
return paramType.Equals(value.GetType()) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@ -20,8 +20,8 @@ namespace Wabbajack
public InstallerSettings Installer { get; set; } = new InstallerSettings();
public CompilerSettings Compiler { get; set; } = new CompilerSettings();
[JsonIgnoreAttribute]
private Subject<Unit> _saveSignal = new Subject<Unit>();
[JsonIgnoreAttribute]
public IObservable<Unit> SaveSignal => _saveSignal;
public static bool TryLoadTypicalSettings(out MainSettings settings)
@ -58,6 +58,7 @@ namespace Wabbajack
{
public string InstallationLocation { get; set; }
public string DownloadLocation { get; set; }
public bool AutomaticallyOverrideExistingInstall { get; set; }
}
public class CompilerSettings

View File

@ -15,6 +15,7 @@
<local:InverseBooleanConverter x:Key="InverseBooleanConverter" />
<local:IsNotNullVisibilityConverter x:Key="IsNotNullVisibilityConverter" />
<local:EqualsToBoolConverter x:Key="EqualsToBoolConverter" />
<local:IsTypeVisibilityConverter x:Key="IsTypeVisibilityConverter" />
<!-- Colors -->
<Color x:Key="WindowBackgroundColor">#121212</Color>
@ -43,6 +44,7 @@
<Color x:Key="Secondary">#03DAC6</Color>
<Color x:Key="DarkSecondary">#0e8f83</Color>
<Color x:Key="DarkerSecondary">#095952</Color>
<Color x:Key="SecondaryBackground">#042421</Color>
<Color x:Key="OffWhiteSeconday">#cef0ed</Color>
<Color x:Key="LightSecondary">#8cede5</Color>
<Color x:Key="IntenseSecondary">#00ffe7</Color>
@ -115,6 +117,7 @@
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}" />
<SolidColorBrush x:Key="DarkSecondaryBrush" Color="{StaticResource DarkSecondary}" />
<SolidColorBrush x:Key="DarkerSecondaryBrush" Color="{StaticResource DarkerSecondary}" />
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="{StaticResource SecondaryBackground}" />
<SolidColorBrush x:Key="OffWhiteSecondayBrush" Color="{StaticResource OffWhiteSeconday}" />
<SolidColorBrush x:Key="LightSecondaryBrush" Color="{StaticResource LightSecondary}" />
<SolidColorBrush x:Key="IntenseSecondaryBrush" Color="{StaticResource IntenseSecondary}" />
@ -3708,4 +3711,58 @@
</Style>
<Style BasedOn="{StaticResource MainFilePickerStyle}" TargetType="{x:Type local:FilePicker}" />
<!-- User Intervention Background -->
<Style x:Key="AttentionBorderStyle" TargetType="Border">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="{StaticResource WindowBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource DarkerSecondaryBrush}" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsVisible, RelativeSource={RelativeSource Self}}" Value="True" />
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="False" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard x:Name="BorderGlow">
<Storyboard>
<ColorAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
To="{StaticResource Secondary}"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard x:Name="BackgroundGlow">
<Storyboard>
<ColorAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="{StaticResource SecondaryBackground}"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
To="{StaticResource DarkerSecondary}"
Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="{StaticResource WindowBackgroundColor}"
Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>

View File

@ -11,8 +11,11 @@ namespace Wabbajack
{
public interface ISubInstallerVM
{
InstallerVM Parent { get; }
IReactiveCommand BeginCommand { get; }
AInstaller ActiveInstallation { get; }
void Unload();
bool SupportsAfterInstallNavigation { get; }
void AfterInstallNavigation();
}
}

View File

@ -19,7 +19,6 @@ using DynamicData;
using DynamicData.Binding;
using Wabbajack.Common.StatusFeed;
using System.Reactive;
using Wabbajack.Common.StatusFeed;
namespace Wabbajack
{
@ -79,11 +78,19 @@ namespace Wabbajack
private readonly ObservableAsPropertyHelper<ModManager?> _TargetManager;
public ModManager? TargetManager => _TargetManager.Value;
private readonly ObservableAsPropertyHelper<IUserIntervention> _ActiveGlobalUserIntervention;
public IUserIntervention ActiveGlobalUserIntervention => _ActiveGlobalUserIntervention.Value;
private readonly ObservableAsPropertyHelper<bool> _Completed;
public bool Completed => _Completed.Value;
// Command properties
public IReactiveCommand ShowReportCommand { get; }
public IReactiveCommand OpenReadmeCommand { get; }
public IReactiveCommand VisitWebsiteCommand { get; }
public IReactiveCommand BackCommand { get; }
public IReactiveCommand CloseWhenCompleteCommand { get; }
public IReactiveCommand GoToInstallCommand { get; }
public InstallerVM(MainWindowVM mainWindowVM)
{
@ -293,6 +300,48 @@ namespace Wabbajack
InstallingMode = true;
})
.DisposeWith(CompositeDisposable);
// Listen for user interventions, and compile a dynamic list of all unhandled ones
var activeInterventions = this.WhenAny(x => x.Installer.ActiveInstallation)
.SelectMany(c => c?.LogMessages ?? Observable.Empty<IStatusMessage>())
.WhereCastable<IStatusMessage, IUserIntervention>()
.ToObservableChangeSet()
.AutoRefresh(i => i.Handled)
.Filter(i => !i.Handled)
.AsObservableList();
// Find the top intervention /w no CPU ID to be marked as "global"
_ActiveGlobalUserIntervention = activeInterventions.Connect()
.Filter(x => x.CpuID == WorkQueue.UnassignedCpuId)
.QueryWhenChanged(query => query.FirstOrDefault())
.ObserveOnGuiThread()
.ToProperty(this, nameof(ActiveGlobalUserIntervention));
_Completed = Observable.CombineLatest(
this.WhenAny(x => x.Installing),
this.WhenAny(x => x.InstallingMode),
resultSelector: (installing, installingMode) =>
{
return installingMode && !installing;
})
.ToProperty(this, nameof(Completed));
CloseWhenCompleteCommand = ReactiveCommand.Create(
canExecute: this.WhenAny(x => x.Completed),
execute: () =>
{
MWVM.ShutdownApplication();
});
GoToInstallCommand = ReactiveCommand.Create(
canExecute: Observable.CombineLatest(
this.WhenAny(x => x.Completed),
this.WhenAny(x => x.Installer.SupportsAfterInstallNavigation),
resultSelector: (complete, supports) => complete && supports),
execute: () =>
{
Installer.AfterInstallNavigation();
});
}
private void ShowReport()

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive.Disposables;
@ -15,7 +16,7 @@ namespace Wabbajack
{
public class MO2InstallerVM : ViewModel, ISubInstallerVM
{
private InstallerVM _installerVM;
public InstallerVM Parent { get; }
public IReactiveCommand BeginCommand { get; }
@ -29,9 +30,14 @@ namespace Wabbajack
public FilePickerVM DownloadLocation { get; }
public bool SupportsAfterInstallNavigation => true;
[Reactive]
public bool AutomaticallyOverwrite { get; set; }
public MO2InstallerVM(InstallerVM installerVM)
{
_installerVM = installerVM;
Parent = installerVM;
Location = new FilePickerVM()
{
@ -131,11 +137,31 @@ namespace Wabbajack
if (settingsPair.Current == null) return;
Location.TargetPath = settingsPair.Current.InstallationLocation;
DownloadLocation.TargetPath = settingsPair.Current.DownloadLocation;
AutomaticallyOverwrite = settingsPair.Current.AutomaticallyOverrideExistingInstall;
})
.DisposeWith(CompositeDisposable);
installerVM.MWVM.Settings.SaveSignal
.Subscribe(_ => SaveSettings(CurrentSettings))
.DisposeWith(CompositeDisposable);
// Hook onto user interventions, and intercept MO2 specific ones for customization
this.WhenAny(x => x.ActiveInstallation.LogMessages)
.Switch()
.Subscribe(x =>
{
switch (x)
{
case ConfirmUpdateOfExistingInstall c:
if (AutomaticallyOverwrite)
{
c.Confirm();
}
break;
default:
break;
}
})
.DisposeWith(CompositeDisposable);
}
public void Unload()
@ -145,10 +171,16 @@ namespace Wabbajack
private void SaveSettings(Mo2ModlistInstallationSettings settings)
{
_installerVM.MWVM.Settings.Installer.LastInstalledListLocation = _installerVM.ModListLocation.TargetPath;
Parent.MWVM.Settings.Installer.LastInstalledListLocation = Parent.ModListLocation.TargetPath;
if (settings == null) return;
settings.InstallationLocation = Location.TargetPath;
settings.DownloadLocation = DownloadLocation.TargetPath;
settings.AutomaticallyOverrideExistingInstall = AutomaticallyOverwrite;
}
public void AfterInstallNavigation()
{
Process.Start("explorer.exe", Location.TargetPath);
}
}
}

View File

@ -13,6 +13,8 @@ namespace Wabbajack
{
public class VortexInstallerVM : ViewModel, ISubInstallerVM
{
public InstallerVM Parent { get; }
public IReactiveCommand BeginCommand { get; }
[Reactive]
@ -27,8 +29,12 @@ namespace Wabbajack
private readonly ObservableAsPropertyHelper<Game> _TargetGame;
public Game TargetGame => _TargetGame.Value;
public bool SupportsAfterInstallNavigation => false;
public VortexInstallerVM(InstallerVM installerVM)
{
Parent = installerVM;
_TargetGame = installerVM.WhenAny(x => x.ModList.SourceModList.GameType)
.ToProperty(this, nameof(TargetGame));
@ -91,5 +97,10 @@ namespace Wabbajack
public void Unload()
{
}
public void AfterInstallNavigation()
{
throw new NotImplementedException();
}
}
}

View File

@ -12,9 +12,6 @@ using System.Windows.Threading;
using Wabbajack.Common;
using Wabbajack.Common.StatusFeed;
using Wabbajack.Lib;
using Wabbajack.Lib.Downloaders;
using Wabbajack.Lib.NexusApi;
using Wabbajack.Lib.StatusMessages;
namespace Wabbajack
{
@ -105,5 +102,16 @@ namespace Wabbajack
ActivePane = installer;
installer.ModListLocation.TargetPath = path;
}
public void ShutdownApplication()
{
Dispose();
Settings.PosX = MainWindow.Left;
Settings.PosY = MainWindow.Top;
Settings.Width = MainWindow.Width;
Settings.Height = MainWindow.Height;
MainSettings.SaveSettings(Settings);
Application.Current.Shutdown();
}
}
}

View File

@ -8,10 +8,8 @@ using System.Windows;
using System.Windows.Threading;
using ReactiveUI;
using Wabbajack.Common;
using Wabbajack.Common.StatusFeed;
using Wabbajack.Lib.Downloaders;
using Wabbajack.Lib.NexusApi;
using Wabbajack.Lib.StatusMessages;
namespace Wabbajack
{
@ -54,22 +52,10 @@ namespace Wabbajack
MainWindow.ActivePane = oldPane;
}
public void Handle(ConfirmUpdateOfExistingInstall msg)
{
var result = MessageBox.Show(msg.ExtendedDescription, msg.ShortDescription, MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK)
msg.Confirm();
else
msg.Cancel();
}
public async Task Handle(IUserIntervention msg)
{
switch (msg)
{
case ConfirmUpdateOfExistingInstall c:
Handle(c);
break;
case RequestNexusAuthorization c:
await WrapBrowserJob(msg, async (vm, cancel) =>
{
@ -84,6 +70,8 @@ namespace Wabbajack
c.Resume(data);
});
break;
case ConfirmationIntervention c:
break;
default:
throw new NotImplementedException($"No handler for {msg}");
}

View File

@ -1,44 +1,17 @@
<UserControl
x:Class="Wabbajack.LogCpuView"
x:Class="Wabbajack.CpuView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wabbajack"
xmlns:mahapps="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="250"
d:DesignHeight="450"
d:DesignWidth="800"
BorderThickness="0"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="500" />
</Grid.ColumnDefinitions>
<Rectangle
Grid.Column="0"
Fill="{StaticResource HeatedBorderBrush}"
Opacity="{Binding ProgressPercent, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
<Rectangle Fill="{StaticResource HeatedBorderBrush}" Opacity="{Binding ProgressPercent, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
<ListBox
Grid.Column="0"
local:AutoScrollBehavior.ScrollOnNewItem="True"
BorderBrush="Transparent"
BorderThickness="1"
ItemsSource="{Binding Log}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ShortDescription}" TextWrapping="WrapWithOverflow" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Rectangle
Grid.Column="2"
Fill="{StaticResource HeatedBorderBrush}"
Opacity="{Binding ProgressPercent, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
<ListBox
Grid.Column="2"
HorizontalAlignment="Stretch"
BorderBrush="Transparent"
BorderThickness="1"

View File

@ -1,22 +1,34 @@
using System.Windows;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Wabbajack
{
/// <summary>
/// Interaction logic for LogCpuView.xaml
/// Interaction logic for CpuView.xaml
/// </summary>
public partial class LogCpuView : UserControl
public partial class CpuView : UserControl
{
public double ProgressPercent
{
get => (double)GetValue(ProgressPercentProperty);
set => SetValue(ProgressPercentProperty, value);
}
public static readonly DependencyProperty ProgressPercentProperty = DependencyProperty.Register(nameof(ProgressPercent), typeof(double), typeof(LogCpuView),
public static readonly DependencyProperty ProgressPercentProperty = DependencyProperty.Register(nameof(ProgressPercent), typeof(double), typeof(CpuView),
new FrameworkPropertyMetadata(default(double)));
public LogCpuView()
public CpuView()
{
InitializeComponent();
}

View File

@ -0,0 +1,26 @@
<UserControl
x:Class="Wabbajack.LogView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wabbajack"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<Rectangle Fill="{StaticResource HeatedBorderBrush}" Opacity="{Binding ProgressPercent, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
<ListBox
local:AutoScrollBehavior.ScrollOnNewItem="True"
BorderBrush="Transparent"
BorderThickness="1"
ItemsSource="{Binding Log}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ShortDescription}" TextWrapping="WrapWithOverflow" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Wabbajack
{
/// <summary>
/// Interaction logic for LogView.xaml
/// </summary>
public partial class LogView : UserControl
{
public double ProgressPercent
{
get => (double)GetValue(ProgressPercentProperty);
set => SetValue(ProgressPercentProperty, value);
}
public static readonly DependencyProperty ProgressPercentProperty = DependencyProperty.Register(nameof(ProgressPercent), typeof(double), typeof(LogView),
new FrameworkPropertyMetadata(default(double)));
public LogView()
{
InitializeComponent();
}
}
}

View File

@ -2,6 +2,7 @@
x:Class="Wabbajack.CompilerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="clr-namespace:Wabbajack.Common;assembly=Wabbajack.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:icon="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:local="clr-namespace:Wabbajack"
@ -240,7 +241,24 @@
Grid.ColumnSpan="5"
Margin="5"
Visibility="{Binding Compiling, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Hidden}">
<local:LogCpuView ProgressPercent="{Binding PercentCompleted}" />
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<local:LogView Grid.Column="0" ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" />
<local:CpuView
Grid.Column="2"
ProgressPercent="{Binding PercentCompleted, Mode=OneWay}"
Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsNotNullVisibilityConverter}, ConverterParameter=False}" />
<Border
Grid.Column="2"
Style="{StaticResource AttentionBorderStyle}"
Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsNotNullVisibilityConverter}}">
<Grid>
<local:ConfirmationInterventionView DataContext="{Binding ActiveGlobalUserIntervention}" Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsTypeVisibilityConverter}, ConverterParameter={x:Type common:ConfirmationIntervention}}" />
</Grid>
</Border>
</Grid>
</Grid>
</UserControl>

View File

@ -0,0 +1,139 @@
<UserControl
x:Class="Wabbajack.InstallationCompleteView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:icon="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:local="clr-namespace:Wabbajack"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Border Style="{StaticResource AttentionBorderStyle}" ClipToBounds="True">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="3*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="3"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
FontFamily="Lucida Sans"
FontSize="22"
FontWeight="Black"
Text="Installation Complete">
<TextBlock.Effect>
<DropShadowEffect BlurRadius="25" Opacity="0.5" />
</TextBlock.Effect>
</TextBlock>
<Grid
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button
Grid.Row="0"
Width="55"
Height="55"
Command="{Binding BackCommand}"
Style="{StaticResource CircleButtonStyle}">
<icon:PackIconMaterial
Width="28"
Height="28"
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
Kind="ArrowLeft" />
</Button>
<TextBlock
Grid.Row="1"
Margin="0,10,0,0"
HorizontalAlignment="Center"
Text="Main Menu" />
</Grid>
<Grid
Grid.Row="1"
Grid.Column="1"
VerticalAlignment="Center"
Visibility="{Binding InstallerSupportsAfterInstallNavigation, Converter={StaticResource bool2VisibilityConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button
Width="55"
Height="55"
Command="{Binding GoToInstallCommand}"
Style="{StaticResource CircleButtonStyle}">
<icon:PackIconMaterial
Width="25"
Height="25"
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
Kind="FolderMove" />
</Button>
<TextBlock
Grid.Row="1"
Margin="0,10,0,0"
HorizontalAlignment="Center"
Text="Open Install Folder" />
</Grid>
<Grid
Grid.Row="1"
Grid.Column="2"
VerticalAlignment="Center"
Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!--<Button
Width="55"
Height="55"
Background="{StaticResource PrimaryVariantBrush}"
BorderBrush="{StaticResource PrimaryVariantBrush}"
IsHitTestVisible="False"
Style="{StaticResource CircleButtonStyle}">
<Button.Effect>
<BlurEffect Radius="35" />
</Button.Effect>
</Button>
<Button
Width="55"
Height="55"
Background="{StaticResource SecondaryBrush}"
BorderBrush="{StaticResource SecondaryBrush}"
IsHitTestVisible="False"
Style="{StaticResource CircleButtonStyle}">
<Button.Effect>
<BlurEffect Radius="15" />
</Button.Effect>
</Button>-->
<Button
Width="55"
Height="55"
Command="{Binding CloseWhenCompleteCommand}"
Style="{StaticResource CircleButtonStyle}">
<icon:PackIconMaterial
Width="30"
Height="30"
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
Kind="Check" />
</Button>
<TextBlock
Grid.Row="1"
Margin="0,10,0,0"
HorizontalAlignment="Center"
Text="Close" />
</Grid>
</Grid>
</Border>
</UserControl>

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Wabbajack
{
/// <summary>
/// Interaction logic for InstallationCompleteView.xaml
/// </summary>
public partial class InstallationCompleteView : UserControl
{
public InstallationCompleteView()
{
InitializeComponent();
}
}
}

View File

@ -2,8 +2,10 @@
x:Class="Wabbajack.InstallationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="clr-namespace:Wabbajack.Common;assembly=Wabbajack.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:icon="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:lib="clr-namespace:Wabbajack.Lib;assembly=Wabbajack.Lib"
xmlns:local="clr-namespace:Wabbajack"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DataContext="{d:DesignInstance local:InstallerVM}"
@ -24,7 +26,7 @@
<Grid.RowDefinitions>
<RowDefinition Height="47" />
<RowDefinition Height="4*" />
<RowDefinition Height="*" MinHeight="150" />
<RowDefinition Height="*" MinHeight="175" />
</Grid.RowDefinitions>
<Rectangle
x:Name="BorderEdgeFadeDown"
@ -287,49 +289,19 @@
Background="Transparent"
VerticalScrollBarVisibility="Auto"
Visibility="{Binding InstallingMode, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="120" />
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="40" />
<RowDefinition Height="80" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="1"
Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontSize="14"
Text="Target Modlist"
TextAlignment="Center" />
<local:FilePicker
Grid.Row="1"
Grid.Column="2"
Height="30"
VerticalAlignment="Center"
DataContext="{Binding ModListLocation}"
FontSize="14" />
<ContentPresenter
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="0"
Content="{Binding Installer}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type local:MO2InstallerVM}">
<local:MO2InstallerConfigView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:VortexInstallerVM}">
<local:VortexInstallerConfigView />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</Grid>
<ContentPresenter
Margin="0"
VerticalAlignment="Center"
Content="{Binding Installer}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type local:MO2InstallerVM}">
<local:MO2InstallerConfigView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:VortexInstallerVM}">
<local:VortexInstallerConfigView />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</ScrollViewer>
<local:BeginButton
Grid.Column="2"
@ -343,7 +315,26 @@
Grid.Row="2"
Margin="5,0,5,5"
Visibility="{Binding InstallingMode, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Hidden}">
<local:LogCpuView ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" />
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<local:LogView Grid.Column="0" ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" />
<local:CpuView
Grid.Column="2"
ProgressPercent="{Binding PercentCompleted, Mode=OneWay}"
Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsNotNullVisibilityConverter}, ConverterParameter=False}" />
<Border
Grid.Column="2"
Style="{StaticResource AttentionBorderStyle}"
Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsNotNullVisibilityConverter}}">
<Grid>
<local:ConfirmationInterventionView DataContext="{Binding ActiveGlobalUserIntervention}" Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsTypeVisibilityConverter}, ConverterParameter={x:Type common:ConfirmationIntervention}}" />
<local:ConfirmUpdateOfExistingInstallView Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsTypeVisibilityConverter}, ConverterParameter={x:Type lib:ConfirmUpdateOfExistingInstall}}" />
</Grid>
</Border>
<local:InstallationCompleteView Grid.Column="2" Visibility="{Binding Completed, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Collapsed}" />
</Grid>
</Grid>
</UserControl>

View File

@ -3,6 +3,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:icon="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:local="clr-namespace:Wabbajack"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
@ -15,11 +16,29 @@
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Grid.Row="1"
Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontSize="14"
Text="Target Modlist"
TextAlignment="Center" />
<local:FilePicker
Grid.Row="1"
Grid.Column="2"
Height="30"
VerticalAlignment="Center"
DataContext="{Binding Parent.ModListLocation}"
FontSize="14" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
@ -27,14 +46,14 @@
Text="Installation Location"
TextAlignment="Center" />
<local:FilePicker
Grid.Row="0"
Grid.Row="2"
Grid.Column="2"
Height="30"
VerticalAlignment="Center"
DataContext="{Binding Location}"
FontSize="14" />
<TextBlock
Grid.Row="1"
Grid.Row="3"
Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
@ -42,11 +61,29 @@
Text="Download Location"
TextAlignment="Center" />
<local:FilePicker
Grid.Row="1"
Grid.Row="3"
Grid.Column="2"
Height="30"
VerticalAlignment="Center"
DataContext="{Binding DownloadLocation}"
FontSize="14" />
<CheckBox
Grid.Row="4"
Grid.Column="2"
HorizontalAlignment="Right"
Content="Overwrite Installation"
IsChecked="{Binding AutomaticallyOverwrite}"
ToolTip="If installing over an existing installation, automatically replace it without asking permission.">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Opacity" Value="0.6" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Opacity" Value="1" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
</Grid>
</UserControl>

View File

@ -9,6 +9,28 @@
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<!-- Nothing so far -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="120" />
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontSize="14"
Text="Target Modlist"
TextAlignment="Center" />
<local:FilePicker
Grid.Row="0"
Grid.Column="2"
Height="30"
VerticalAlignment="Center"
DataContext="{Binding Parent.ModListLocation}"
FontSize="14" />
</Grid>
</UserControl>

View File

@ -0,0 +1,58 @@
<UserControl
x:Class="Wabbajack.ConfirmUpdateOfExistingInstallView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wabbajack"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="5*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="0,0,0,5"
FontFamily="Lucida Sans"
FontSize="14"
FontWeight="Bold"
Text="{Binding ActiveGlobalUserIntervention.ShortDescription}"
TextWrapping="WrapWithOverflow" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="3"
Text="{Binding ActiveGlobalUserIntervention.ExtendedDescription}"
TextWrapping="WrapWithOverflow" />
<CheckBox
Grid.Row="2"
Grid.Column="2"
Margin="4"
HorizontalAlignment="Right"
Content="Remember"
IsChecked="{Binding Installer.AutomaticallyOverwrite}"
ToolTip="If installing over an existing installation next time, automatically replace it without asking permission." />
<Button
Grid.Row="3"
Grid.Column="0"
Command="{Binding ActiveGlobalUserIntervention.CancelCommand}"
Content="Cancel" />
<Button
Grid.Row="3"
Grid.Column="2"
Command="{Binding ActiveGlobalUserIntervention.ConfirmCommand}"
Content="Confirm" />
</Grid>
</UserControl>

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Wabbajack
{
/// <summary>
/// Interaction logic for ConfirmUpdateOfExistingInstallView.xaml
/// </summary>
public partial class ConfirmUpdateOfExistingInstallView : UserControl
{
public ConfirmUpdateOfExistingInstallView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,49 @@
<UserControl
x:Class="Wabbajack.ConfirmationInterventionView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wabbajack"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="4*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="3"
Margin="0,0,0,5"
FontFamily="Lucida Sans"
FontSize="14"
FontWeight="Bold"
Text="{Binding ShortDescription}"
TextWrapping="WrapWithOverflow" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="3"
Text="{Binding ExtendedDescription}"
TextWrapping="WrapWithOverflow" />
<Button
Grid.Row="2"
Grid.Column="0"
Command="{Binding CancelCommand}"
Content="Cancel" />
<Button
Grid.Row="2"
Grid.Column="2"
Command="{Binding ConfirmCommand}"
Content="Confirm" />
</Grid>
</UserControl>

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Wabbajack
{
/// <summary>
/// Interaction logic for ConfirmationInterventionView.xaml
/// </summary>
public partial class ConfirmationInterventionView : UserControl
{
public ConfirmationInterventionView()
{
InitializeComponent();
}
}
}

View File

@ -15,8 +15,6 @@ namespace Wabbajack
private MainWindowVM _mwvm;
private MainSettings _settings;
internal bool ExitWhenClosing = true;
public MainWindow()
{
// Wire any unhandled crashing exceptions to log before exiting
@ -93,16 +91,7 @@ namespace Wabbajack
private void Window_Closing(object sender, CancelEventArgs e)
{
_mwvm.Dispose();
_settings.PosX = Left;
_settings.PosY = Top;
_settings.Width = Width;
_settings.Height = Height;
MainSettings.SaveSettings(_settings);
if (ExitWhenClosing)
{
Application.Current.Shutdown();
}
_mwvm.ShutdownApplication();
}
}
}

View File

@ -172,7 +172,20 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Converters\IsTypeVisibilityConverter.cs" />
<Compile Include="Views\Installers\InstallationCompleteView.xaml.cs">
<DependentUpon>InstallationCompleteView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Interventions\ConfirmationInterventionView.xaml.cs">
<DependentUpon>ConfirmationInterventionView.xaml</DependentUpon>
</Compile>
<Compile Include="Converters\EqualsToBoolConverter.cs" />
<Compile Include="Views\Common\CpuView.xaml.cs">
<DependentUpon>CpuView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Common\LogView.xaml.cs">
<DependentUpon>LogView.xaml</DependentUpon>
</Compile>
<Compile Include="View Models\UserInterventionHandlers.cs" />
<Compile Include="View Models\WebBrowserVM.cs" />
<Compile Include="Views\Installers\MO2InstallerConfigView.xaml.cs">
@ -186,6 +199,9 @@
<Compile Include="Views\Common\HeatedBackgroundView.xaml.cs">
<DependentUpon>HeatedBackgroundView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Interventions\ConfirmUpdateOfExistingInstallView.xaml.cs">
<DependentUpon>ConfirmUpdateOfExistingInstallView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\LinksView.xaml.cs">
<DependentUpon>LinksView.xaml</DependentUpon>
</Compile>
@ -234,9 +250,6 @@
</Compile>
<Compile Include="View Models\Compilers\CompilerVM.cs" />
<Compile Include="View Models\MainWindowVM.cs" />
<Compile Include="Views\Common\LogCpuView.xaml.cs">
<DependentUpon>LogCpuView.xaml</DependentUpon>
</Compile>
<Compile Include="Converters\LeftMarginMultiplierConverter.cs" />
<Compile Include="Util\TreeViewItemExtensions.cs" />
<Compile Include="View Models\SlideShow.cs" />
@ -256,6 +269,22 @@
<Compile Include="Views\WebBrowserView.xaml.cs">
<DependentUpon>WebBrowserView.xaml</DependentUpon>
</Compile>
<Page Include="Views\Installers\InstallationCompleteView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Interventions\ConfirmationInterventionView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Common\CpuView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Common\LogView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Installers\MO2InstallerConfigView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -264,6 +293,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Interventions\ConfirmUpdateOfExistingInstallView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\LinksView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -304,10 +337,6 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Common\LogCpuView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>