From 1bd8894a1fa103f3906541746dc6a6acfbbe46cf Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Sat, 25 Jul 2020 17:58:45 -0500 Subject: [PATCH] Error triangle under play button --- .../Error States/ErrorResponse.cs | 10 ++ .../View Models/Installers/ISubInstallerVM.cs | 2 +- .../View Models/Installers/InstallerVM.cs | 2 +- .../View Models/Installers/MO2InstallerVM.cs | 20 ++-- Wabbajack/Views/Common/CpuView.xaml.cs | 7 +- .../InstallationConfigurationView.xaml | 99 +++++++++++++++++++ .../InstallationConfigurationView.xaml.cs | 59 +++++++++++ .../Views/Installers/InstallationView.xaml | 67 +------------ .../Views/Installers/InstallationView.xaml.cs | 13 --- 9 files changed, 189 insertions(+), 90 deletions(-) create mode 100644 Wabbajack/Views/Installers/InstallationConfigurationView.xaml create mode 100644 Wabbajack/Views/Installers/InstallationConfigurationView.xaml.cs diff --git a/Wabbajack.Common/Error States/ErrorResponse.cs b/Wabbajack.Common/Error States/ErrorResponse.cs index c0fecf48..e06f4ed7 100644 --- a/Wabbajack.Common/Error States/ErrorResponse.cs +++ b/Wabbajack.Common/Error States/ErrorResponse.cs @@ -1,4 +1,5 @@ using System; +using DynamicData.Kernel; namespace Wabbajack { @@ -86,6 +87,15 @@ namespace Wabbajack if (err == null) return Create(nullIsSuccess); return new ErrorResponse(err.Succeeded, err.Reason, err.Exception); } + + public static ErrorResponse FirstFail(params ErrorResponse[] responses) + { + foreach (var resp in responses) + { + if (resp.Failed) return resp; + } + return ErrorResponse.Success; + } } public interface IErrorResponse diff --git a/Wabbajack/View Models/Installers/ISubInstallerVM.cs b/Wabbajack/View Models/Installers/ISubInstallerVM.cs index 0c69d559..85f2787e 100644 --- a/Wabbajack/View Models/Installers/ISubInstallerVM.cs +++ b/Wabbajack/View Models/Installers/ISubInstallerVM.cs @@ -17,7 +17,7 @@ namespace Wabbajack bool SupportsAfterInstallNavigation { get; } void AfterInstallNavigation(); int ConfigVisualVerticalOffset { get; } - IObservable CanInstall { get; } + ErrorResponse CanInstall { get; } Task Install(); IUserIntervention InterventionConverter(IUserIntervention intervention); } diff --git a/Wabbajack/View Models/Installers/InstallerVM.cs b/Wabbajack/View Models/Installers/InstallerVM.cs index 1e28d287..36156d4d 100644 --- a/Wabbajack/View Models/Installers/InstallerVM.cs +++ b/Wabbajack/View Models/Installers/InstallerVM.cs @@ -356,7 +356,7 @@ namespace Wabbajack BeginCommand = ReactiveCommand.CreateFromTask( canExecute: this.WhenAny(x => x.Installer.CanInstall) - .Switch(), + .Select(err => err.Succeeded), execute: async () => { try diff --git a/Wabbajack/View Models/Installers/MO2InstallerVM.cs b/Wabbajack/View Models/Installers/MO2InstallerVM.cs index cc2b4dbb..ed83ec2d 100644 --- a/Wabbajack/View Models/Installers/MO2InstallerVM.cs +++ b/Wabbajack/View Models/Installers/MO2InstallerVM.cs @@ -20,7 +20,8 @@ namespace Wabbajack { public InstallerVM Parent { get; } - public IObservable CanInstall { get; } + private readonly ObservableAsPropertyHelper _CanInstall; + public ErrorResponse CanInstall => _CanInstall.Value; [Reactive] public AInstaller ActiveInstallation { get; private set; } @@ -65,14 +66,15 @@ namespace Wabbajack .Select(i => MO2Installer.CheckValidInstallPath(i.target, i.download)) .ObserveOnGuiThread(); - CanInstall = Observable.CombineLatest( - this.WhenAny(x => x.Location.InError), - this.WhenAny(x => x.DownloadLocation.InError), - installerVM.WhenAny(x => x.ModListLocation.InError), - resultSelector: (loc, modlist, download) => - { - return !loc && !download && !modlist; - }); + _CanInstall = Observable.CombineLatest( + this.WhenAny(x => x.Location.ErrorState), + this.WhenAny(x => x.DownloadLocation.ErrorState), + installerVM.WhenAny(x => x.ModListLocation.ErrorState), + resultSelector: (loc, modlist, download) => + { + return ErrorResponse.FirstFail(loc, modlist, download); + }) + .ToProperty(this, nameof(CanInstall)); // Have Installation location updates modify the downloads location if empty this.WhenAny(x => x.Location.TargetPath) diff --git a/Wabbajack/Views/Common/CpuView.xaml.cs b/Wabbajack/Views/Common/CpuView.xaml.cs index 2e1eb6b6..d631f954 100644 --- a/Wabbajack/Views/Common/CpuView.xaml.cs +++ b/Wabbajack/Views/Common/CpuView.xaml.cs @@ -64,7 +64,12 @@ namespace Wabbajack .BindToStrict(this, x => x.CpuListControl.ItemsSource) .DisposeWith(disposable); - this.Bind(this.ViewModel, x => x.MWVM.Settings.Performance.TargetUsage, x => x.TargetPercentageSlider.Value) + this.BindStrict( + this.ViewModel, + x => x.MWVM.Settings.Performance.TargetUsage, + x => x.TargetPercentageSlider.Value, + vmToViewConverter: p => p.Value, + viewToVmConverter: d => new Percent(d)) .DisposeWith(disposable); this.WhenAny(x => x.ViewModel.MWVM.Settings.Performance.TargetUsage) diff --git a/Wabbajack/Views/Installers/InstallationConfigurationView.xaml b/Wabbajack/Views/Installers/InstallationConfigurationView.xaml new file mode 100644 index 00000000..225346f0 --- /dev/null +++ b/Wabbajack/Views/Installers/InstallationConfigurationView.xaml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wabbajack/Views/Installers/InstallationConfigurationView.xaml.cs b/Wabbajack/Views/Installers/InstallationConfigurationView.xaml.cs new file mode 100644 index 00000000..7e298345 --- /dev/null +++ b/Wabbajack/Views/Installers/InstallationConfigurationView.xaml.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Text; +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; +using ReactiveUI; + +namespace Wabbajack +{ + /// + /// Interaction logic for InstallationConfigurationView.xaml + /// + public partial class InstallationConfigurationView : ReactiveUserControl + { + public InstallationConfigurationView() + { + InitializeComponent(); + this.WhenActivated(dispose => + { + this.WhenAny(x => x.ViewModel.Installer.ConfigVisualVerticalOffset) + .Select(i => (double)i) + .BindToStrict(this, x => x.InstallConfigSpacer.Height) + .DisposeWith(dispose); + this.WhenAny(x => x.ViewModel.ModListLocation) + .BindToStrict(this, x => x.ModListLocationPicker.PickerVM) + .DisposeWith(dispose); + this.WhenAny(x => x.ViewModel.Installer) + .BindToStrict(this, x => x.InstallerCustomizationContent.Content) + .DisposeWith(dispose); + this.WhenAny(x => x.ViewModel.BeginCommand) + .BindToStrict(this, x => x.BeginButton.Command) + .DisposeWith(dispose); + + // Error icon display + var vis = this.WhenAny(x => x.ViewModel.Installer.CanInstall) + .Select(err => err.Failed ? Visibility.Visible : Visibility.Hidden) + .Replay(1) + .RefCount(); + vis.BindToStrict(this, x => x.ErrorSummaryIconGlow.Visibility) + .DisposeWith(dispose); + vis.BindToStrict(this, x => x.ErrorSummaryIcon.Visibility) + .DisposeWith(dispose); + this.WhenAny(x => x.ViewModel.Installer.CanInstall) + .Select(x => x.Reason) + .BindToStrict(this, x => x.ErrorSummaryIcon.ToolTip) + .DisposeWith(dispose); + }); + } + } +} diff --git a/Wabbajack/Views/Installers/InstallationView.xaml b/Wabbajack/Views/Installers/InstallationView.xaml index ed4ce7b1..3929cd66 100644 --- a/Wabbajack/Views/Installers/InstallationView.xaml +++ b/Wabbajack/Views/Installers/InstallationView.xaml @@ -284,72 +284,9 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + ViewModel="{Binding}" /> started ? Visibility.Collapsed : Visibility.Visible) .BindToStrict(this, x => x.InstallationConfigurationView.Visibility) .DisposeWith(dispose); - this.WhenAny(x => x.ViewModel.Installer.ConfigVisualVerticalOffset) - .Select(i => (double)i) - .BindToStrict(this, x => x.InstallConfigSpacer.Height) - .DisposeWith(dispose); - this.WhenAny(x => x.ViewModel.ModListLocation) - .BindToStrict(this, x => x.ModListLocationPicker.PickerVM) - .DisposeWith(dispose); - this.WhenAny(x => x.ViewModel.Installer) - .BindToStrict(this, x => x.InstallerCustomizationContent.Content) - .DisposeWith(dispose); - this.WhenAny(x => x.ViewModel.BeginCommand) - .BindToStrict(this, x => x.BeginButton.Command) - .DisposeWith(dispose); // Bottom mid-install display this.WhenAny(x => x.ViewModel.StartedInstallation)