Merge branch 'master' into bunny-cdn-push

This commit is contained in:
Timothy Baldridge 2020-01-21 20:46:10 -07:00 committed by GitHub
commit 1e2e364688
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 1075 additions and 580 deletions

View File

@ -1,5 +1,9 @@
### Changelog ### Changelog
=======
* Fix for website readme compilation
* Fix for compiler downloads folder specification (was always standard path)
#### Version - 1.0 beta 16 - 1/19/2020 #### Version - 1.0 beta 16 - 1/19/2020
* Progress ring displays when downloading modlist images * Progress ring displays when downloading modlist images
* GUI releases memory of download modlists better when navigating around * GUI releases memory of download modlists better when navigating around

View File

@ -1,3 +1,13 @@
The Wabbajack Codebase is under the GPLv3 license.
Modlists produced by Wabbajack under the [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/)
As such, Wabbajack modlists may *not* be paywalled (be it beta
pre-release or otherwise). Any quid-pro-quo payment structure in connection
with Wabbajack lists is strictly prohibited.
----------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007

View File

@ -125,6 +125,17 @@ Look at the [`CONTRIBUTING.md`](https://github.com/halgari/wabbajack/blob/master
I (_halgari_) used to be a developer working on Automaton. Sadly development was moving a bit too slowly for my liking, and I realized that a complete rewrite would allow the implementation of some really nice features (like BSA packing). As such I made the decision to strike out on my own and make an app that worked first, and then make it pretty. The end result is an app with a ton of features, and a less than professional UI. But that's my motto when coding "_make it work, then make it pretty_". I (_halgari_) used to be a developer working on Automaton. Sadly development was moving a bit too slowly for my liking, and I realized that a complete rewrite would allow the implementation of some really nice features (like BSA packing). As such I made the decision to strike out on my own and make an app that worked first, and then make it pretty. The end result is an app with a ton of features, and a less than professional UI. But that's my motto when coding "_make it work, then make it pretty_".
**Can I charge for a Wabbajack Modlist I created?**
No, as specified in the license, Wabbajack modlists must be available for free. Any payment in exchange for access to a Wabbajack
installer is strictly prohibited. This includes paywalling, "pay for beta access", "pay for current version, previous version is free",
or any sort of other quid-pro-quo monitization structure. The Wabbajack team reserves the right to implement software that will prohibit the installation of any lists that are paywalled.
**Can I accept donations for my installer?**
Absolutely! As long as the act of donating does not entitle the donator to access to the installer. The installer must be free,
donations must be a "thank you" not a purchase of services or content.
## Thanks to ## Thanks to
Our testers and Discord members who encourage development and help test the builds. Our testers and Discord members who encourage development and help test the builds.

View File

@ -24,12 +24,12 @@
<PackageReference Include="ini-parser-netstandard" Version="2.5.2" /> <PackageReference Include="ini-parser-netstandard" Version="2.5.2" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" /> <PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="ReactiveUI" Version="11.1.11" /> <PackageReference Include="ReactiveUI" Version="11.1.12" />
<PackageReference Include="SharpZipLib" Version="1.2.0" /> <PackageReference Include="SharpZipLib" Version="1.2.0" />
<PackageReference Include="System.Data.HashFunction.xxHash" Version="2.0.0" /> <PackageReference Include="System.Data.HashFunction.xxHash" Version="2.0.0" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.7.0" /> <PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.7.0" />
<PackageReference Include="System.Security.Principal.Windows" Version="4.7.0" /> <PackageReference Include="System.Security.Principal.Windows" Version="4.7.0" />
<PackageReference Include="YamlDotNet" Version="8.0.0" /> <PackageReference Include="YamlDotNet" Version="8.1.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Compression.BSA\Compression.BSA.csproj" /> <ProjectReference Include="..\Compression.BSA\Compression.BSA.csproj" />

View File

@ -22,7 +22,7 @@
<Version>0.15.1</Version> <Version>0.15.1</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Fody"> <PackageReference Include="Fody">
<Version>6.0.6</Version> <Version>6.0.7</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Genbox.AlphaFS"> <PackageReference Include="Genbox.AlphaFS">
<Version>2.2.2.1</Version> <Version>2.2.2.1</Version>
@ -49,10 +49,10 @@
<Version>2.10.1</Version> <Version>2.10.1</Version>
</PackageReference> </PackageReference>
<PackageReference Include="ReactiveUI"> <PackageReference Include="ReactiveUI">
<Version>11.1.11</Version> <Version>11.1.12</Version>
</PackageReference> </PackageReference>
<PackageReference Include="ReactiveUI.Fody"> <PackageReference Include="ReactiveUI.Fody">
<Version>11.1.11</Version> <Version>11.1.12</Version>
</PackageReference> </PackageReference>
<PackageReference Include="SharpCompress"> <PackageReference Include="SharpCompress">
<Version>0.24.0</Version> <Version>0.24.0</Version>

View File

@ -188,7 +188,7 @@
<Version>12.0.3</Version> <Version>12.0.3</Version>
</PackageReference> </PackageReference>
<PackageReference Include="ReactiveUI"> <PackageReference Include="ReactiveUI">
<Version>11.1.11</Version> <Version>11.1.12</Version>
</PackageReference> </PackageReference>
<PackageReference Include="System.Reactive"> <PackageReference Include="System.Reactive">
<Version>4.3.2</Version> <Version>4.3.2</Version>

View File

@ -12,6 +12,7 @@
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
<ResourceDictionary Source="Themes\Styles.xaml" /> <ResourceDictionary Source="Themes\Styles.xaml" />
<ResourceDictionary Source="Themes\CustomControls.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
</Application.Resources> </Application.Resources>

View File

@ -54,6 +54,26 @@ namespace Wabbajack
viewProperty: viewProperty); viewProperty: viewProperty);
} }
public static IReactiveBinding<TView, TViewModel, (object view, bool isViewModel)> BindStrict<TViewModel, TView, TVMProp, TVProp, TDontCare>(
this TView view,
TViewModel viewModel,
Expression<Func<TViewModel, TVMProp>> vmProperty,
Expression<Func<TView, TVProp>> viewProperty,
IObservable<TDontCare> signalViewUpdate,
Func<TVMProp, TVProp> vmToViewConverter,
Func<TVProp, TVMProp> viewToVmConverter)
where TViewModel : class
where TView : class, IViewFor
{
return view.Bind(
viewModel: viewModel,
vmProperty: vmProperty,
viewProperty: viewProperty,
signalViewUpdate: signalViewUpdate,
vmToViewConverter: vmToViewConverter,
viewToVmConverter: viewToVmConverter);
}
public static IReactiveBinding<TView, TViewModel, (object view, bool isViewModel)> BindStrict<TViewModel, TView, TVMProp, TVProp>( public static IReactiveBinding<TView, TViewModel, (object view, bool isViewModel)> BindStrict<TViewModel, TView, TVMProp, TVProp>(
this TView view, this TView view,
TViewModel viewModel, TViewModel viewModel,
@ -78,7 +98,9 @@ namespace Wabbajack
Expression<Func<TTarget, TValue>> property) Expression<Func<TTarget, TValue>> property)
where TTarget : class where TTarget : class
{ {
return @this.BindTo<TValue, TTarget, TValue>(target, property); return @this
.ObserveOnGuiThread()
.BindTo<TValue, TTarget, TValue>(target, property);
} }
/// <summary> /// <summary>

View File

@ -0,0 +1,118 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wabbajack">
<Style TargetType="local:AttentionBorder">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:AttentionBorder">
<Border BorderThickness="1">
<Border.Style>
<Style TargetType="Border">
<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" />
<Condition Binding="{Binding Failure, RelativeSource={RelativeSource AncestorType={x:Type local:AttentionBorder}}}" Value="False" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
To="{StaticResource Secondary}"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<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>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsVisible, RelativeSource={RelativeSource Self}}" Value="True" />
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="False" />
<Condition Binding="{Binding Failure, RelativeSource={RelativeSource AncestorType={x:Type local:AttentionBorder}}}" Value="True" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
To="#ff0026"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="#540914"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
To="#700d1c"
Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="#1c0307"
Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@ -48,9 +48,9 @@ namespace Wabbajack
public ObservableCollectionExtended<IStatusMessage> Log => MWVM.Log; public ObservableCollectionExtended<IStatusMessage> Log => MWVM.Log;
public ReactiveCommand<Unit, Unit> BackCommand { get; } public ReactiveCommand<Unit, Unit> BackCommand { get; }
public IReactiveCommand GoToModlistCommand { get; } public ReactiveCommand<Unit, Unit> GoToModlistCommand { get; }
public IReactiveCommand CloseWhenCompleteCommand { get; } public ReactiveCommand<Unit, Unit> CloseWhenCompleteCommand { get; }
public IReactiveCommand BeginCommand { get; } public ReactiveCommand<Unit, Unit> BeginCommand { get; }
public FilePickerVM OutputLocation { get; } public FilePickerVM OutputLocation { get; }

View File

@ -189,6 +189,7 @@ namespace Wabbajack
ModListWebsite = ModlistSettings.Website, ModListWebsite = ModlistSettings.Website,
ModListReadme = ModlistSettings.ReadmeIsWebsite ? ModlistSettings.ReadmeWebsite : ModlistSettings.ReadmeFilePath.TargetPath, ModListReadme = ModlistSettings.ReadmeIsWebsite ? ModlistSettings.ReadmeWebsite : ModlistSettings.ReadmeFilePath.TargetPath,
ReadmeIsWebsite = ModlistSettings.ReadmeIsWebsite, ReadmeIsWebsite = ModlistSettings.ReadmeIsWebsite,
MO2DownloadsFolder = DownloadLocation.TargetPath,
}) })
{ {
Parent.MWVM.Settings.Performance.AttachToBatchProcessor(ActiveCompilation); Parent.MWVM.Settings.Performance.AttachToBatchProcessor(ActiveCompilation);

View File

@ -19,5 +19,6 @@ namespace Wabbajack
int ConfigVisualVerticalOffset { get; } int ConfigVisualVerticalOffset { get; }
IObservable<bool> CanInstall { get; } IObservable<bool> CanInstall { get; }
Task<bool> Install(); Task<bool> Install();
IUserIntervention InterventionConverter(IUserIntervention intervention);
} }
} }

View File

@ -96,13 +96,13 @@ namespace Wabbajack
public bool IsActive => _IsActive.Value; public bool IsActive => _IsActive.Value;
// Command properties // Command properties
public IReactiveCommand ShowReportCommand { get; } public ReactiveCommand<Unit, Unit> ShowManifestCommand { get; }
public IReactiveCommand OpenReadmeCommand { get; } public ReactiveCommand<Unit, Unit> OpenReadmeCommand { get; }
public IReactiveCommand VisitWebsiteCommand { get; } public ReactiveCommand<Unit, Unit> VisitModListWebsiteCommand { get; }
public ReactiveCommand<Unit, Unit> BackCommand { get; } public ReactiveCommand<Unit, Unit> BackCommand { get; }
public IReactiveCommand CloseWhenCompleteCommand { get; } public ReactiveCommand<Unit, Unit> CloseWhenCompleteCommand { get; }
public IReactiveCommand GoToInstallCommand { get; } public ReactiveCommand<Unit, Unit> GoToInstallCommand { get; }
public IReactiveCommand BeginCommand { get; } public ReactiveCommand<Unit, Unit> BeginCommand { get; }
public InstallerVM(MainWindowVM mainWindowVM) public InstallerVM(MainWindowVM mainWindowVM)
{ {
@ -317,14 +317,18 @@ namespace Wabbajack
.ToGuiProperty(this, nameof(ModListName)); .ToGuiProperty(this, nameof(ModListName));
// Define commands // Define commands
ShowReportCommand = ReactiveCommand.Create(ShowReport); ShowManifestCommand = ReactiveCommand.Create(ShowReport);
OpenReadmeCommand = ReactiveCommand.Create( OpenReadmeCommand = ReactiveCommand.Create(
execute: () => this.ModList?.OpenReadmeWindow(), execute: () => this.ModList?.OpenReadmeWindow(),
canExecute: this.WhenAny(x => x.ModList) canExecute: this.WhenAny(x => x.ModList)
.Select(modList => !string.IsNullOrEmpty(modList?.Readme)) .Select(modList => !string.IsNullOrEmpty(modList?.Readme))
.ObserveOnGuiThread()); .ObserveOnGuiThread());
VisitWebsiteCommand = ReactiveCommand.Create( VisitModListWebsiteCommand = ReactiveCommand.Create(
execute: () => Process.Start(ModList.Website), execute: () =>
{
Process.Start(ModList.Website);
return Unit.Default;
},
canExecute: this.WhenAny(x => x.ModList.Website) canExecute: this.WhenAny(x => x.ModList.Website)
.Select(x => x?.StartsWith("https://") ?? false) .Select(x => x?.StartsWith("https://") ?? false)
.ObserveOnGuiThread()); .ObserveOnGuiThread());
@ -393,11 +397,19 @@ namespace Wabbajack
// Listen for user interventions, and compile a dynamic list of all unhandled ones // Listen for user interventions, and compile a dynamic list of all unhandled ones
var activeInterventions = this.WhenAny(x => x.Installer.ActiveInstallation) var activeInterventions = this.WhenAny(x => x.Installer.ActiveInstallation)
.SelectMany(c => c?.LogMessages ?? Observable.Empty<IStatusMessage>()) .WithLatestFrom(
this.WhenAny(x => x.Installer),
(activeInstall, installer) =>
{
if (activeInstall == null) return Observable.Empty<IChangeSet<IUserIntervention>>();
return activeInstall.LogMessages
.WhereCastable<IStatusMessage, IUserIntervention>() .WhereCastable<IStatusMessage, IUserIntervention>()
.ToObservableChangeSet() .ToObservableChangeSet()
.AutoRefresh(i => i.Handled) .AutoRefresh(i => i.Handled)
.Filter(i => !i.Handled) .Filter(i => !i.Handled)
.Transform(x => installer.InterventionConverter(x));
})
.Switch()
.AsObservableList(); .AsObservableList();
// Find the top intervention /w no CPU ID to be marked as "global" // Find the top intervention /w no CPU ID to be marked as "global"

View File

@ -169,5 +169,16 @@ namespace Wabbajack
}); });
} }
} }
public IUserIntervention InterventionConverter(IUserIntervention intervention)
{
switch (intervention)
{
case ConfirmUpdateOfExistingInstall confirm:
return new ConfirmUpdateOfExistingInstallVM(this, confirm);
default:
return intervention;
}
}
} }
} }

View File

@ -87,5 +87,7 @@ namespace Wabbajack
}); });
} }
} }
public IUserIntervention InterventionConverter(IUserIntervention intervention) => intervention;
} }
} }

View File

@ -10,6 +10,8 @@ using System.Threading.Tasks;
using DynamicData; using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Wabbajack.Common;
using Wabbajack.Lib; using Wabbajack.Lib;
using Wabbajack.Lib.ModListRegistry; using Wabbajack.Lib.ModListRegistry;
@ -23,6 +25,9 @@ namespace Wabbajack
private int missingHashFallbackCounter; private int missingHashFallbackCounter;
[Reactive]
public IErrorResponse Error { get; set; }
public ModListGalleryVM(MainWindowVM mainWindowVM) public ModListGalleryVM(MainWindowVM mainWindowVM)
: base(mainWindowVM) : base(mainWindowVM)
{ {
@ -32,8 +37,18 @@ namespace Wabbajack
.ObserveOn(RxApp.TaskpoolScheduler) .ObserveOn(RxApp.TaskpoolScheduler)
.SelectTask(async _ => .SelectTask(async _ =>
{ {
return (await ModlistMetadata.LoadFromGithub()) try
.AsObservableChangeSet(x => x.DownloadMetadata?.Hash ?? $"Fallback{missingHashFallbackCounter++}"); {
Error = null;
var list = await ModlistMetadata.LoadFromGithub();
return list.AsObservableChangeSet(x => x.DownloadMetadata?.Hash ?? $"Fallback{missingHashFallbackCounter++}");
}
catch (Exception ex)
{
Utils.Error(ex);
Error = ErrorResponse.Fail(ex);
return Observable.Empty<IChangeSet<ModlistMetadata, string>>();
}
}) })
// Unsubscribe and release when not active // Unsubscribe and release when not active
.FlowSwitch( .FlowSwitch(

View File

@ -166,7 +166,9 @@ namespace Wabbajack
} }
}); });
await Metrics.Send(Metrics.Downloading, Metadata.Title);
Task.Run(() => Metrics.Send(Metrics.Downloading, Metadata.Title))
.FireAndForget(ex => Utils.Error(ex, "Error sending download metric"));
return await tcs.Task; return await tcs.Task;
} }

View File

@ -94,7 +94,7 @@ namespace Wabbajack
public void OpenReadmeWindow() public void OpenReadmeWindow()
{ {
if (string.IsNullOrEmpty(Readme)) return; if (string.IsNullOrEmpty(Readme)) return;
if (false) //SourceModList.ReadmeIsWebsite) if (SourceModList.ReadmeIsWebsite)
{ {
Process.Start(Readme); Process.Start(Readme);
} }

View File

@ -32,8 +32,8 @@ namespace Wabbajack
private readonly ObservableAsPropertyHelper<ModVM> _targetMod; private readonly ObservableAsPropertyHelper<ModVM> _targetMod;
public ModVM TargetMod => _targetMod.Value; public ModVM TargetMod => _targetMod.Value;
public IReactiveCommand SlideShowNextItemCommand { get; } = ReactiveCommand.Create(() => { }); public ReactiveCommand<Unit, Unit> SlideShowNextItemCommand { get; } = ReactiveCommand.Create(() => { });
public IReactiveCommand VisitNexusSiteCommand { get; } public ReactiveCommand<Unit, Unit> VisitNexusSiteCommand { get; }
public const int PreloadAmount = 4; public const int PreloadAmount = 4;
@ -119,7 +119,11 @@ namespace Wabbajack
.ToGuiProperty(this, nameof(Image)); .ToGuiProperty(this, nameof(Image));
VisitNexusSiteCommand = ReactiveCommand.Create( VisitNexusSiteCommand = ReactiveCommand.Create(
execute: () => Process.Start(TargetMod.ModURL), execute: () =>
{
Process.Start(TargetMod.ModURL);
return Unit.Default;
},
canExecute: this.WhenAny(x => x.TargetMod.ModURL) canExecute: this.WhenAny(x => x.TargetMod.ModURL)
.Select(x => x?.StartsWith("https://") ?? false) .Select(x => x?.StartsWith("https://") ?? false)
.ObserveOnGuiThread()); .ObserveOnGuiThread());

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wabbajack.Common;
using Wabbajack.Lib;
namespace Wabbajack
{
public class ConfirmUpdateOfExistingInstallVM : ViewModel, IUserIntervention
{
public ConfirmUpdateOfExistingInstall Source { get; }
public MO2InstallerVM Installer { get; }
public bool Handled => ((IUserIntervention)Source).Handled;
public int CpuID => ((IUserIntervention)Source).CpuID;
public DateTime Timestamp => ((IUserIntervention)Source).Timestamp;
public string ShortDescription => ((IUserIntervention)Source).ShortDescription;
public string ExtendedDescription => ((IUserIntervention)Source).ExtendedDescription;
public ConfirmUpdateOfExistingInstallVM(MO2InstallerVM installer, ConfirmUpdateOfExistingInstall confirm)
{
Source = confirm;
Installer = installer;
}
public void Cancel()
{
((IUserIntervention)Source).Cancel();
}
}
}

View File

@ -20,14 +20,6 @@ namespace Wabbajack
/// </summary> /// </summary>
public partial class AttentionBorder : UserControl public partial class AttentionBorder : UserControl
{ {
public object DisplayContent
{
get => (object)GetValue(DisplayContentProperty);
set => SetValue(DisplayContentProperty, value);
}
public static readonly DependencyProperty DisplayContentProperty = DependencyProperty.Register(nameof(DisplayContent), typeof(object), typeof(AttentionBorder),
new FrameworkPropertyMetadata(default(object)));
public bool Failure public bool Failure
{ {
get => (bool)GetValue(FailureProperty); get => (bool)GetValue(FailureProperty);
@ -35,10 +27,5 @@ namespace Wabbajack
} }
public static readonly DependencyProperty FailureProperty = DependencyProperty.Register(nameof(Failure), typeof(bool), typeof(AttentionBorder), public static readonly DependencyProperty FailureProperty = DependencyProperty.Register(nameof(Failure), typeof(bool), typeof(AttentionBorder),
new FrameworkPropertyMetadata(default(bool))); new FrameworkPropertyMetadata(default(bool)));
public AttentionBorder()
{
InitializeComponent();
}
} }
} }

View File

@ -1,116 +0,0 @@
<UserControl
x:Class="Wabbajack.AttentionBorder"
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">
<Border BorderThickness="1">
<Border.Style>
<Style TargetType="Border">
<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" />
<Condition Binding="{Binding Failure, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Value="False" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
To="{StaticResource Secondary}"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<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>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsVisible, RelativeSource={RelativeSource Self}}" Value="True" />
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="False" />
<Condition Binding="{Binding Failure, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Value="True" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
To="#ff0026"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="#540914"
Duration="0:0:1.5" />
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
To="#700d1c"
Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
To="#1c0307"
Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<ContentPresenter Content="{Binding DisplayContent, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
</Border>
</UserControl>

View File

@ -40,7 +40,7 @@ namespace Wabbajack
set => SetValue(SettingsHookProperty, value); set => SetValue(SettingsHookProperty, value);
} }
public static readonly DependencyProperty SettingsHookProperty = DependencyProperty.Register(nameof(SettingsHook), typeof(MainSettings), typeof(CpuView), public static readonly DependencyProperty SettingsHookProperty = DependencyProperty.Register(nameof(SettingsHook), typeof(MainSettings), typeof(CpuView),
new FrameworkPropertyMetadata(default(SettingsVM))); new FrameworkPropertyMetadata(default(SettingsVM), WireNotifyPropertyChanged));
private bool _ShowingSettings; private bool _ShowingSettings;
public bool ShowingSettings { get => _ShowingSettings; set => this.RaiseAndSetIfChanged(ref _ShowingSettings, value); } public bool ShowingSettings { get => _ShowingSettings; set => this.RaiseAndSetIfChanged(ref _ShowingSettings, value); }

View File

@ -1,4 +1,4 @@
<UserControl <rxui:ReactiveUserControl
x:Class="Wabbajack.CompilationCompleteView" x:Class="Wabbajack.CompilationCompleteView"
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"
@ -6,11 +6,12 @@
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"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rxui="http://reactiveui.net"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
x:TypeArguments="local:CompilerVM"
mc:Ignorable="d"> mc:Ignorable="d">
<local:AttentionBorder ClipToBounds="True" Failure="{Binding Completed.Failed}"> <local:AttentionBorder x:Name="AttentionBorder" ClipToBounds="True">
<local:AttentionBorder.DisplayContent>
<Grid Margin="5"> <Grid Margin="5">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
@ -22,6 +23,7 @@
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock <TextBlock
x:Name="TitleText"
Grid.Row="0" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
@ -33,16 +35,6 @@
<TextBlock.Effect> <TextBlock.Effect>
<DropShadowEffect BlurRadius="25" Opacity="0.5" /> <DropShadowEffect BlurRadius="25" Opacity="0.5" />
</TextBlock.Effect> </TextBlock.Effect>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="Compilation Complete" />
<Style.Triggers>
<DataTrigger Binding="{Binding Completed.Failed}" Value="True">
<Setter Property="Text" Value="Compilation Failed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock> </TextBlock>
<Grid <Grid
Grid.Row="1" Grid.Row="1"
@ -53,10 +45,10 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Button <Button
x:Name="BackButton"
Grid.Row="0" Grid.Row="0"
Width="55" Width="55"
Height="55" Height="55"
Command="{Binding BackCommand}"
Style="{StaticResource CircleButtonStyle}"> Style="{StaticResource CircleButtonStyle}">
<icon:PackIconMaterial <icon:PackIconMaterial
Width="28" Width="28"
@ -73,16 +65,15 @@
<Grid <Grid
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
VerticalAlignment="Center" VerticalAlignment="Center">
Visibility="{Binding CompilerSupportsAfterCompileNavigation, Converter={StaticResource bool2VisibilityConverter}}">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Button <Button
x:Name="GoToModlistButton"
Width="55" Width="55"
Height="55" Height="55"
Command="{Binding GoToModlistCommand}"
Style="{StaticResource CircleButtonStyle}"> Style="{StaticResource CircleButtonStyle}">
<icon:PackIconMaterial <icon:PackIconMaterial
Width="25" Width="25"
@ -128,9 +119,9 @@
</Button.Effect> </Button.Effect>
</Button>--> </Button>-->
<Button <Button
x:Name="CloseWhenCompletedButton"
Width="55" Width="55"
Height="55" Height="55"
Command="{Binding CloseWhenCompleteCommand}"
Style="{StaticResource CircleButtonStyle}"> Style="{StaticResource CircleButtonStyle}">
<icon:PackIconMaterial <icon:PackIconMaterial
Width="30" Width="30"
@ -145,6 +136,5 @@
Text="Close" /> Text="Close" />
</Grid> </Grid>
</Grid> </Grid>
</local:AttentionBorder.DisplayContent>
</local:AttentionBorder> </local:AttentionBorder>
</UserControl> </rxui:ReactiveUserControl>

View File

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
@ -12,17 +14,42 @@ using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Shapes; using System.Windows.Shapes;
using ReactiveUI;
namespace Wabbajack namespace Wabbajack
{ {
/// <summary> /// <summary>
/// Interaction logic for CompilationCompleteView.xaml /// Interaction logic for CompilationCompleteView.xaml
/// </summary> /// </summary>
public partial class CompilationCompleteView : UserControl public partial class CompilationCompleteView : ReactiveUserControl<CompilerVM>
{ {
public CompilationCompleteView() public CompilationCompleteView()
{ {
InitializeComponent(); InitializeComponent();
this.WhenActivated(dispose =>
{
this.WhenAny(x => x.ViewModel.Completed)
.Select(x => x?.Failed ?? false)
.BindToStrict(this, x => x.AttentionBorder.Failure)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Completed)
.Select(x => x?.Failed ?? false)
.Select(failed =>
{
return $"Compilation {(failed ? "Failed" : "Complete")}";
})
.BindToStrict(this, x => x.TitleText.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.BackCommand)
.BindToStrict(this, x => x.BackButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.GoToModlistCommand)
.BindToStrict(this, x => x.GoToModlistButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CloseWhenCompleteCommand)
.BindToStrict(this, x => x.CloseWhenCompletedButton.Command)
.DisposeWith(dispose);
});
} }
} }
} }

View File

@ -1,4 +1,4 @@
<UserControl <rxui:ReactiveUserControl
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"
@ -8,10 +8,12 @@
xmlns:local="clr-namespace:Wabbajack" xmlns:local="clr-namespace:Wabbajack"
xmlns:mahapps="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:mahapps="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rxui="http://reactiveui.net"
xmlns:wabbacommon="clr-namespace:Wabbajack.Common;assembly=Wabbajack.Common" xmlns:wabbacommon="clr-namespace:Wabbajack.Common;assembly=Wabbajack.Common"
d:DataContext="{d:DesignInstance local:CompilerVM}" d:DataContext="{d:DesignInstance local:CompilerVM}"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
x:TypeArguments="local:CompilerVM"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
@ -27,11 +29,11 @@
<ColumnDefinition Width="5" /> <ColumnDefinition Width="5" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:HeatedBackgroundView <local:HeatedBackgroundView
x:Name="HeatedBackground"
Grid.Row="0" Grid.Row="0"
Grid.RowSpan="3" Grid.RowSpan="3"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="5" Grid.ColumnSpan="5" />
PercentCompleted="{Binding PercentCompleted}" />
<Border <Border
x:Name="ModlistDetailsBackground" x:Name="ModlistDetailsBackground"
Grid.Row="1" Grid.Row="1"
@ -54,30 +56,22 @@
Grid.ColumnSpan="2" Grid.ColumnSpan="2"
Margin="1,1,5,0" Margin="1,1,5,0"
BorderBrush="{StaticResource HeatedBorderBrush}" BorderBrush="{StaticResource HeatedBorderBrush}"
BorderThickness="1" BorderThickness="1" />
Opacity="{Binding PercentCompleted}" />
<Border <Border
Grid.Row="1" Grid.Row="1"
Grid.Column="3" Grid.Column="3"
BorderBrush="{StaticResource BorderInterestBrush}" BorderBrush="{StaticResource BorderInterestBrush}"
BorderThickness="1,0,1,1"> BorderThickness="1,0,1,1">
<local:DetailImageView <local:DetailImageView x:Name="DetailImage" BorderThickness="0" />
Title="{Binding CurrentModlistSettings.ModListName}"
Author="{Binding CurrentModlistSettings.AuthorText}"
BorderThickness="0"
Description="{Binding CurrentModlistSettings.Description}"
Image="{Binding Image}" />
</Border> </Border>
<!-- Comes after image area so shadow can overlay --> <!-- Comes after image area so shadow can overlay -->
<local:TopProgressView <local:TopProgressView
Title="{Binding CurrentModlistSettings.ModListName, Mode=OneWay}" x:Name="TopProgressBar"
Grid.Row="0" Grid.Row="0"
Grid.RowSpan="2" Grid.RowSpan="2"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="5" Grid.ColumnSpan="5"
OverhangShadow="True" OverhangShadow="True" />
ProgressPercent="{Binding PercentCompleted}"
StatePrefixTitle="{Binding ProgressTitle}" />
<Button <Button
x:Name="BackButton" x:Name="BackButton"
Grid.Row="0" Grid.Row="0"
@ -88,23 +82,21 @@
Margin="12,5,0,0" Margin="12,5,0,0"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Top" VerticalAlignment="Top"
Command="{Binding BackCommand}"
Style="{StaticResource IconCircleButtonStyle}" Style="{StaticResource IconCircleButtonStyle}"
ToolTip="Back to main menu"> ToolTip="Back to main menu">
<icon:PackIconMaterial Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" Kind="ArrowLeft" /> <icon:PackIconMaterial Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" Kind="ArrowLeft" />
</Button> </Button>
<ScrollViewer <ScrollViewer
x:Name="SettingsScrollViewer"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Margin="5" Margin="5"
Background="Transparent" Background="Transparent"
HorizontalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled"
IsEnabled="{Binding Compiling, Converter={StaticResource InverseBooleanConverter}}"
VerticalScrollBarVisibility="Auto"> VerticalScrollBarVisibility="Auto">
<StackPanel <StackPanel
Margin="0,5,0,0" Margin="0,5,0,0"
Background="Transparent" Background="Transparent"
DataContext="{Binding CurrentModlistSettings}"
Orientation="Vertical"> Orientation="Vertical">
<StackPanel.Resources> <StackPanel.Resources>
<Thickness <Thickness
@ -128,26 +120,26 @@
</Style> </Style>
</StackPanel.Resources> </StackPanel.Resources>
<TextBlock Margin="{StaticResource TitleMargin}" Text="ModList Name" /> <TextBlock Margin="{StaticResource TitleMargin}" Text="ModList Name" />
<TextBox Style="{StaticResource ValueStyle}" Text="{Binding ModListName, UpdateSourceTrigger=PropertyChanged}" /> <TextBox x:Name="ModListNameSetting" Style="{StaticResource ValueStyle}" />
<TextBlock Margin="{StaticResource TitleMargin}" Text="Author" /> <TextBlock Margin="{StaticResource TitleMargin}" Text="Author" />
<TextBox Style="{StaticResource ValueStyle}" Text="{Binding AuthorText, UpdateSourceTrigger=PropertyChanged}" /> <TextBox x:Name="AuthorNameSetting" Style="{StaticResource ValueStyle}" />
<TextBlock Margin="{StaticResource TitleMargin}" Text="Description" /> <TextBlock Margin="{StaticResource TitleMargin}" Text="Description" />
<TextBox <TextBox
x:Name="DescriptionSetting"
Height="150" Height="150"
mahapps:TextBoxHelper.Watermark="(700 characters max)" mahapps:TextBoxHelper.Watermark="(700 characters max)"
AcceptsReturn="True" AcceptsReturn="True"
AcceptsTab="False" AcceptsTab="False"
MaxLength="700" MaxLength="700"
Style="{StaticResource ValueStyle}" Style="{StaticResource ValueStyle}"
Text="{Binding Description, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock Margin="{StaticResource TitleMargin}" Text="Image" /> <TextBlock Margin="{StaticResource TitleMargin}" Text="Image" />
<local:FilePicker <local:FilePicker
PickerVM="{Binding ImagePath}" x:Name="ImageFilePicker"
Style="{StaticResource PickerStyle}" Style="{StaticResource PickerStyle}"
ToolTip="Path to an image to display for the modlist." /> ToolTip="Path to an image to display for the modlist." />
<TextBlock Margin="{StaticResource TitleMargin}" Text="Website" /> <TextBlock Margin="{StaticResource TitleMargin}" Text="Website" />
<TextBox Style="{StaticResource ValueStyle}" Text="{Binding Website, UpdateSourceTrigger=PropertyChanged}" /> <TextBox x:Name="WebsiteSetting" Style="{StaticResource ValueStyle}" />
<TextBlock <TextBlock
Margin="{StaticResource TitleMargin}" Margin="{StaticResource TitleMargin}"
Text="Readme" Text="Readme"
@ -159,30 +151,28 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:FilePicker <local:FilePicker
x:Name="ReadmeFilePickerSetting"
Grid.Column="0" Grid.Column="0"
Height="27" Height="27"
Margin="0,0,3,0" Margin="0,0,3,0"
VerticalAlignment="Center" VerticalAlignment="Center"
PickerVM="{Binding ReadmeFilePath}" ToolTip="Path to a readme file." />
ToolTip="Path to a readme file."
Visibility="{Binding ReadmeIsWebsite, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}" />
<TextBox <TextBox
x:Name="ReadmeWebsiteSetting"
Grid.Column="0" Grid.Column="0"
Height="27" Height="27"
Margin="0,0,3,0" Margin="0,0,3,0"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{Binding ReadmeWebsite}" ToolTip="Readme website" />
ToolTip="Readme website"
Visibility="{Binding ReadmeIsWebsite, Converter={StaticResource bool2VisibilityConverter}}" />
<Button <Button
x:Name="SwapToReadmeWebsiteButton"
Grid.Column="1" Grid.Column="1"
Width="27" Width="27"
Command="{Binding SwapToWebsiteReadmeCommand}"
ToolTip="Set readme to be a website"> ToolTip="Set readme to be a website">
<Button.Style> <Button.Style>
<Style BasedOn="{StaticResource IconBareButtonStyle}" TargetType="Button"> <Style BasedOn="{StaticResource IconBareButtonStyle}" TargetType="Button">
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding ReadmeIsWebsite}" Value="True"> <DataTrigger Binding="{Binding CurrentModlistSettings.ReadmeIsWebsite}" Value="True">
<Setter Property="Foreground" Value="{StaticResource SecondaryBrush}" /> <Setter Property="Foreground" Value="{StaticResource SecondaryBrush}" />
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>
@ -194,14 +184,14 @@
Kind="Web" /> Kind="Web" />
</Button> </Button>
<Button <Button
x:Name="SwapToReadmeFileButton"
Grid.Column="2" Grid.Column="2"
Width="27" Width="27"
Command="{Binding SwapToTextReadmeCommand}"
ToolTip="Source readme from a local file (txt | html)"> ToolTip="Source readme from a local file (txt | html)">
<Button.Style> <Button.Style>
<Style BasedOn="{StaticResource IconBareButtonStyle}" TargetType="Button"> <Style BasedOn="{StaticResource IconBareButtonStyle}" TargetType="Button">
<Style.Triggers> <Style.Triggers>
<DataTrigger Binding="{Binding ReadmeIsWebsite}" Value="False"> <DataTrigger Binding="{Binding CurrentModlistSettings.ReadmeIsWebsite}" Value="False">
<Setter Property="Foreground" Value="{StaticResource SecondaryBrush}" /> <Setter Property="Foreground" Value="{StaticResource SecondaryBrush}" />
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>
@ -228,10 +218,10 @@
Grid.ColumnSpan="5" Grid.ColumnSpan="5"
MaxWidth="1000"> MaxWidth="1000">
<Grid <Grid
x:Name="BottomCompilerSettingsGrid"
Margin="35,0,35,0" Margin="35,0,35,0"
VerticalAlignment="Center" VerticalAlignment="Center"
ClipToBounds="False" ClipToBounds="False">
Visibility="{Binding StartedCompilation, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@ -254,6 +244,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<local:ImageRadioButtonView <local:ImageRadioButtonView
x:Name="MO2CompilerButton"
Grid.Row="0" Grid.Row="0"
Height="35" Height="35"
Margin="4" Margin="4"
@ -263,6 +254,7 @@
</local:ImageRadioButtonView.Image> </local:ImageRadioButtonView.Image>
</local:ImageRadioButtonView> </local:ImageRadioButtonView>
<local:ImageRadioButtonView <local:ImageRadioButtonView
x:Name="VortexCompilerButton"
Grid.Row="1" Grid.Row="1"
Height="35" Height="35"
Margin="4" Margin="4"
@ -273,9 +265,9 @@
</local:ImageRadioButtonView> </local:ImageRadioButtonView>
</Grid> </Grid>
<ContentPresenter <ContentPresenter
x:Name="CustomCompilerSettingsPresenter"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1">
Content="{Binding Compiler}">
<ContentPresenter.Resources> <ContentPresenter.Resources>
<DataTemplate DataType="{x:Type local:MO2CompilerVM}"> <DataTemplate DataType="{x:Type local:MO2CompilerVM}">
<local:MO2CompilerConfigView /> <local:MO2CompilerConfigView />
@ -286,38 +278,37 @@
</ContentPresenter.Resources> </ContentPresenter.Resources>
</ContentPresenter> </ContentPresenter>
<local:BeginButton <local:BeginButton
x:Name="BeginButton"
Grid.Row="0" Grid.Row="0"
Grid.RowSpan="3" Grid.RowSpan="3"
Grid.Column="5" Grid.Column="5" />
Command="{Binding BeginCommand}" />
</Grid> </Grid>
</Grid> </Grid>
<Grid <Grid
x:Name="MidCompilationGrid"
Grid.Row="2" Grid.Row="2"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="5" Grid.ColumnSpan="5"
Margin="5" Margin="5">
Visibility="{Binding StartedCompilation, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Hidden}">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" /> <ColumnDefinition Width="4*" />
<ColumnDefinition Width="5" /> <ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" /> <ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:LogView Grid.Column="0" ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" /> <local:LogView x:Name="LogView" Grid.Column="0" />
<local:CpuView <local:CpuView
x:Name="CpuView"
Grid.Column="2" Grid.Column="2"
ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" ViewModel="{Binding}" />
SettingsHook="{Binding MWVM.Settings}" <local:AttentionBorder x:Name="UserInterventionsControl" Grid.Column="2">
ViewModel="{Binding}"
Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsNotNullVisibilityConverter}, ConverterParameter=False}" />
<local:AttentionBorder Grid.Column="2" Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsNotNullVisibilityConverter}}">
<local:AttentionBorder.DisplayContent>
<Grid> <Grid>
<local:ConfirmationInterventionView DataContext="{Binding ActiveGlobalUserIntervention}" Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsTypeVisibilityConverter}, ConverterParameter={x:Type common:ConfirmationIntervention}}" /> <local:ConfirmationInterventionView DataContext="{Binding ActiveGlobalUserIntervention}" Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsTypeVisibilityConverter}, ConverterParameter={x:Type common:ConfirmationIntervention}}" />
</Grid> </Grid>
</local:AttentionBorder.DisplayContent>
</local:AttentionBorder> </local:AttentionBorder>
<local:CompilationCompleteView Grid.Column="2" Visibility="{Binding Completed, Converter={StaticResource IsNotNullVisibilityConverter}, FallbackValue=Collapsed}" /> <local:CompilationCompleteView
x:Name="CompilationComplete"
Grid.Column="2"
ViewModel="{Binding}" />
</Grid> </Grid>
</Grid> </Grid>
</UserControl> </rxui:ReactiveUserControl>

View File

@ -1,15 +1,146 @@
using System.Windows.Controls; using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows.Controls;
using ReactiveUI;
using System.Windows;
using Wabbajack.Common;
namespace Wabbajack namespace Wabbajack
{ {
/// <summary> /// <summary>
/// Interaction logic for CompilerView.xaml /// Interaction logic for CompilerView.xaml
/// </summary> /// </summary>
public partial class CompilerView : UserControl public partial class CompilerView : ReactiveUserControl<CompilerVM>
{ {
public CompilerView() public CompilerView()
{ {
InitializeComponent(); InitializeComponent();
this.WhenActivated(dispose =>
{
// Bind percent completed chanes
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(f => (double)f)
.BindToStrict(this, x => x.HeatedBackground.PercentCompleted)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(f => (double)f)
.BindToStrict(this, x => x.ModlistDetailsHeatBorder.Opacity)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(f => (double)f)
.BindToStrict(this, x => x.TopProgressBar.ProgressPercent)
.DisposeWith(dispose);
// Bind detail image display
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ModListName)
.BindToStrict(this, x => x.DetailImage.Title)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.AuthorText)
.BindToStrict(this, x => x.DetailImage.Author)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.Description)
.BindToStrict(this, x => x.DetailImage.Description)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Image)
.BindToStrict(this, x => x.DetailImage.Image)
.DisposeWith(dispose);
// Top Progress Bar
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ModListName)
.BindToStrict(this, x => x.TopProgressBar.Title)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ProgressTitle)
.BindToStrict(this, x => x.TopProgressBar.StatePrefixTitle)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.BackCommand)
.BindToStrict(this, x => x.BackButton.Command)
.DisposeWith(dispose);
// Settings Panel
this.WhenAny(x => x.ViewModel.Compiling)
.Select(x => !x)
.BindToStrict(this, x => x.SettingsScrollViewer.IsEnabled)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.ModListName, x => x.ModListNameSetting.Text)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.AuthorText, x => x.AuthorNameSetting.Text)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.Description, x => x.DescriptionSetting.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ImagePath)
.BindToStrict(this, x => x.ImageFilePicker.PickerVM)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.Website, x => x.WebsiteSetting.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ReadmeFilePath)
.BindToStrict(this, x => x.ReadmeFilePickerSetting.PickerVM)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ReadmeIsWebsite)
.Select(isWebsite => isWebsite ? Visibility.Collapsed : Visibility.Visible)
.BindToStrict(this, x => x.ReadmeFilePickerSetting.Visibility)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.ReadmeWebsite, x => x.ReadmeWebsiteSetting.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ReadmeIsWebsite)
.Select(isWebsite => isWebsite ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.ReadmeWebsiteSetting.Visibility)
.DisposeWith(dispose);
this.MarkAsNeeded<CompilerView, CompilerVM, bool>(this.ViewModel, x => x.CurrentModlistSettings.ReadmeIsWebsite);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.SwapToWebsiteReadmeCommand)
.BindToStrict(this, x => x.SwapToReadmeWebsiteButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CurrentModlistSettings.SwapToTextReadmeCommand)
.BindToStrict(this, x => x.SwapToReadmeFileButton.Command)
.DisposeWith(dispose);
// Bottom Compiler Settings
this.WhenAny(x => x.ViewModel.StartedCompilation)
.Select(started => started ? Visibility.Hidden : Visibility.Visible)
.BindToStrict(this, x => x.BottomCompilerSettingsGrid.Visibility)
.DisposeWith(dispose);
// Seems to go into an infinite loop between each other. Need to research a better radio button style pattern
//this.BindStrict(this.ViewModel, x => x.SelectedCompilerType, x => x.MO2CompilerButton.IsChecked,
// vmToViewConverter: type => type == ModManager.MO2,
// viewToVmConverter: isChecked => isChecked ? ModManager.MO2 : ModManager.Vortex);
//this.BindStrict(this.ViewModel, x => x.SelectedCompilerType, x => x.MO2CompilerButton.IsChecked,
// vmToViewConverter: type => type == ModManager.Vortex,
// viewToVmConverter: isChecked => isChecked ? ModManager.Vortex : ModManager.MO2);
this.WhenAny(x => x.ViewModel.Compiler)
.BindToStrict(this, x => x.CustomCompilerSettingsPresenter.Content)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.BeginCommand)
.BindToStrict(this, x => x.BeginButton.Command)
.DisposeWith(dispose);
// Mid-compilation panel
this.WhenAny(x => x.ViewModel.StartedCompilation)
.Select(started => started ? Visibility.Visible : Visibility.Hidden)
.BindToStrict(this, x => x.MidCompilationGrid.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(f => (double)f)
.BindToStrict(this, x => x.LogView.ProgressPercent)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(f => (double)f)
.BindToStrict(this, x => x.CpuView.ProgressPercent)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.MWVM.Settings)
.BindToStrict(this, x => x.CpuView.SettingsHook)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ActiveGlobalUserIntervention)
.Select(x => x == null ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.CpuView.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ActiveGlobalUserIntervention)
.Select(x => x != null ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.UserInterventionsControl.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Completed)
.Select(x => x != null ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.CompilationComplete.Visibility)
.DisposeWith(dispose);
});
} }
} }
} }

View File

@ -1,4 +1,4 @@
<UserControl <rxui:ReactiveUserControl
x:Class="Wabbajack.InstallationCompleteView" x:Class="Wabbajack.InstallationCompleteView"
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"
@ -6,11 +6,12 @@
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"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rxui="http://reactiveui.net"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
x:TypeArguments="local:InstallerVM"
mc:Ignorable="d"> mc:Ignorable="d">
<local:AttentionBorder ClipToBounds="True" Failure="{Binding Completed.Failed}"> <local:AttentionBorder x:Name="AttentionBorder" ClipToBounds="True">
<local:AttentionBorder.DisplayContent>
<Grid Margin="5"> <Grid Margin="5">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
@ -23,6 +24,7 @@
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock <TextBlock
x:Name="TitleText"
Grid.Row="0" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="4" Grid.ColumnSpan="4"
@ -34,16 +36,6 @@
<TextBlock.Effect> <TextBlock.Effect>
<DropShadowEffect BlurRadius="25" Opacity="0.5" /> <DropShadowEffect BlurRadius="25" Opacity="0.5" />
</TextBlock.Effect> </TextBlock.Effect>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="Installation Complete" />
<Style.Triggers>
<DataTrigger Binding="{Binding Completed.Failed}" Value="True">
<Setter Property="Text" Value="Installation Failed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock> </TextBlock>
<Grid <Grid
Grid.Row="1" Grid.Row="1"
@ -54,10 +46,10 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Button <Button
x:Name="BackButton"
Grid.Row="0" Grid.Row="0"
Width="50" Width="50"
Height="50" Height="50"
Command="{Binding BackCommand}"
Style="{StaticResource CircleButtonStyle}"> Style="{StaticResource CircleButtonStyle}">
<icon:PackIconMaterial <icon:PackIconMaterial
Width="25" Width="25"
@ -81,9 +73,9 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Button <Button
x:Name="GoToInstallButton"
Width="50" Width="50"
Height="50" Height="50"
Command="{Binding GoToInstallCommand}"
Style="{StaticResource CircleButtonStyle}"> Style="{StaticResource CircleButtonStyle}">
<icon:PackIconMaterial <icon:PackIconMaterial
Width="23" Width="23"
@ -107,9 +99,9 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Button <Button
x:Name="OpenReadmeButton"
Width="50" Width="50"
Height="50" Height="50"
Command="{Binding OpenReadmeCommand}"
Style="{StaticResource CircleButtonStyle}"> Style="{StaticResource CircleButtonStyle}">
<icon:PackIconFontAwesome <icon:PackIconFontAwesome
Width="25" Width="25"
@ -133,9 +125,9 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Button <Button
x:Name="CloseButton"
Width="50" Width="50"
Height="50" Height="50"
Command="{Binding CloseWhenCompleteCommand}"
Style="{StaticResource CircleButtonStyle}"> Style="{StaticResource CircleButtonStyle}">
<icon:PackIconMaterial <icon:PackIconMaterial
Width="25" Width="25"
@ -150,6 +142,5 @@
Text="Close" /> Text="Close" />
</Grid> </Grid>
</Grid> </Grid>
</local:AttentionBorder.DisplayContent>
</local:AttentionBorder> </local:AttentionBorder>
</UserControl> </rxui:ReactiveUserControl>

View File

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
@ -12,17 +14,45 @@ using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Shapes; using System.Windows.Shapes;
using ReactiveUI;
namespace Wabbajack namespace Wabbajack
{ {
/// <summary> /// <summary>
/// Interaction logic for InstallationCompleteView.xaml /// Interaction logic for InstallationCompleteView.xaml
/// </summary> /// </summary>
public partial class InstallationCompleteView : UserControl public partial class InstallationCompleteView : ReactiveUserControl<InstallerVM>
{ {
public InstallationCompleteView() public InstallationCompleteView()
{ {
InitializeComponent(); InitializeComponent();
this.WhenActivated(dispose =>
{
this.WhenAny(x => x.ViewModel.Completed)
.Select(x => x?.Failed ?? false)
.BindToStrict(this, x => x.AttentionBorder.Failure)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Completed)
.Select(x => x?.Failed ?? false)
.Select(failed =>
{
return $"Installation {(failed ? "Failed" : "Complete")}";
})
.BindToStrict(this, x => x.TitleText.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.BackCommand)
.BindToStrict(this, x => x.BackButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.GoToInstallCommand)
.BindToStrict(this, x => x.GoToInstallButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.OpenReadmeCommand)
.BindToStrict(this, x => x.OpenReadmeButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CloseWhenCompleteCommand)
.BindToStrict(this, x => x.CloseButton.Command)
.DisposeWith(dispose);
});
} }
} }
} }

View File

@ -1,4 +1,4 @@
<UserControl <rxui:ReactiveUserControl
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"
@ -9,9 +9,11 @@
xmlns:local="clr-namespace:Wabbajack" xmlns:local="clr-namespace:Wabbajack"
xmlns:mahapps="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:mahapps="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rxui="http://reactiveui.net"
d:DataContext="{d:DesignInstance local:InstallerVM}" d:DataContext="{d:DesignInstance local:InstallerVM}"
d:DesignHeight="500" d:DesignHeight="500"
d:DesignWidth="800" d:DesignWidth="800"
x:TypeArguments="local:InstallerVM"
mc:Ignorable="d"> mc:Ignorable="d">
<UserControl.Resources> <UserControl.Resources>
<Style <Style
@ -41,21 +43,17 @@
</Rectangle.Fill> </Rectangle.Fill>
</Rectangle> </Rectangle>
<local:HeatedBackgroundView <local:HeatedBackgroundView
x:Name="HeatedBackground"
Grid.Row="0" Grid.Row="0"
Grid.RowSpan="3" Grid.RowSpan="3" />
PercentCompleted="{Binding PercentCompleted}" />
<Grid <Grid
x:Name="Slideshow" x:Name="Slideshow"
Grid.Row="1" Grid.Row="1"
Margin="5,0,5,5"> Margin="5,0,5,5">
<Border BorderBrush="{StaticResource BorderInterestBrush}" BorderThickness="1,0,1,1"> <Border BorderBrush="{StaticResource BorderInterestBrush}" BorderThickness="1,0,1,1">
<Grid> <Grid>
<local:DetailImageView <local:DetailImageView x:Name="DetailImage" />
Title="{Binding TitleText, Mode=OneWay}" <mahapps:ProgressRing x:Name="ModlistLoadingRing" />
Author="{Binding AuthorText, Mode=OneWay}"
Description="{Binding Description, Mode=OneWay}"
Image="{Binding Image, Mode=OneWay}" />
<mahapps:ProgressRing Visibility="{Binding LoadingModlist, Mode=OneWay, Converter={StaticResource bool2VisibilityHiddenConverter}}" />
</Grid> </Grid>
</Border> </Border>
<Grid <Grid
@ -108,12 +106,12 @@
</Style> </Style>
</Grid.Style> </Grid.Style>
<Button <Button
x:Name="SkipSlideButton"
Grid.Column="3" Grid.Column="3"
Width="60" Width="60"
Height="60" Height="60"
Margin="6" Margin="6"
Background="{StaticResource BackgroundBrush}" Background="{StaticResource BackgroundBrush}"
Command="{Binding Slideshow.SlideShowNextItemCommand}"
Style="{StaticResource CircleButtonStyle}" Style="{StaticResource CircleButtonStyle}"
ToolTip="Skip to the next mod"> ToolTip="Skip to the next mod">
<icon:PackIconFontAwesome <icon:PackIconFontAwesome
@ -126,17 +124,7 @@
Grid.Column="2" Grid.Column="2"
Margin="6" Margin="6"
Background="{StaticResource BackgroundBrush}" Background="{StaticResource BackgroundBrush}"
IsChecked="{Binding Slideshow.Enable}"> Style="{StaticResource SlideshowButton}">
<ToggleButton.Style>
<Style BasedOn="{StaticResource SlideshowButton}" TargetType="ToggleButton">
<Setter Property="ToolTip" Value="Play slideshow" />
<Style.Triggers>
<DataTrigger Binding="{Binding Slideshow.Enable}" Value="True">
<Setter Property="ToolTip" Value="Pause slideshow" />
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
<icon:PackIconMaterial> <icon:PackIconMaterial>
<icon:PackIconMaterial.Style> <icon:PackIconMaterial.Style>
<Style TargetType="icon:PackIconMaterial"> <Style TargetType="icon:PackIconMaterial">
@ -151,32 +139,22 @@
</icon:PackIconMaterial> </icon:PackIconMaterial>
</ToggleButton> </ToggleButton>
<Button <Button
x:Name="OpenWebsite"
Grid.Column="1" Grid.Column="1"
Margin="6" Margin="6"
Background="{StaticResource BackgroundBrush}" Background="{StaticResource BackgroundBrush}"
Command="{Binding Slideshow.VisitNexusSiteCommand}"
Style="{StaticResource SlideshowButton}" Style="{StaticResource SlideshowButton}"
ToolTip="Open Nexus Website"> ToolTip="Open mod's website">
<icon:PackIconMaterial <icon:PackIconMaterial
Width="28" Width="28"
Height="28" Height="28"
Kind="Web" /> Kind="Web" />
</Button> </Button>
<ToggleButton <ToggleButton
x:Name="ShowNSFWButton"
Grid.Column="0" Grid.Column="0"
Background="{StaticResource BackgroundBrush}" Background="{StaticResource BackgroundBrush}"
IsChecked="{Binding Slideshow.ShowNSFW}" Style="{StaticResource SlideshowButton}">
ToolTip="Show NSFW mods">
<ToggleButton.Style>
<Style BasedOn="{StaticResource SlideshowButton}" TargetType="ToggleButton">
<Setter Property="ToolTip" Value="Show NSFW mods" />
<Style.Triggers>
<DataTrigger Binding="{Binding Slideshow.ShowNSFW}" Value="True">
<Setter Property="ToolTip" Value="Hide NSFW mods" />
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
<Grid> <Grid>
<TextBlock <TextBlock
Margin="4" Margin="4"
@ -187,24 +165,22 @@
FontWeight="Bold" FontWeight="Bold"
Text="NSFW" /> Text="NSFW" />
<icon:PackIconOcticons <icon:PackIconOcticons
x:Name="NSFWSlashIcon"
Width="40" Width="40"
Height="40" Height="40"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
Foreground="#88FFFFFF" Foreground="#88FFFFFF"
Kind="CircleSlash" Kind="CircleSlash" />
Visibility="{Binding Slideshow.ShowNSFW, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}" />
</Grid> </Grid>
</ToggleButton> </ToggleButton>
</Grid> </Grid>
</Grid> </Grid>
<!-- Comes after slideshow control, so that any effects/overlap goes on top --> <!-- Comes after slideshow control, so that any effects/overlap goes on top -->
<local:TopProgressView <local:TopProgressView
Title="{Binding ModListName}" x:Name="TopProgressBar"
Grid.Row="0" Grid.Row="0"
Grid.RowSpan="2" Grid.RowSpan="2">
ProgressPercent="{Binding PercentCompleted}"
StatePrefixTitle="{Binding ProgressTitle}">
<!-- Readd when Pause/Stop implementations added --> <!-- Readd when Pause/Stop implementations added -->
<!--<Button Grid.Column="2" <!--<Button Grid.Column="2"
ToolTip="Pause Installation" ToolTip="Pause Installation"
@ -234,17 +210,16 @@
Margin="7,5,0,0" Margin="7,5,0,0"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Top" VerticalAlignment="Top"
Command="{Binding BackCommand}"
Style="{StaticResource IconCircleButtonStyle}" Style="{StaticResource IconCircleButtonStyle}"
ToolTip="Back to main menu"> ToolTip="Back to main menu">
<icon:PackIconMaterial Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" Kind="ArrowLeft" /> <icon:PackIconMaterial Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" Kind="ArrowLeft" />
</Button> </Button>
<!-- Bottom Area --> <!-- Bottom Area -->
<Grid <Grid
x:Name="BottomButtonInputGrid"
Grid.Row="2" Grid.Row="2"
Margin="5,0,5,5" Margin="5,0,5,5"
ClipToBounds="True" ClipToBounds="True">
Visibility="{Binding StartedInstallation, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="4" /> <ColumnDefinition Width="4" />
@ -257,9 +232,9 @@
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Button <Button
x:Name="OpenReadmePreInstallButton"
Grid.Row="0" Grid.Row="0"
Margin="30,5" Margin="30,5"
Command="{Binding OpenReadmeCommand}"
FontSize="20" FontSize="20"
Style="{StaticResource LargeButtonStyle}" Style="{StaticResource LargeButtonStyle}"
ToolTip="Open the readme for the modlist"> ToolTip="Open the readme for the modlist">
@ -282,9 +257,9 @@
</Grid> </Grid>
</Button> </Button>
<Button <Button
x:Name="VisitWebsitePreInstallButton"
Grid.Row="1" Grid.Row="1"
Margin="30,5" Margin="30,5"
Command="{Binding VisitWebsiteCommand}"
FontSize="20" FontSize="20"
Style="{StaticResource LargeButtonStyle}" Style="{StaticResource LargeButtonStyle}"
ToolTip="Open the webpage for the modlist"> ToolTip="Open the webpage for the modlist">
@ -307,9 +282,9 @@
</Grid> </Grid>
</Button> </Button>
<Button <Button
x:Name="ShowManifestPreInstallButton"
Grid.Row="2" Grid.Row="2"
Margin="30,5" Margin="30,5"
Command="{Binding ShowReportCommand}"
FontSize="20" FontSize="20"
Style="{StaticResource LargeButtonStyle}" Style="{StaticResource LargeButtonStyle}"
ToolTip="Open an explicit listing of all actions this modlist will take"> ToolTip="Open an explicit listing of all actions this modlist will take">
@ -345,8 +320,7 @@
Grid.Column="0" Grid.Column="0"
Margin="5" Margin="5"
VerticalAlignment="Center" VerticalAlignment="Center"
Background="Transparent" Background="Transparent">
Visibility="{Binding StartedInstallation, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@ -358,7 +332,7 @@
<ColumnDefinition Width="20" /> <ColumnDefinition Width="20" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Rectangle Grid.Row="0" Height="{Binding Installer.ConfigVisualVerticalOffset, Mode=OneWay}" /> <Rectangle x:Name="InstallConfigSpacer" Grid.Row="0" />
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="1"
Grid.Column="0" Grid.Column="0"
@ -368,18 +342,18 @@
Text="Target Modlist" Text="Target Modlist"
TextAlignment="Center" /> TextAlignment="Center" />
<local:FilePicker <local:FilePicker
x:Name="ModListLocationPicker"
Grid.Row="1" Grid.Row="1"
Grid.Column="2" Grid.Column="2"
Height="30" Height="30"
VerticalAlignment="Center" VerticalAlignment="Center"
FontSize="14" FontSize="14" />
PickerVM="{Binding ModListLocation}" />
<ContentPresenter <ContentPresenter
x:Name="InstallerCustomizationContent"
Grid.Row="3" Grid.Row="3"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
VerticalAlignment="Top" VerticalAlignment="Top">
Content="{Binding Installer}">
<ContentPresenter.Resources> <ContentPresenter.Resources>
<DataTemplate DataType="{x:Type local:MO2InstallerVM}"> <DataTemplate DataType="{x:Type local:MO2InstallerVM}">
<local:MO2InstallerConfigView /> <local:MO2InstallerConfigView />
@ -406,38 +380,44 @@
</ContentPresenter> </ContentPresenter>
</Grid> </Grid>
<local:BeginButton <local:BeginButton
x:Name="BeginButton"
Grid.Column="2" Grid.Column="2"
Margin="0,0,25,0" Margin="0,0,25,0"
HorizontalAlignment="Right" HorizontalAlignment="Right"
VerticalAlignment="Center" VerticalAlignment="Center" />
Command="{Binding BeginCommand, Mode=OneWay}" />
</Grid> </Grid>
</Grid> </Grid>
<Grid <Grid
x:Name="MidInstallDisplayGrid"
Grid.Row="2" Grid.Row="2"
Margin="5,0,5,5" Margin="5,0,5,5">
Visibility="{Binding StartedInstallation, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Hidden}">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" /> <ColumnDefinition Width="4*" />
<ColumnDefinition Width="5" /> <ColumnDefinition Width="5" />
<ColumnDefinition Width="3*" /> <ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<local:LogView Grid.Column="0" ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" /> <local:LogView x:Name="LogView" Grid.Column="0" />
<local:CpuView <local:CpuView
x:Name="CpuView"
Grid.Column="2" Grid.Column="2"
ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" ViewModel="{Binding}" />
SettingsHook="{Binding MWVM.Settings}" <local:AttentionBorder
ViewModel="{Binding}" x:Name="UserInterventionsControl"
Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsNotNullVisibilityConverter}, ConverterParameter=False}" /> Grid.Column="2"
<local:AttentionBorder Grid.Column="2" Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsNotNullVisibilityConverter}}"> Content="{Binding ActiveGlobalUserIntervention}">
<local:AttentionBorder.DisplayContent> <local:AttentionBorder.Resources>
<Grid> <DataTemplate DataType="{x:Type common:ConfirmationIntervention}">
<local:ConfirmationInterventionView DataContext="{Binding ActiveGlobalUserIntervention}" Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsTypeVisibilityConverter}, ConverterParameter={x:Type common:ConfirmationIntervention}}" /> <local:ConfirmationInterventionView ViewModel="{Binding}" />
<local:ConfirmUpdateOfExistingInstallView Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsTypeVisibilityConverter}, ConverterParameter={x:Type lib:ConfirmUpdateOfExistingInstall}}" /> </DataTemplate>
</Grid> <DataTemplate DataType="{x:Type local:ConfirmUpdateOfExistingInstallVM}">
</local:AttentionBorder.DisplayContent> <local:ConfirmUpdateOfExistingInstallView ViewModel="{Binding}" />
</DataTemplate>
</local:AttentionBorder.Resources>
</local:AttentionBorder> </local:AttentionBorder>
<local:InstallationCompleteView Grid.Column="2" Visibility="{Binding Completed, Converter={StaticResource IsNotNullVisibilityConverter}, FallbackValue=Collapsed}" /> <local:InstallationCompleteView
x:Name="InstallComplete"
Grid.Column="2"
ViewModel="{Binding}" />
</Grid> </Grid>
</Grid> </Grid>
</UserControl> </rxui:ReactiveUserControl>

View File

@ -1,15 +1,158 @@
using System.Windows.Controls; using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows.Controls;
using ReactiveUI;
using System.Windows;
namespace Wabbajack namespace Wabbajack
{ {
/// <summary> /// <summary>
/// Interaction logic for InstallationView.xaml /// Interaction logic for InstallationView.xaml
/// </summary> /// </summary>
public partial class InstallationView : UserControl public partial class InstallationView : ReactiveUserControl<InstallerVM>
{ {
public InstallationView() public InstallationView()
{ {
InitializeComponent(); InitializeComponent();
this.WhenActivated(dispose =>
{
this.MarkAsNeeded<InstallationView, InstallerVM, bool>(this.ViewModel, x => x.Installing);
this.MarkAsNeeded<InstallationView, InstallerVM, bool>(this.ViewModel, x => x.Slideshow.Enable);
// General progress indicators
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(x => (double)x)
.BindToStrict(this, x => x.HeatedBackground.PercentCompleted)
.DisposeWith(dispose);
// Top Progress Bar
this.WhenAny(x => x.ViewModel.ModListName)
.BindToStrict(this, x => x.TopProgressBar.Title)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ProgressTitle)
.BindToStrict(this, x => x.TopProgressBar.StatePrefixTitle)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(x => (double)x)
.BindToStrict(this, x => x.TopProgressBar.ProgressPercent)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.BackCommand)
.BindToStrict(this, x => x.BackButton.Command)
.DisposeWith(dispose);
// Detail Image
this.WhenAny(x => x.ViewModel.TitleText)
.BindToStrict(this, x => x.DetailImage.Title)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.AuthorText)
.BindToStrict(this, x => x.DetailImage.Author)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Description)
.BindToStrict(this, x => x.DetailImage.Description)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Image)
.BindToStrict(this, x => x.DetailImage.Image)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.LoadingModlist)
.Select(x => x ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.ModlistLoadingRing.Visibility)
.DisposeWith(dispose);
// Slideshow controls
this.WhenAny(x => x.ViewModel.Slideshow.SlideShowNextItemCommand)
.BindToStrict(this, x => x.SkipSlideButton.Command)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.Slideshow.Enable, x => x.PlayPauseButton.IsChecked,
vmToViewConverter: x => x,
viewToVmConverter: x => x ?? true)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Slideshow.Enable)
.Select(enabled =>
{
return $"{(enabled ? "Pause" : "Play")} slideshow";
})
.BindToStrict(this, x => x.PlayPauseButton.ToolTip)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Slideshow.VisitNexusSiteCommand)
.BindToStrict(this, x => x.OpenWebsite.Command)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.Slideshow.ShowNSFW, x => x.ShowNSFWButton.IsChecked,
vmToViewConverter: x => x,
viewToVmConverter: x => x ?? true)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Slideshow.ShowNSFW)
.Select(show =>
{
return $"{(show ? "Hide" : "Show")} NSFW mods";
})
.BindToStrict(this, x => x.ShowNSFWButton.ToolTip)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Slideshow.ShowNSFW)
.Select(show => show ? Visibility.Collapsed : Visibility.Visible)
.BindToStrict(this, x => x.NSFWSlashIcon.Visibility)
.DisposeWith(dispose);
// Bottom Input Customization
this.WhenAny(x => x.ViewModel.StartedInstallation)
.Select(started => started ? Visibility.Hidden : Visibility.Visible)
.BindToStrict(this, x => x.BottomButtonInputGrid.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.OpenReadmeCommand)
.BindToStrict(this, x => x.OpenReadmePreInstallButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.VisitModListWebsiteCommand)
.BindToStrict(this, x => x.VisitWebsitePreInstallButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ShowManifestCommand)
.BindToStrict(this, x => x.ShowManifestPreInstallButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.StartedInstallation)
.Select(started => 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)
.Select(started => started ? Visibility.Visible : Visibility.Hidden)
.BindToStrict(this, x => x.MidInstallDisplayGrid.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(x => (double)x)
.BindToStrict(this, x => x.LogView.ProgressPercent)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.PercentCompleted)
.Select(f => (double)f)
.BindToStrict(this, x => x.CpuView.ProgressPercent)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.MWVM.Settings)
.BindToStrict(this, x => x.CpuView.SettingsHook)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ActiveGlobalUserIntervention)
.Select(x => x == null ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.CpuView.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ActiveGlobalUserIntervention)
.Select(x => x != null ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.UserInterventionsControl.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Completed)
.Select(completed => completed != null ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.InstallComplete.Visibility)
.DisposeWith(dispose);
});
} }
} }
} }

View File

@ -1,12 +1,15 @@
<UserControl <rxui:ReactiveUserControl
x:Class="Wabbajack.ConfirmUpdateOfExistingInstallView" x:Class="Wabbajack.ConfirmUpdateOfExistingInstallView"
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:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
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"
xmlns:rxui="http://reactiveui.net"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
x:TypeArguments="local:ConfirmUpdateOfExistingInstallVM"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid Margin="10"> <Grid Margin="10">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@ -21,6 +24,7 @@
<RowDefinition Height="2*" /> <RowDefinition Height="2*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock <TextBlock
x:Name="ShortDescription"
Grid.Row="0" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
@ -28,15 +32,15 @@
FontFamily="Lucida Sans" FontFamily="Lucida Sans"
FontSize="14" FontSize="14"
FontWeight="Bold" FontWeight="Bold"
Text="{Binding ActiveGlobalUserIntervention.ShortDescription}"
TextWrapping="WrapWithOverflow" /> TextWrapping="WrapWithOverflow" />
<TextBlock <TextBlock
x:Name="ExtendedDescription"
Grid.Row="1" Grid.Row="1"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
Text="{Binding ActiveGlobalUserIntervention.ExtendedDescription}"
TextWrapping="WrapWithOverflow" /> TextWrapping="WrapWithOverflow" />
<CheckBox <CheckBox
x:Name="AutoOverwriteCheckbox"
Grid.Row="2" Grid.Row="2"
Grid.Column="2" Grid.Column="2"
Margin="4" Margin="4"
@ -45,14 +49,14 @@
IsChecked="{Binding Installer.AutomaticallyOverwrite}" IsChecked="{Binding Installer.AutomaticallyOverwrite}"
ToolTip="If installing over an existing installation next time, automatically replace it without asking permission." /> ToolTip="If installing over an existing installation next time, automatically replace it without asking permission." />
<Button <Button
x:Name="CancelButton"
Grid.Row="3" Grid.Row="3"
Grid.Column="0" Grid.Column="0"
Command="{Binding ActiveGlobalUserIntervention.CancelCommand}"
Content="Cancel" /> Content="Cancel" />
<Button <Button
x:Name="ConfirmButton"
Grid.Row="3" Grid.Row="3"
Grid.Column="2" Grid.Column="2"
Command="{Binding ActiveGlobalUserIntervention.ConfirmCommand}"
Content="Confirm" /> Content="Confirm" />
</Grid> </Grid>
</UserControl> </rxui:ReactiveUserControl>

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Disposables;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
@ -12,17 +13,39 @@ using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Shapes; using System.Windows.Shapes;
using ReactiveUI;
using Wabbajack.Lib;
namespace Wabbajack namespace Wabbajack
{ {
/// <summary> /// <summary>
/// Interaction logic for ConfirmUpdateOfExistingInstallView.xaml /// Interaction logic for ConfirmUpdateOfExistingInstallView.xaml
/// </summary> /// </summary>
public partial class ConfirmUpdateOfExistingInstallView : UserControl public partial class ConfirmUpdateOfExistingInstallView : ReactiveUserControl<ConfirmUpdateOfExistingInstallVM>
{ {
public ConfirmUpdateOfExistingInstallView() public ConfirmUpdateOfExistingInstallView()
{ {
InitializeComponent(); InitializeComponent();
this.WhenActivated(dispose =>
{
this.WhenAny(x => x.ViewModel.ShortDescription)
.BindToStrict(this, x => x.ShortDescription.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ExtendedDescription)
.BindToStrict(this, x => x.ExtendedDescription.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Source.ConfirmCommand)
.BindToStrict(this, x => x.ConfirmButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Source.CancelCommand)
.BindToStrict(this, x => x.CancelButton.Command)
.DisposeWith(dispose);
this.BindStrict(this.ViewModel, x => x.Installer.AutomaticallyOverwrite, x => x.AutoOverwriteCheckbox.IsChecked,
vmToViewConverter: x => x,
viewToVmConverter: x => x ?? false)
.DisposeWith(dispose);
});
} }
} }
} }

View File

@ -1,12 +1,15 @@
<UserControl <rxui:ReactiveUserControl
x:Class="Wabbajack.ConfirmationInterventionView" x:Class="Wabbajack.ConfirmationInterventionView"
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: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"
xmlns:rxui="http://reactiveui.net"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
x:TypeArguments="common:ConfirmationIntervention"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid Margin="10"> <Grid Margin="10">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@ -20,6 +23,7 @@
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock <TextBlock
x:Name="ShortDescription"
Grid.Row="0" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
@ -27,23 +31,22 @@
FontFamily="Lucida Sans" FontFamily="Lucida Sans"
FontSize="14" FontSize="14"
FontWeight="Bold" FontWeight="Bold"
Text="{Binding ShortDescription}"
TextWrapping="WrapWithOverflow" /> TextWrapping="WrapWithOverflow" />
<TextBlock <TextBlock
x:Name="ExtendedDescription"
Grid.Row="1" Grid.Row="1"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
Text="{Binding ExtendedDescription}"
TextWrapping="WrapWithOverflow" /> TextWrapping="WrapWithOverflow" />
<Button <Button
x:Name="CancelButton"
Grid.Row="2" Grid.Row="2"
Grid.Column="0" Grid.Column="0"
Command="{Binding CancelCommand}"
Content="Cancel" /> Content="Cancel" />
<Button <Button
x:Name="ConfirmButton"
Grid.Row="2" Grid.Row="2"
Grid.Column="2" Grid.Column="2"
Command="{Binding ConfirmCommand}"
Content="Confirm" /> Content="Confirm" />
</Grid> </Grid>
</UserControl> </rxui:ReactiveUserControl>

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Disposables;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
@ -12,17 +13,34 @@ using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Shapes; using System.Windows.Shapes;
using ReactiveUI;
using Wabbajack.Common;
namespace Wabbajack namespace Wabbajack
{ {
/// <summary> /// <summary>
/// Interaction logic for ConfirmationInterventionView.xaml /// Interaction logic for ConfirmationInterventionView.xaml
/// </summary> /// </summary>
public partial class ConfirmationInterventionView : UserControl public partial class ConfirmationInterventionView : ReactiveUserControl<ConfirmationIntervention>
{ {
public ConfirmationInterventionView() public ConfirmationInterventionView()
{ {
InitializeComponent(); InitializeComponent();
this.WhenActivated(dispose =>
{
this.WhenAny(x => x.ViewModel.ShortDescription)
.BindToStrict(this, x => x.ShortDescription.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ExtendedDescription)
.BindToStrict(this, x => x.ExtendedDescription.Text)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ConfirmCommand)
.BindToStrict(this, x => x.ConfirmButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.CancelCommand)
.BindToStrict(this, x => x.CancelButton.Command)
.DisposeWith(dispose);
});
} }
} }
} }

View File

@ -23,16 +23,16 @@
<ContentPresenter Content="{Binding ActivePane}"> <ContentPresenter Content="{Binding ActivePane}">
<ContentPresenter.Resources> <ContentPresenter.Resources>
<DataTemplate DataType="{x:Type local:CompilerVM}"> <DataTemplate DataType="{x:Type local:CompilerVM}">
<local:CompilerView /> <local:CompilerView ViewModel="{Binding}" />
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type local:InstallerVM}"> <DataTemplate DataType="{x:Type local:InstallerVM}">
<local:InstallationView /> <local:InstallationView ViewModel="{Binding}" />
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type local:ModeSelectionVM}"> <DataTemplate DataType="{x:Type local:ModeSelectionVM}">
<local:ModeSelectionView /> <local:ModeSelectionView />
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type local:ModListGalleryVM}"> <DataTemplate DataType="{x:Type local:ModListGalleryVM}">
<local:ModListGalleryView /> <local:ModListGalleryView ViewModel="{Binding}" />
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type local:WebBrowserVM}"> <DataTemplate DataType="{x:Type local:WebBrowserVM}">
<local:WebBrowserView /> <local:WebBrowserView />

View File

@ -1,14 +1,17 @@
<UserControl <rxui:ReactiveUserControl
x:Class="Wabbajack.ModListGalleryView" x:Class="Wabbajack.ModListGalleryView"
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:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:local="clr-namespace:Wabbajack" xmlns:local="clr-namespace:Wabbajack"
xmlns:mahapps="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:rxui="http://reactiveui.net"
xmlns:system="clr-namespace:System;assembly=mscorlib" xmlns:system="clr-namespace:System;assembly=mscorlib"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
x:TypeArguments="local:ModListGalleryVM"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
@ -32,9 +35,9 @@
BorderThickness="1,0,1,1"> BorderThickness="1,0,1,1">
<ScrollViewer Background="Transparent" VerticalScrollBarVisibility="Auto"> <ScrollViewer Background="Transparent" VerticalScrollBarVisibility="Auto">
<ItemsControl <ItemsControl
x:Name="ModListGalleryControl"
Margin="0,10,0,0" Margin="0,10,0,0"
HorizontalAlignment="Center" HorizontalAlignment="Center">
ItemsSource="{Binding ModLists}">
<ItemsControl.ItemsPanel> <ItemsControl.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<WrapPanel /> <WrapPanel />
@ -48,6 +51,17 @@
</ItemsControl> </ItemsControl>
</ScrollViewer> </ScrollViewer>
</Border> </Border>
<mahapps:ProgressRing x:Name="LoadingRing" Grid.Row="1" />
<iconPacks:PackIconControl
x:Name="ErrorIcon"
Grid.Row="1"
Width="55"
Height="55"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{StaticResource ErrorBrush}"
Kind="{x:Static iconPacks:PackIconMaterialKind.AlertCircle}"
ToolTip="Error loading modlist gallery" />
<local:TopProgressView <local:TopProgressView
Title="Browsing Modlists" Title="Browsing Modlists"
Grid.Row="0" Grid.Row="0"
@ -61,10 +75,9 @@
Margin="7,5,0,0" Margin="7,5,0,0"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Top" VerticalAlignment="Top"
Command="{Binding BackCommand}"
Style="{StaticResource IconCircleButtonStyle}" Style="{StaticResource IconCircleButtonStyle}"
ToolTip="Back to main menu"> ToolTip="Back to main menu">
<iconPacks:PackIconMaterial Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" Kind="ArrowLeft" /> <iconPacks:PackIconMaterial Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" Kind="ArrowLeft" />
</Button> </Button>
</Grid> </Grid>
</UserControl> </rxui:ReactiveUserControl>

View File

@ -1,16 +1,45 @@
using System.Diagnostics; using System.Diagnostics;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using MahApps.Metro.Controls; using MahApps.Metro.Controls;
using ReactiveUI;
using Wabbajack.Lib.ModListRegistry; using Wabbajack.Lib.ModListRegistry;
namespace Wabbajack namespace Wabbajack
{ {
public partial class ModListGalleryView : UserControl public partial class ModListGalleryView : ReactiveUserControl<ModListGalleryVM>
{ {
public ModListGalleryView() public ModListGalleryView()
{ {
InitializeComponent(); InitializeComponent();
this.WhenActivated(dispose =>
{
this.WhenAny(x => x.ViewModel.BackCommand)
.BindToStrict(this, x => x.BackButton.Command)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ModLists)
.BindToStrict(this, x => x.ModListGalleryControl.ItemsSource)
.DisposeWith(dispose);
Observable.CombineLatest(
this.WhenAny(x => x.ViewModel.ModLists.Count)
.Select(x => x > 0),
this.WhenAny(x => x.ViewModel.Error)
.Select(e => e?.Succeeded ?? true),
resultSelector: (hasContent, succeeded) =>
{
return !hasContent && succeeded;
})
.Select(x => x ? Visibility.Visible : Visibility.Collapsed)
.BindToStrict(this, x => x.LoadingRing.Visibility)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.Error)
.Select(e => (e?.Succeeded ?? true) ? Visibility.Collapsed : Visibility.Visible)
.BindToStrict(this, x => x.ErrorIcon.Visibility)
.DisposeWith(dispose);
});
} }
} }
} }

View File

@ -174,6 +174,8 @@
</ApplicationDefinition> </ApplicationDefinition>
<Compile Include="Extensions\DynamicDataExt.cs" /> <Compile Include="Extensions\DynamicDataExt.cs" />
<Compile Include="View Models\Settings\AuthorFilesVM.cs" /> <Compile Include="View Models\Settings\AuthorFilesVM.cs" />
<Compile Include="View Models\UserIntervention\ConfirmUpdateOfExistingInstallVM.cs" />
<Compile Include="Views\Common\AttentionBorder.cs" />
<Compile Include="Views\ModListTileView.xaml.cs"> <Compile Include="Views\ModListTileView.xaml.cs">
<DependentUpon>ModListTileView.xaml</DependentUpon> <DependentUpon>ModListTileView.xaml</DependentUpon>
</Compile> </Compile>
@ -202,9 +204,6 @@
<Compile Include="Views\Settings\SettingsView.xaml.cs"> <Compile Include="Views\Settings\SettingsView.xaml.cs">
<DependentUpon>SettingsView.xaml</DependentUpon> <DependentUpon>SettingsView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\Common\AttentionBorder.xaml.cs">
<DependentUpon>AttentionBorder.xaml</DependentUpon>
</Compile>
<Compile Include="Converters\IsTypeVisibilityConverter.cs" /> <Compile Include="Converters\IsTypeVisibilityConverter.cs" />
<Compile Include="Views\Common\UnderMaintenanceOverlay.xaml.cs"> <Compile Include="Views\Common\UnderMaintenanceOverlay.xaml.cs">
<DependentUpon>UnderMaintenanceOverlay.xaml</DependentUpon> <DependentUpon>UnderMaintenanceOverlay.xaml</DependentUpon>
@ -308,6 +307,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="Themes\CustomControls.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ModListTileView.xaml"> <Page Include="Views\ModListTileView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -329,10 +332,6 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Views\Common\AttentionBorder.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Common\UnderMaintenanceOverlay.xaml"> <Page Include="Views\Common\UnderMaintenanceOverlay.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -535,7 +534,7 @@
<Version>3.7.0</Version> <Version>3.7.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Fody"> <PackageReference Include="Fody">
<Version>6.0.6</Version> <Version>6.0.7</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
@ -569,13 +568,13 @@
<Version>3.0.0-alpha.128</Version> <Version>3.0.0-alpha.128</Version>
</PackageReference> </PackageReference>
<PackageReference Include="ReactiveUI.Events.WPF"> <PackageReference Include="ReactiveUI.Events.WPF">
<Version>11.1.11</Version> <Version>11.1.12</Version>
</PackageReference> </PackageReference>
<PackageReference Include="ReactiveUI.Fody"> <PackageReference Include="ReactiveUI.Fody">
<Version>11.1.11</Version> <Version>11.1.12</Version>
</PackageReference> </PackageReference>
<PackageReference Include="ReactiveUI.WPF"> <PackageReference Include="ReactiveUI.WPF">
<Version>11.1.11</Version> <Version>11.1.12</Version>
</PackageReference> </PackageReference>
<PackageReference Include="SharpCompress"> <PackageReference Include="SharpCompress">
<Version>0.24.0</Version> <Version>0.24.0</Version>
@ -596,7 +595,7 @@
<Version>1.0.8</Version> <Version>1.0.8</Version>
</PackageReference> </PackageReference>
<PackageReference Include="YamlDotNet"> <PackageReference Include="YamlDotNet">
<Version>8.0.0</Version> <Version>8.1.0</Version>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>