Install/Compile views display ConfirmationInterventions in CPU area

This commit is contained in:
Justin Swanson 2019-12-08 18:19:36 -06:00
parent 886fbd13ad
commit 7f695a4a9e
20 changed files with 328 additions and 80 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="SplittingStream.cs" />
<Compile Include="StatusFeed\AErrorMessage.cs" /> <Compile Include="StatusFeed\AErrorMessage.cs" />
<Compile Include="StatusFeed\AStatusMessage.cs" /> <Compile Include="StatusFeed\AStatusMessage.cs" />
<Compile Include="StatusFeed\Interventions\AUserIntervention.cs" />
<Compile Include="StatusFeed\Errors\7zipReturnError.cs" /> <Compile Include="StatusFeed\Errors\7zipReturnError.cs" />
<Compile Include="StatusFeed\Errors\FileExtractionError.cs" /> <Compile Include="StatusFeed\Errors\FileExtractionError.cs" />
<Compile Include="StatusFeed\Errors\GenericException.cs" /> <Compile Include="StatusFeed\Errors\GenericException.cs" />
@ -122,8 +123,9 @@
<Compile Include="StatusFeed\IError.cs" /> <Compile Include="StatusFeed\IError.cs" />
<Compile Include="StatusFeed\IException.cs" /> <Compile Include="StatusFeed\IException.cs" />
<Compile Include="StatusFeed\IInfo.cs" /> <Compile Include="StatusFeed\IInfo.cs" />
<Compile Include="StatusFeed\Interventions\ConfirmationIntervention.cs" />
<Compile Include="StatusFeed\IStatusMessage.cs" /> <Compile Include="StatusFeed\IStatusMessage.cs" />
<Compile Include="StatusFeed\IUserIntervention.cs" /> <Compile Include="StatusFeed\Interventions\IUserIntervention.cs" />
<Compile Include="StatusFileStream.cs" /> <Compile Include="StatusFileStream.cs" />
<Compile Include="StatusUpdate.cs" /> <Compile Include="StatusUpdate.cs" />
<Compile Include="SteamHandler.cs" /> <Compile Include="SteamHandler.cs" />

View File

@ -14,7 +14,10 @@ namespace Wabbajack.Common
internal BlockingCollection<Action> internal BlockingCollection<Action>
Queue = new BlockingCollection<Action>(new ConcurrentStack<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; internal static bool WorkerThread => CurrentQueue != null;
[ThreadStatic] internal static WorkQueue CurrentQueue; [ThreadStatic] internal static WorkQueue CurrentQueue;
@ -24,6 +27,11 @@ namespace Wabbajack.Common
public static List<Thread> Threads { get; private set; } 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) public WorkQueue(int threadCount = 0)
{ {
StartThreads(threadCount == 0 ? Environment.ProcessorCount : threadCount); StartThreads(threadCount == 0 ? Environment.ProcessorCount : threadCount);
@ -48,7 +56,7 @@ namespace Wabbajack.Common
private void ThreadBody(int idx) private void ThreadBody(int idx)
{ {
CpuId = idx; _cpuId = idx;
CurrentQueue = this; CurrentQueue = this;
while (true) while (true)
@ -67,7 +75,7 @@ namespace Wabbajack.Common
Progress = progress, Progress = progress,
ProgressPercent = progress / 100f, ProgressPercent = progress / 100f,
Msg = msg, Msg = msg,
ID = CpuId, ID = _cpuId,
IsWorking = isWorking IsWorking = isWorking
}); });
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -3,24 +3,16 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; 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 OutputFolder { get; set; }
public string ModListName { 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 override string ShortDescription { get; } = "Do you want to overwrite existing files?";
public Task<Choice> Task => _source.Task;
public override string ExtendedDescription 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 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?"; 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

@ -43,6 +43,7 @@
<Color x:Key="Secondary">#03DAC6</Color> <Color x:Key="Secondary">#03DAC6</Color>
<Color x:Key="DarkSecondary">#0e8f83</Color> <Color x:Key="DarkSecondary">#0e8f83</Color>
<Color x:Key="DarkerSecondary">#095952</Color> <Color x:Key="DarkerSecondary">#095952</Color>
<Color x:Key="SecondaryBackground">#042421</Color>
<Color x:Key="OffWhiteSeconday">#cef0ed</Color> <Color x:Key="OffWhiteSeconday">#cef0ed</Color>
<Color x:Key="LightSecondary">#8cede5</Color> <Color x:Key="LightSecondary">#8cede5</Color>
<Color x:Key="IntenseSecondary">#00ffe7</Color> <Color x:Key="IntenseSecondary">#00ffe7</Color>
@ -115,6 +116,7 @@
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}" /> <SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}" />
<SolidColorBrush x:Key="DarkSecondaryBrush" Color="{StaticResource DarkSecondary}" /> <SolidColorBrush x:Key="DarkSecondaryBrush" Color="{StaticResource DarkSecondary}" />
<SolidColorBrush x:Key="DarkerSecondaryBrush" Color="{StaticResource DarkerSecondary}" /> <SolidColorBrush x:Key="DarkerSecondaryBrush" Color="{StaticResource DarkerSecondary}" />
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="{StaticResource SecondaryBackground}" />
<SolidColorBrush x:Key="OffWhiteSecondayBrush" Color="{StaticResource OffWhiteSeconday}" /> <SolidColorBrush x:Key="OffWhiteSecondayBrush" Color="{StaticResource OffWhiteSeconday}" />
<SolidColorBrush x:Key="LightSecondaryBrush" Color="{StaticResource LightSecondary}" /> <SolidColorBrush x:Key="LightSecondaryBrush" Color="{StaticResource LightSecondary}" />
<SolidColorBrush x:Key="IntenseSecondaryBrush" Color="{StaticResource IntenseSecondary}" /> <SolidColorBrush x:Key="IntenseSecondaryBrush" Color="{StaticResource IntenseSecondary}" />

View File

@ -19,7 +19,6 @@ using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using Wabbajack.Common.StatusFeed; using Wabbajack.Common.StatusFeed;
using System.Reactive; using System.Reactive;
using Wabbajack.Common.StatusFeed;
namespace Wabbajack namespace Wabbajack
{ {
@ -79,6 +78,9 @@ namespace Wabbajack
private readonly ObservableAsPropertyHelper<ModManager?> _TargetManager; private readonly ObservableAsPropertyHelper<ModManager?> _TargetManager;
public ModManager? TargetManager => _TargetManager.Value; public ModManager? TargetManager => _TargetManager.Value;
private readonly ObservableAsPropertyHelper<IUserIntervention> _ActiveGlobalUserIntervention;
public IUserIntervention ActiveGlobalUserIntervention => _ActiveGlobalUserIntervention.Value;
// Command properties // Command properties
public IReactiveCommand ShowReportCommand { get; } public IReactiveCommand ShowReportCommand { get; }
public IReactiveCommand OpenReadmeCommand { get; } public IReactiveCommand OpenReadmeCommand { get; }
@ -293,6 +295,22 @@ namespace Wabbajack
InstallingMode = true; InstallingMode = true;
}) })
.DisposeWith(CompositeDisposable); .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));
} }
private void ShowReport() private void ShowReport()

View File

@ -12,9 +12,6 @@ using System.Windows.Threading;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.Common.StatusFeed; using Wabbajack.Common.StatusFeed;
using Wabbajack.Lib; using Wabbajack.Lib;
using Wabbajack.Lib.Downloaders;
using Wabbajack.Lib.NexusApi;
using Wabbajack.Lib.StatusMessages;
namespace Wabbajack namespace Wabbajack
{ {

View File

@ -8,10 +8,8 @@ using System.Windows;
using System.Windows.Threading; using System.Windows.Threading;
using ReactiveUI; using ReactiveUI;
using Wabbajack.Common; using Wabbajack.Common;
using Wabbajack.Common.StatusFeed;
using Wabbajack.Lib.Downloaders; using Wabbajack.Lib.Downloaders;
using Wabbajack.Lib.NexusApi; using Wabbajack.Lib.NexusApi;
using Wabbajack.Lib.StatusMessages;
namespace Wabbajack namespace Wabbajack
{ {
@ -54,22 +52,10 @@ namespace Wabbajack
MainWindow.ActivePane = oldPane; 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) public async Task Handle(IUserIntervention msg)
{ {
switch (msg) switch (msg)
{ {
case ConfirmUpdateOfExistingInstall c:
Handle(c);
break;
case RequestNexusAuthorization c: case RequestNexusAuthorization c:
await WrapBrowserJob(msg, async (vm, cancel) => await WrapBrowserJob(msg, async (vm, cancel) =>
{ {
@ -84,6 +70,8 @@ namespace Wabbajack
c.Resume(data); c.Resume(data);
}); });
break; break;
case ConfirmationIntervention c:
break;
default: default:
throw new NotImplementedException($"No handler for {msg}"); throw new NotImplementedException($"No handler for {msg}");
} }

View File

@ -2,6 +2,7 @@
x:Class="Wabbajack.CompilerView" x:Class="Wabbajack.CompilerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:icon="http://metro.mahapps.com/winfx/xaml/iconpacks" xmlns:icon="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:local="clr-namespace:Wabbajack" xmlns:local="clr-namespace:Wabbajack"
@ -241,12 +242,29 @@
Margin="5" Margin="5"
Visibility="{Binding Compiling, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Hidden}"> Visibility="{Binding Compiling, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Hidden}">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="3*" />
<ColumnDefinition Width="5" /> <ColumnDefinition Width="5" />
<ColumnDefinition Width="500" /> <ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:LogView Grid.Column="0" ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" /> <local:LogView Grid.Column="0" ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" />
<local:CpuView Grid.Column="2" 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"
Background="{StaticResource SecondaryBackgroundBrush}"
BorderBrush="{StaticResource SecondaryBrush}"
BorderThickness="1"
Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsNotNullVisibilityConverter}}">
<ContentPresenter Content="{Binding ActiveGlobalUserIntervention}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type common:ConfirmationIntervention}">
<local:ConfirmationInterventionView />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
</Grid> </Grid>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -2,8 +2,10 @@
x:Class="Wabbajack.InstallationView" x:Class="Wabbajack.InstallationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:icon="http://metro.mahapps.com/winfx/xaml/iconpacks" xmlns:icon="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:lib="clr-namespace:Wabbajack.Lib;assembly=Wabbajack.Lib"
xmlns:local="clr-namespace:Wabbajack" xmlns:local="clr-namespace:Wabbajack"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DataContext="{d:DesignInstance local:InstallerVM}" d:DataContext="{d:DesignInstance local:InstallerVM}"
@ -344,12 +346,59 @@
Margin="5,0,5,5" Margin="5,0,5,5"
Visibility="{Binding InstallingMode, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Hidden}"> Visibility="{Binding InstallingMode, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Hidden}">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="3*" />
<ColumnDefinition Width="5" /> <ColumnDefinition Width="5" />
<ColumnDefinition Width="500" /> <ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:LogView Grid.Column="0" ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" /> <local:LogView Grid.Column="0" ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" />
<local:CpuView Grid.Column="2" 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"
Background="{StaticResource SecondaryBackgroundBrush}"
BorderBrush="{StaticResource SecondaryBrush}"
BorderThickness="1"
Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsNotNullVisibilityConverter}}">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible, RelativeSource={RelativeSource AncestorType={x:Type Border}}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
To="{StaticResource DarkerSecondary}"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="{StaticResource WindowBackgroundColor}"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<ContentPresenter Content="{Binding ActiveGlobalUserIntervention}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type common:ConfirmationIntervention}">
<local:ConfirmationInterventionView />
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
</Grid> </Grid>
</Grid> </Grid>
</UserControl> </UserControl>

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

@ -172,6 +172,9 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</ApplicationDefinition> </ApplicationDefinition>
<Compile Include="Views\Interventions\ConfirmationInterventionView.xaml.cs">
<DependentUpon>ConfirmationInterventionView.xaml</DependentUpon>
</Compile>
<Compile Include="Converters\EqualsToBoolConverter.cs" /> <Compile Include="Converters\EqualsToBoolConverter.cs" />
<Compile Include="Views\Common\CpuView.xaml.cs"> <Compile Include="Views\Common\CpuView.xaml.cs">
<DependentUpon>CpuView.xaml</DependentUpon> <DependentUpon>CpuView.xaml</DependentUpon>
@ -259,6 +262,10 @@
<Compile Include="Views\WebBrowserView.xaml.cs"> <Compile Include="Views\WebBrowserView.xaml.cs">
<DependentUpon>WebBrowserView.xaml</DependentUpon> <DependentUpon>WebBrowserView.xaml</DependentUpon>
</Compile> </Compile>
<Page Include="Views\Interventions\ConfirmationInterventionView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Common\CpuView.xaml"> <Page Include="Views\Common\CpuView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -529,5 +536,8 @@
<ItemGroup> <ItemGroup>
<Resource Include="Resources\Wabba_Ded.png" /> <Resource Include="Resources\Wabba_Ded.png" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="View Models\Installers\User Interventions\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> </Project>