Settings page work. Some experimentation /w RxUI binding

This commit is contained in:
Justin Swanson 2020-01-05 22:49:11 -06:00
parent f44f75d497
commit feb3e781fc
23 changed files with 605 additions and 80 deletions

View File

@ -14,7 +14,7 @@ namespace Wabbajack.Lib.Downloaders
ICommand ClearLogin { get; } ICommand ClearLogin { get; }
IObservable<bool> IsLoggedIn { get; } IObservable<bool> IsLoggedIn { get; }
string SiteName { get; } string SiteName { get; }
string MetaInfo { get; } IObservable<string> MetaInfo { get; }
Uri SiteURL { get; } Uri SiteURL { get; }
Uri IconUri { get; } Uri IconUri { get; }
} }

View File

@ -31,7 +31,7 @@ namespace Wabbajack.Lib.Downloaders
public ICommand ClearLogin { get; } public ICommand ClearLogin { get; }
public IObservable<bool> IsLoggedIn => Utils.HaveEncryptedJsonObservable("loverslabcookies"); public IObservable<bool> IsLoggedIn => Utils.HaveEncryptedJsonObservable("loverslabcookies");
public string SiteName => "Lovers Lab"; public string SiteName => "Lovers Lab";
public string MetaInfo => ""; public IObservable<string> MetaInfo => Observable.Return("");
public Uri SiteURL => new Uri("https://loverslab.com"); public Uri SiteURL => new Uri("https://loverslab.com");
public Uri IconUri => new Uri("https://www.loverslab.com/favicon.ico"); public Uri IconUri => new Uri("https://www.loverslab.com/favicon.ico");

View File

@ -24,7 +24,7 @@ namespace Wabbajack.Lib.Downloaders
public string SiteName => "Nexus Mods"; public string SiteName => "Nexus Mods";
public string MetaInfo => ""; public IObservable<string> MetaInfo => Observable.Return("");
public Uri SiteURL => new Uri("https://www.nexusmods.com"); public Uri SiteURL => new Uri("https://www.nexusmods.com");

View File

@ -1,4 +1,5 @@
using ReactiveUI; using Newtonsoft.Json;
using ReactiveUI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reactive.Disposables; using System.Reactive.Disposables;
@ -9,6 +10,7 @@ namespace Wabbajack.Lib
public class ViewModel : ReactiveObject, IDisposable public class ViewModel : ReactiveObject, IDisposable
{ {
private readonly Lazy<CompositeDisposable> _compositeDisposable = new Lazy<CompositeDisposable>(); private readonly Lazy<CompositeDisposable> _compositeDisposable = new Lazy<CompositeDisposable>();
[JsonIgnore]
public CompositeDisposable CompositeDisposable => _compositeDisposable.Value; public CompositeDisposable CompositeDisposable => _compositeDisposable.Value;
public virtual void Dispose() public virtual void Dispose()

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using ReactiveUI;
namespace Wabbajack
{
public class CommandConverter : IBindingTypeConverter
{
public int GetAffinityForObjects(Type fromType, Type toType)
{
if (toType != typeof(ICommand)) return 0;
if (fromType == typeof(ICommand)
|| fromType == typeof(IReactiveCommand))
{
return 1;
}
return 0;
}
public bool TryConvert(object from, Type toType, object conversionHint, out object result)
{
if (from == null)
{
result = default(ICommand);
return true;
}
result = from as ICommand;
return result != null;
}
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ReactiveUI;
using Splat;
namespace Wabbajack
{
public static class ConverterRegistration
{
public static void Register()
{
Locator.CurrentMutable.RegisterConstant(
new CommandConverter(),
typeof(IBindingTypeConverter)
);
Locator.CurrentMutable.RegisterConstant(
new IntDownCastConverter(),
typeof(IBindingTypeConverter)
);
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using ReactiveUI;
namespace Wabbajack
{
public class IntDownCastConverter : IBindingTypeConverter
{
public int GetAffinityForObjects(Type fromType, Type toType)
{
if (toType == typeof(int) || fromType == typeof(int?)) return 1;
if (fromType == typeof(ICommand)
|| fromType == typeof(IReactiveCommand))
{
return 1;
}
return 0;
}
public bool TryConvert(object from, Type toType, object conversionHint, out object result)
{
if (from == null)
{
result = default(ICommand);
return true;
}
result = from as ICommand;
return result != null;
}
}
}

View File

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using ReactiveUI;
namespace Wabbajack
{
public static class IViewForExt
{
public static IReactiveBinding<TView, TViewModel, TProp> OneWayBindStrict<TViewModel, TView, TProp>(
this TView view,
TViewModel viewModel,
Expression<Func<TViewModel, TProp>> vmProperty,
Expression<Func<TView, TProp>> viewProperty)
where TViewModel : class
where TView : class, IViewFor
{
return view.OneWayBind(
viewModel: viewModel,
vmProperty: vmProperty,
viewProperty: viewProperty);
}
public static IReactiveBinding<TView, TViewModel, TOut> OneWayBindStrict<TViewModel, TView, TProp, TOut>(
this TView view,
TViewModel viewModel,
Expression<Func<TViewModel, TProp>> vmProperty,
Expression<Func<TView, TOut>> viewProperty,
Func<TProp, TOut> selector)
where TViewModel : class
where TView : class, IViewFor
{
return view.OneWayBind(
viewModel: viewModel,
vmProperty: vmProperty,
viewProperty: viewProperty,
selector: selector);
}
public static IReactiveBinding<TView, TViewModel, (object view, bool isViewModel)> BindStrict<TViewModel, TView, TProp>(
this TView view,
TViewModel viewModel,
Expression<Func<TViewModel, TProp>> vmProperty,
Expression<Func<TView, TProp>> viewProperty)
where TViewModel : class
where TView : class, IViewFor
{
return view.Bind(
viewModel: viewModel,
vmProperty: vmProperty,
viewProperty: viewProperty);
}
public static IReactiveBinding<TView, TViewModel, (object view, bool isViewModel)> BindStrict<TViewModel, TView, TVMProp, TVProp>(
this TView view,
TViewModel viewModel,
Expression<Func<TViewModel, TVMProp>> vmProperty,
Expression<Func<TView, TVProp>> viewProperty,
Func<TVMProp, TVProp> vmToViewConverter,
Func<TVProp, TVMProp> viewToVmConverter)
where TViewModel : class
where TView : class, IViewFor
{
return view.Bind(
viewModel: viewModel,
vmProperty: vmProperty,
viewProperty: viewProperty,
vmToViewConverter: vmToViewConverter,
viewToVmConverter: viewToVmConverter);
}
}
}

View File

@ -1,4 +1,5 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using ReactiveUI.Fody.Helpers;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -10,7 +11,7 @@ using Wabbajack.Lib;
namespace Wabbajack namespace Wabbajack
{ {
[JsonObject(MemberSerialization.OptOut)] [JsonObject(MemberSerialization.OptOut)]
public class MainSettings : ViewModel public class MainSettings
{ {
private static string _filename = "settings.json"; private static string _filename = "settings.json";
@ -20,6 +21,7 @@ namespace Wabbajack
public double Width { get; set; } public double Width { get; set; }
public InstallerSettings Installer { get; set; } = new InstallerSettings(); public InstallerSettings Installer { get; set; } = new InstallerSettings();
public CompilerSettings Compiler { get; set; } = new CompilerSettings(); public CompilerSettings Compiler { get; set; } = new CompilerSettings();
public PerformanceSettings Performance { get; set; } = new PerformanceSettings();
private Subject<Unit> _saveSignal = new Subject<Unit>(); private Subject<Unit> _saveSignal = new Subject<Unit>();
[JsonIgnore] [JsonIgnore]
@ -70,6 +72,19 @@ namespace Wabbajack
public VortexCompilationSettings VortexCompilation { get; } = new VortexCompilationSettings(); public VortexCompilationSettings VortexCompilation { get; } = new VortexCompilationSettings();
} }
[JsonObject(MemberSerialization.OptOut)]
public class PerformanceSettings : ViewModel
{
private bool _Manual = false;
public bool Manual { get => _Manual; set => this.RaiseAndSetIfChanged(ref _Manual, value); }
private byte _MaxCores = byte.MaxValue;
public byte MaxCores { get => _MaxCores; set => this.RaiseAndSetIfChanged(ref _MaxCores, value); }
private double _TargetUsage = 1.0d;
public double TargetUsage { get => _TargetUsage; set => this.RaiseAndSetIfChanged(ref _TargetUsage, value); }
}
public class CompilationModlistSettings public class CompilationModlistSettings
{ {
public string ModListName { get; set; } public string ModListName { get; set; }

View File

@ -53,6 +53,7 @@
<Color x:Key="IntenseSecondary">#00ffe7</Color> <Color x:Key="IntenseSecondary">#00ffe7</Color>
<Color x:Key="Complementary">#C7FC86</Color> <Color x:Key="Complementary">#C7FC86</Color>
<Color x:Key="DarkComplementary">#8eb55e</Color> <Color x:Key="DarkComplementary">#8eb55e</Color>
<Color x:Key="ComplementaryBackground">#4b6130</Color>
<Color x:Key="IntenseComplementary">#abf74d</Color> <Color x:Key="IntenseComplementary">#abf74d</Color>
<Color x:Key="Analogous1">#868CFC</Color> <Color x:Key="Analogous1">#868CFC</Color>
<Color x:Key="Analogous2">#F686FC</Color> <Color x:Key="Analogous2">#F686FC</Color>
@ -130,6 +131,7 @@
<SolidColorBrush x:Key="ComplementaryBrush" Color="{StaticResource Complementary}" /> <SolidColorBrush x:Key="ComplementaryBrush" Color="{StaticResource Complementary}" />
<SolidColorBrush x:Key="DarkComplementaryBrush" Color="{StaticResource DarkComplementary}" /> <SolidColorBrush x:Key="DarkComplementaryBrush" Color="{StaticResource DarkComplementary}" />
<SolidColorBrush x:Key="IntenseComplementaryBrush" Color="{StaticResource IntenseComplementary}" /> <SolidColorBrush x:Key="IntenseComplementaryBrush" Color="{StaticResource IntenseComplementary}" />
<SolidColorBrush x:Key="ComplementaryBackgroundBrush" Color="{StaticResource ComplementaryBackground}" />
<SolidColorBrush x:Key="Analogous1Brush" Color="{StaticResource Analogous1}" /> <SolidColorBrush x:Key="Analogous1Brush" Color="{StaticResource Analogous1}" />
<SolidColorBrush x:Key="Analogous2Brush" Color="{StaticResource Analogous2}" /> <SolidColorBrush x:Key="Analogous2Brush" Color="{StaticResource Analogous2}" />
<SolidColorBrush x:Key="Triadic1Brush" Color="{StaticResource Triadic1}" /> <SolidColorBrush x:Key="Triadic1Brush" Color="{StaticResource Triadic1}" />
@ -250,9 +252,14 @@
<Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" /> <Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
</Style> </Style>
<Style TargetType="{x:Type ItemsControl}">
<Setter Property="Focusable" Value="False" />
</Style>
<!-- ScrollBar --> <!-- ScrollBar -->
<Style TargetType="{x:Type ScrollViewer}"> <Style TargetType="{x:Type ScrollViewer}">
<Setter Property="Background" Value="{DynamicResource ScrollViewerBackground}" /> <Setter Property="Background" Value="{DynamicResource ScrollViewerBackground}" />
<Setter Property="Focusable" Value="False" />
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}"> <ControlTemplate TargetType="{x:Type ScrollViewer}">
@ -279,7 +286,8 @@
CanHorizontallyScroll="False" CanHorizontallyScroll="False"
CanVerticallyScroll="False" CanVerticallyScroll="False"
Content="{TemplateBinding Content}" Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" /> ContentTemplate="{TemplateBinding ContentTemplate}"
Focusable="False" />
<ScrollBar <ScrollBar
x:Name="PART_VerticalScrollBar" x:Name="PART_VerticalScrollBar"
Grid.Row="0" Grid.Row="0"
@ -1157,8 +1165,54 @@
</Setter> </Setter>
</Style> </Style>
<Style x:Key="MainButtonStyle" TargetType="{x:Type Button}"> <Style x:Key="MainButtonStyle" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}" />
<Setter Property="Background" Value="{StaticResource DarkBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource ButtonBorder}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Focusable" Value="False" />
<Setter Property="Foreground" Value="{StaticResource ButtonForeground}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Padding" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="3">
<ContentPresenter
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{StaticResource DarkHoverBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource DarkComplementaryBrush}" />
<Setter Property="Foreground" Value="{StaticResource ComplementaryBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" Value="{StaticResource PressedButtonBackground}" />
<Setter Property="BorderBrush" Value="{StaticResource ComplementaryBrush}" />
<Setter Property="Foreground" Value="{StaticResource IntenseComplementaryBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource DisabledButtonForeground}" />
<Setter Property="Background" Value="{StaticResource DisabledButtonBackground}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="LargeButtonStyle" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}" /> <Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}" />
<Setter Property="Background" Value="{StaticResource DarkBackgroundBrush}" /> <Setter Property="Background" Value="{StaticResource DarkBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource ButtonBorder}" /> <Setter Property="BorderBrush" Value="{StaticResource ButtonBorder}" />

View File

@ -48,6 +48,7 @@ namespace Wabbajack
public MainWindowVM(MainWindow mainWindow, MainSettings settings) public MainWindowVM(MainWindow mainWindow, MainSettings settings)
{ {
ConverterRegistration.Register();
MainWindow = mainWindow; MainWindow = mainWindow;
Settings = settings; Settings = settings;
Installer = new Lazy<InstallerVM>(() => new InstallerVM(this)); Installer = new Lazy<InstallerVM>(() => new InstallerVM(this));

View File

@ -4,18 +4,38 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;
using ReactiveUI;
using Wabbajack.Lib;
using Wabbajack.Lib.Downloaders; using Wabbajack.Lib.Downloaders;
namespace Wabbajack namespace Wabbajack
{ {
public class LoginManagerVM : BackNavigatingVM public class LoginManagerVM : BackNavigatingVM
{ {
public List<INeedsLogin> Downloaders { get; } public List<LoginTargetVM> Downloaders { get; }
public LoginManagerVM(SettingsVM settingsVM) public LoginManagerVM(SettingsVM settingsVM)
: base(settingsVM.MWVM) : base(settingsVM.MWVM)
{ {
Downloaders = DownloadDispatcher.Downloaders.OfType<INeedsLogin>().ToList(); Downloaders = DownloadDispatcher.Downloaders
.OfType<INeedsLogin>()
.Select(x => new LoginTargetVM(x))
.ToList();
}
public class LoginTargetVM : ViewModel
{
private readonly ObservableAsPropertyHelper<string> _MetaInfo;
public string MetaInfo => _MetaInfo.Value;
public INeedsLogin Login { get; }
public LoginTargetVM(INeedsLogin login)
{
Login = login;
_MetaInfo = login.MetaInfo
.ToProperty(this, nameof(MetaInfo));
}
} }
} }
} }

View File

@ -11,13 +11,15 @@ namespace Wabbajack
public class SettingsVM : BackNavigatingVM public class SettingsVM : BackNavigatingVM
{ {
public MainWindowVM MWVM { get; } public MainWindowVM MWVM { get; }
public LoginManagerVM LoginManagerVM { get; } public LoginManagerVM Login { get; }
public PerformanceSettings Performance { get; }
public SettingsVM(MainWindowVM mainWindowVM) public SettingsVM(MainWindowVM mainWindowVM)
: base(mainWindowVM) : base(mainWindowVM)
{ {
MWVM = mainWindowVM; MWVM = mainWindowVM;
LoginManagerVM = new LoginManagerVM(this); Login = new LoginManagerVM(this);
Performance = mainWindowVM.Settings.Performance;
} }
} }
} }

View File

@ -257,6 +257,7 @@
Margin="30,5" Margin="30,5"
Command="{Binding OpenReadmeCommand}" Command="{Binding OpenReadmeCommand}"
FontSize="20" FontSize="20"
Style="{StaticResource LargeButtonStyle}"
ToolTip="Open the readme for the modlist"> ToolTip="Open the readme for the modlist">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@ -281,6 +282,7 @@
Margin="30,5" Margin="30,5"
Command="{Binding VisitWebsiteCommand}" Command="{Binding VisitWebsiteCommand}"
FontSize="20" FontSize="20"
Style="{StaticResource LargeButtonStyle}"
ToolTip="Open the webpage for the modlist"> ToolTip="Open the webpage for the modlist">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@ -305,6 +307,7 @@
Margin="30,5" Margin="30,5"
Command="{Binding ShowReportCommand}" Command="{Binding ShowReportCommand}"
FontSize="20" FontSize="20"
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">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>

View File

@ -28,9 +28,6 @@
<DataTemplate DataType="{x:Type local:InstallerVM}"> <DataTemplate DataType="{x:Type local:InstallerVM}">
<local:InstallationView /> <local:InstallationView />
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type local:LoginManagerVM}">
<local:LoginManagerView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ModeSelectionVM}"> <DataTemplate DataType="{x:Type local:ModeSelectionVM}">
<local:ModeSelectionView /> <local:ModeSelectionView />
</DataTemplate> </DataTemplate>
@ -41,7 +38,7 @@
<local:WebBrowserView /> <local:WebBrowserView />
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type local:SettingsVM}"> <DataTemplate DataType="{x:Type local:SettingsVM}">
<local:SettingsView /> <local:SettingsView ViewModel="{Binding}" />
</DataTemplate> </DataTemplate>
</ContentPresenter.Resources> </ContentPresenter.Resources>
</ContentPresenter> </ContentPresenter>

View File

@ -1,50 +0,0 @@
<UserControl
x:Class="Wabbajack.LoginManagerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wabbajack"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<!-- Do it this way so we can access the browser directly from the VM -->
<ListView Background="{StaticResource WindowBackgroundBrush}" ItemsSource="{Binding Downloaders}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Height="30" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding IconUrl, Mode=OneTime}" />
<Label
Grid.Column="1"
Width="400"
Content="{Binding SiteName, Mode=OneTime}"
FontSize="14" />
<Label
Grid.Column="2"
Width="400"
Content="{Binding MetaInfo, Mode=OneWay}"
FontSize="14" />
<Button
Grid.Column="3"
Margin="5"
Command="{Binding TriggerLogin}"
Content="Login" />
<Button
Grid.Column="4"
Margin="5"
Command="{Binding ClearLogin}"
Content="Logout" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</UserControl>

View File

@ -0,0 +1,69 @@
<rxui:ReactiveUserControl
x:Class="Wabbajack.LoginSettingsView"
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"
xmlns:rxui="http://reactiveui.net"
d:DesignHeight="450"
d:DesignWidth="800"
x:TypeArguments="local:LoginManagerVM"
mc:Ignorable="d">
<Border
x:Name="LoginView"
Margin="5"
Background="{StaticResource BackgroundBrush}"
BorderBrush="{StaticResource ButtonNormalBorder}"
BorderThickness="1">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock
Margin="5,0"
FontFamily="Lucida Sans"
FontSize="20"
FontWeight="Bold"
Text="Logins" />
<ItemsControl
x:Name="DownloadersList"
Grid.Row="1"
Margin="5"
Background="{StaticResource BackgroundBrush}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Height="30" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="150" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!--<Image Grid.Column="0" Source="{Binding Login.IconUrl, Mode=OneTime}" />-->
<TextBlock
Grid.Column="0"
VerticalAlignment="Center"
Text="{Binding Login.SiteName, Mode=OneWay}" />
<Button
Grid.Column="1"
Margin="5"
Command="{Binding Login.TriggerLogin}"
Content="Login" />
<Button
Grid.Column="2"
Margin="5"
Command="{Binding Login.ClearLogin}"
Content="Logout" />
<Label
Grid.Column="3"
Content="{Binding MetaInfo, Mode=OneWay}"
FontSize="14" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Border>
</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,23 @@ 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 LoginManager.xaml /// Interaction logic for LoginSettingsView.xaml
/// </summary> /// </summary>
public partial class LoginManagerView : UserControl public partial class LoginSettingsView : ReactiveUserControl<LoginManagerVM>
{ {
public LoginManagerView() public LoginSettingsView()
{ {
InitializeComponent(); InitializeComponent();
this.WhenActivated(disposable =>
{
this.OneWayBind(this.ViewModel, x => x.Downloaders, x => x.DownloadersList.ItemsSource)
.DisposeWith(disposable);
});
} }
} }
} }

View File

@ -0,0 +1,121 @@
<rxui:ReactiveUserControl
x:Class="Wabbajack.PerformanceSettingsView"
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"
xmlns:rxui="http://reactiveui.net"
xmlns:xwpf="http://schemas.xceed.com/wpf/xaml/toolkit"
d:DesignHeight="450"
d:DesignWidth="800"
x:TypeArguments="local:PerformanceSettings"
mc:Ignorable="d">
<Border
x:Name="PerformanceView"
MinWidth="280"
Margin="5"
Background="{StaticResource BackgroundBrush}"
BorderBrush="{StaticResource ButtonNormalBorder}"
BorderThickness="1">
<Grid Margin="15,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="10" />
<RowDefinition Height="Auto" />
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Grid.ColumnSpan="2"
FontFamily="Lucida Sans"
FontSize="20"
FontWeight="Bold"
Text="Performance" />
<Grid
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="3"
Height="25"
Margin="0,0,0,10">
<Grid.Resources>
<Style BasedOn="{StaticResource MainButtonStyle}" TargetType="Button">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
<Setter Property="Background" Value="{StaticResource SecondaryBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource DarkSecondaryBrush}" />
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
x:Name="ManualButton"
Grid.Column="0"
Content="Manual"
ToolTip="Control the number of cores by setting the max limit manually" />
<Button
x:Name="AutoButton"
Grid.Column="2"
Content="Auto"
ToolTip="Control the number of cores by scaling it to a percentage of what WJ would use at full speed" />
</Grid>
<TextBlock
x:Name="MaxCoresLabel"
Grid.Row="3"
Grid.Column="0"
VerticalAlignment="Center"
Text="Max Cores" />
<xwpf:IntegerUpDown
x:Name="MaxCoresSpinner"
Grid.Row="3"
Grid.Column="2"
MinWidth="75"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Foreground="White"
Maximum="255"
Minimum="1" />
<TextBlock
x:Name="TargetUsageLabel"
Grid.Row="3"
Grid.Column="0"
VerticalAlignment="Center"
Text="Target Percent Usage" />
<xwpf:DoubleUpDown
x:Name="TargetUsageSpinner"
Grid.Row="3"
Grid.Column="2"
MinWidth="75"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Foreground="White"
FormatString="F2"
Increment="0.1"
Maximum="1"
Minimum="0.1" />
<Slider
x:Name="TargetUsageSlider"
Grid.Row="4"
Grid.Column="0"
Grid.ColumnSpan="3"
IsSnapToTickEnabled="True"
LargeChange="0.1"
Maximum="1"
Minimum="0.1"
TickFrequency="0.05" />
</Grid>
</Border>
</rxui:ReactiveUserControl>

View File

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ReactiveUI;
namespace Wabbajack
{
/// <summary>
/// Interaction logic for PerformanceSettingsView.xaml
/// </summary>
public partial class PerformanceSettingsView : ReactiveUserControl<PerformanceSettings>
{
public PerformanceSettingsView()
{
InitializeComponent();
this.AutoButton.Command = ReactiveCommand.Create(
execute: () => this.ViewModel.Manual = false,
canExecute: this.WhenAny(x => x.ViewModel.Manual)
.ObserveOnGuiThread());
this.ManualButton.Command = ReactiveCommand.Create(
execute: () => this.ViewModel.Manual = true,
canExecute: this.WhenAny(x => x.ViewModel.Manual)
.Select(x => !x)
.ObserveOnGuiThread());
this.WhenActivated(disposable =>
{
// Bind mode buttons
// Modify visibility of controls based on if auto
this.OneWayBindStrict(this.ViewModel, x => x.Manual, x => x.MaxCoresLabel.Visibility,
b => b ? Visibility.Visible : Visibility.Collapsed)
.DisposeWith(disposable);
this.OneWayBindStrict(this.ViewModel, x => x.Manual, x => x.MaxCoresSpinner.Visibility,
b => b ? Visibility.Visible : Visibility.Collapsed)
.DisposeWith(disposable);
this.OneWayBindStrict(this.ViewModel, x => x.Manual, x => x.TargetUsageLabel.Visibility,
b => b ? Visibility.Collapsed : Visibility.Visible)
.DisposeWith(disposable);
this.OneWayBindStrict(this.ViewModel, x => x.Manual, x => x.TargetUsageSpinner.Visibility,
b => b ? Visibility.Collapsed : Visibility.Visible)
.DisposeWith(disposable);
this.OneWayBindStrict(this.ViewModel, x => x.Manual, x => x.TargetUsageSlider.Visibility,
b => b ? Visibility.Collapsed : Visibility.Visible)
.DisposeWith(disposable);
// Bind Values
this.BindStrict(this.ViewModel, x => x.MaxCores, x => x.MaxCoresSpinner.Value,
vmToViewConverter: x => x,
viewToVmConverter: x => (byte)(x ?? 0))
.DisposeWith(disposable);
this.BindStrict(this.ViewModel, x => x.TargetUsage, x => x.TargetUsageSpinner.Value)
.DisposeWith(disposable);
this.BindStrict(this.ViewModel, x => x.TargetUsage, x => x.TargetUsageSlider.Value)
.DisposeWith(disposable);
});
}
}
}

View File

@ -1,4 +1,4 @@
<UserControl <rxui:ReactiveUserControl
x:Class="Wabbajack.SettingsView" x:Class="Wabbajack.SettingsView"
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,9 +6,18 @@
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: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:SettingsVM"
mc:Ignorable="d"> mc:Ignorable="d">
<UserControl.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="Lucida Sans" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="FontSize" Value="12" />
</Style>
</UserControl.Resources>
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="47" /> <RowDefinition Height="47" />
@ -27,11 +36,18 @@
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>
<local:LoginManagerView Grid.Row="1" DataContext="{Binding LoginManagerVM}" /> <ScrollViewer
Grid.Row="1"
Focusable="False"
VerticalScrollBarVisibility="Auto">
<WrapPanel>
<local:LoginSettingsView x:Name="LoginView" />
<local:PerformanceSettingsView x:Name="PerformanceView" />
</WrapPanel>
</ScrollViewer>
</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,27 @@ 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 SettingsView.xaml /// Interaction logic for SettingsView.xaml
/// </summary> /// </summary>
public partial class SettingsView : UserControl public partial class SettingsView : ReactiveUserControl<SettingsVM>
{ {
public SettingsView() public SettingsView()
{ {
InitializeComponent(); InitializeComponent();
this.WhenActivated(disposable =>
{
this.OneWayBind(this.ViewModel, x => x.BackCommand, x => x.BackButton.Command)
.DisposeWith(disposable);
this.OneWayBind(this.ViewModel, x => x.Login, x => x.LoginView.ViewModel)
.DisposeWith(disposable);
this.OneWayBind(this.ViewModel, x => x.Performance, x => x.PerformanceView.ViewModel)
.DisposeWith(disposable);
});
} }
} }
} }

View File

@ -172,6 +172,16 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</ApplicationDefinition> </ApplicationDefinition>
<Compile Include="Converters\IntDownCastConverter.cs" />
<Compile Include="Converters\CommandConverter.cs" />
<Compile Include="Converters\ConverterRegistration.cs" />
<Compile Include="Extensions\IViewForExt.cs" />
<Compile Include="Views\Settings\LoginSettingsView.xaml.cs">
<DependentUpon>LoginSettingsView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Settings\PerformanceSettingsView.xaml.cs">
<DependentUpon>PerformanceSettingsView.xaml</DependentUpon>
</Compile>
<Compile Include="View Models\BackNavigatingVM.cs" /> <Compile Include="View Models\BackNavigatingVM.cs" />
<Compile Include="View Models\Settings\SettingsVM.cs" /> <Compile Include="View Models\Settings\SettingsVM.cs" />
<Compile Include="Views\Settings\SettingsView.xaml.cs"> <Compile Include="Views\Settings\SettingsView.xaml.cs">
@ -270,9 +280,6 @@
<Compile Include="Views\ModListGalleryView.xaml.cs"> <Compile Include="Views\ModListGalleryView.xaml.cs">
<DependentUpon>ModListGalleryView.xaml</DependentUpon> <DependentUpon>ModListGalleryView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\Settings\LoginManagerView.xaml.cs">
<DependentUpon>LoginManagerView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\TextViewer.xaml.cs"> <Compile Include="Views\TextViewer.xaml.cs">
<DependentUpon>TextViewer.xaml</DependentUpon> <DependentUpon>TextViewer.xaml</DependentUpon>
</Compile> </Compile>
@ -286,6 +293,14 @@
<Compile Include="Views\WebBrowserView.xaml.cs"> <Compile Include="Views\WebBrowserView.xaml.cs">
<DependentUpon>WebBrowserView.xaml</DependentUpon> <DependentUpon>WebBrowserView.xaml</DependentUpon>
</Compile> </Compile>
<Page Include="Views\Settings\LoginSettingsView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Settings\PerformanceSettingsView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Settings\SettingsView.xaml"> <Page Include="Views\Settings\SettingsView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -392,10 +407,6 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Views\Settings\LoginManagerView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\TextViewer.xaml"> <Page Include="Views\TextViewer.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
@ -496,6 +507,9 @@
<PackageReference Include="DynamicData"> <PackageReference Include="DynamicData">
<Version>6.14.3</Version> <Version>6.14.3</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Extended.Wpf.Toolkit">
<Version>3.7.0</Version>
</PackageReference>
<PackageReference Include="Fody"> <PackageReference Include="Fody">
<Version>6.0.6</Version> <Version>6.0.6</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>