mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
commit
e9585feb9c
38
Wabbajack.Common/Util/TempFile.cs
Normal file
38
Wabbajack.Common/Util/TempFile.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Common
|
||||
{
|
||||
public class TempFile : IDisposable
|
||||
{
|
||||
public FileInfo File { get; private set; }
|
||||
public bool DeleteAfter = true;
|
||||
|
||||
public TempFile(bool deleteAfter = true, bool createFolder = true)
|
||||
: this(new FileInfo(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())))
|
||||
{
|
||||
}
|
||||
|
||||
public TempFile(FileInfo file, bool deleteAfter = true, bool createFolder = true)
|
||||
{
|
||||
this.File = file;
|
||||
if (createFolder && !file.Directory.Exists)
|
||||
{
|
||||
file.Directory.Create();
|
||||
}
|
||||
this.DeleteAfter = deleteAfter;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (DeleteAfter)
|
||||
{
|
||||
this.File.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
45
Wabbajack.Common/Util/TempFolder.cs
Normal file
45
Wabbajack.Common/Util/TempFolder.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack.Common
|
||||
{
|
||||
public class TempFolder : IDisposable
|
||||
{
|
||||
public DirectoryInfo Dir { get; private set; }
|
||||
public bool DeleteAfter = true;
|
||||
|
||||
public TempFolder(bool deleteAfter = true)
|
||||
{
|
||||
this.Dir = new DirectoryInfo(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));
|
||||
this.Dir.Create();
|
||||
this.DeleteAfter = deleteAfter;
|
||||
}
|
||||
|
||||
public TempFolder(DirectoryInfo dir, bool deleteAfter = true)
|
||||
{
|
||||
this.Dir = dir;
|
||||
if (!dir.Exists)
|
||||
{
|
||||
this.Dir.Create();
|
||||
}
|
||||
this.DeleteAfter = deleteAfter;
|
||||
}
|
||||
|
||||
public TempFolder(string addedFolderPath, bool deleteAfter = true)
|
||||
: this(new DirectoryInfo(Path.Combine(Path.GetTempPath(), addedFolderPath)), deleteAfter: deleteAfter)
|
||||
{
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (DeleteAfter)
|
||||
{
|
||||
Utils.DeleteDirectory(this.Dir.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -75,9 +75,6 @@
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Syroot.KnownFolders">
|
||||
<HintPath>..\..\..\Users\tbald\.nuget\packages\syroot.windows.io.knownfolders\1.2.1\lib\net452\Syroot.KnownFolders.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
@ -103,6 +100,7 @@
|
||||
<Compile Include="Enums\ModManager.cs" />
|
||||
<Compile Include="ExtensionManager.cs" />
|
||||
<Compile Include="Extensions\DictionaryExt.cs" />
|
||||
<Compile Include="Extensions\EnumerableExt.cs" />
|
||||
<Compile Include="Extensions\EnumExt.cs" />
|
||||
<Compile Include="Extensions\HashHelper.cs" />
|
||||
<Compile Include="Extensions\RxExt.cs" />
|
||||
@ -131,6 +129,8 @@
|
||||
<Compile Include="StatusUpdate.cs" />
|
||||
<Compile Include="SteamHandler.cs" />
|
||||
<Compile Include="Utils.cs" />
|
||||
<Compile Include="Util\TempFile.cs" />
|
||||
<Compile Include="Util\TempFolder.cs" />
|
||||
<Compile Include="WorkQueue.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
3
Wabbajack.Lib/FodyWeavers.xml
Normal file
3
Wabbajack.Lib/FodyWeavers.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<ReactiveUI />
|
||||
</Weavers>
|
26
Wabbajack.Lib/FodyWeavers.xsd
Normal file
26
Wabbajack.Lib/FodyWeavers.xsd
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
|
||||
<xs:element name="Weavers">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="ReactiveUI" minOccurs="0" maxOccurs="1" type="xs:anyType" />
|
||||
</xs:all>
|
||||
<xs:attribute name="VerifyAssembly" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="GenerateXsd" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using DynamicData;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using System;
|
||||
@ -9,7 +10,7 @@ using System.Reactive.Linq;
|
||||
using System.Windows.Input;
|
||||
using Wabbajack.Lib;
|
||||
|
||||
namespace Wabbajack
|
||||
namespace Wabbajack.Lib
|
||||
{
|
||||
public class FilePickerVM : ViewModel
|
||||
{
|
||||
@ -21,10 +22,10 @@ namespace Wabbajack
|
||||
Folder
|
||||
}
|
||||
|
||||
public enum ExistCheckOptions
|
||||
public enum CheckOptions
|
||||
{
|
||||
Off,
|
||||
IfNotEmpty,
|
||||
IfPathNotEmpty,
|
||||
On
|
||||
}
|
||||
|
||||
@ -43,7 +44,10 @@ namespace Wabbajack
|
||||
public PathTypeOptions PathType { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public ExistCheckOptions ExistCheckOption { get; set; }
|
||||
public CheckOptions ExistCheckOption { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public CheckOptions FilterCheckOption { get; set; } = CheckOptions.IfPathNotEmpty;
|
||||
|
||||
[Reactive]
|
||||
public IObservable<IErrorResponse> AdditionalError { get; set; }
|
||||
@ -60,46 +64,52 @@ namespace Wabbajack
|
||||
private readonly ObservableAsPropertyHelper<string> _errorTooltip;
|
||||
public string ErrorTooltip => _errorTooltip.Value;
|
||||
|
||||
public List<CommonFileDialogFilter> Filters { get; } = new List<CommonFileDialogFilter>();
|
||||
public SourceList<CommonFileDialogFilter> Filters { get; } = new SourceList<CommonFileDialogFilter>();
|
||||
|
||||
public const string PathDoesNotExistText = "Path does not exist";
|
||||
public const string DoesNotPassFiltersText = "Path does not pass designated filters";
|
||||
|
||||
public FilePickerVM(object parentVM = null)
|
||||
{
|
||||
Parent = parentVM;
|
||||
SetTargetPathCommand = ConstructTypicalPickerCommand();
|
||||
|
||||
// Check that file exists
|
||||
|
||||
var existsCheckTuple = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ExistCheckOption),
|
||||
this.WhenAny(x => x.PathType),
|
||||
this.WhenAny(x => x.TargetPath)
|
||||
// Dont want to debounce the initial value, because we know it's null
|
||||
.Skip(1)
|
||||
.Debounce(TimeSpan.FromMilliseconds(200))
|
||||
.StartWith(default(string)),
|
||||
// Dont want to debounce the initial value, because we know it's null
|
||||
.Skip(1)
|
||||
.Debounce(TimeSpan.FromMilliseconds(200))
|
||||
.StartWith(default(string)),
|
||||
resultSelector: (existsOption, type, path) => (ExistsOption: existsOption, Type: type, Path: path))
|
||||
.Publish()
|
||||
.StartWith((ExistsOption: ExistCheckOption, Type: PathType, Path: TargetPath))
|
||||
.Replay(1)
|
||||
.RefCount();
|
||||
|
||||
var doExistsCheck = existsCheckTuple
|
||||
.Select(t =>
|
||||
{
|
||||
// Don't do exists type if we don't know what path type we're tracking
|
||||
if (t.Type == PathTypeOptions.Off) return false;
|
||||
switch (t.ExistsOption)
|
||||
{
|
||||
case CheckOptions.Off:
|
||||
return false;
|
||||
case CheckOptions.IfPathNotEmpty:
|
||||
return !string.IsNullOrWhiteSpace(t.Path);
|
||||
case CheckOptions.On:
|
||||
return true;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
})
|
||||
.Replay(1)
|
||||
.RefCount();
|
||||
|
||||
_exists = Observable.Interval(TimeSpan.FromSeconds(3))
|
||||
// Only check exists on timer if desired
|
||||
.FilterSwitch(existsCheckTuple
|
||||
.Select(t =>
|
||||
{
|
||||
// Don't do exists type if we don't know what path type we're tracking
|
||||
if (t.Type == PathTypeOptions.Off) return false;
|
||||
switch (t.ExistsOption)
|
||||
{
|
||||
case ExistCheckOptions.Off:
|
||||
return false;
|
||||
case ExistCheckOptions.IfNotEmpty:
|
||||
return !string.IsNullOrWhiteSpace(t.Path);
|
||||
case ExistCheckOptions.On:
|
||||
return true;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}))
|
||||
.FilterSwitch(doExistsCheck)
|
||||
.Unit()
|
||||
// Also check though, when fields change
|
||||
.Merge(this.WhenAny(x => x.PathType).Unit())
|
||||
@ -113,14 +123,14 @@ namespace Wabbajack
|
||||
{
|
||||
switch (t.ExistsOption)
|
||||
{
|
||||
case ExistCheckOptions.IfNotEmpty:
|
||||
if (string.IsNullOrWhiteSpace(t.Path)) return true;
|
||||
case CheckOptions.IfPathNotEmpty:
|
||||
if (string.IsNullOrWhiteSpace(t.Path)) return false;
|
||||
break;
|
||||
case ExistCheckOptions.On:
|
||||
case CheckOptions.On:
|
||||
break;
|
||||
case ExistCheckOptions.Off:
|
||||
case CheckOptions.Off:
|
||||
default:
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
switch (t.Type)
|
||||
{
|
||||
@ -130,24 +140,81 @@ namespace Wabbajack
|
||||
return File.Exists(t.Path);
|
||||
case PathTypeOptions.Folder:
|
||||
return Directory.Exists(t.Path);
|
||||
case PathTypeOptions.Off:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.DistinctUntilChanged()
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.StartWith(false)
|
||||
.ToProperty(this, nameof(Exists));
|
||||
|
||||
var passesFilters = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.TargetPath),
|
||||
this.WhenAny(x => x.PathType),
|
||||
this.WhenAny(x => x.FilterCheckOption),
|
||||
Filters.Connect().QueryWhenChanged(),
|
||||
resultSelector: (target, type, checkOption, query) =>
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PathTypeOptions.Either:
|
||||
case PathTypeOptions.File:
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
if (query.Count == 0) return true;
|
||||
switch (checkOption)
|
||||
{
|
||||
case CheckOptions.Off:
|
||||
return true;
|
||||
case CheckOptions.IfPathNotEmpty:
|
||||
if (string.IsNullOrWhiteSpace(target)) return true;
|
||||
break;
|
||||
case CheckOptions.On:
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var extension = Path.GetExtension(target);
|
||||
if (extension == null || !extension.StartsWith(".")) return false;
|
||||
extension = extension.Substring(1);
|
||||
if (!query.Any(filter => filter.Extensions.Any(ext => string.Equals(ext, extension)))) return false;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.StartWith(false)
|
||||
.DistinctUntilChanged()
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.ToProperty(this, nameof(Exists));
|
||||
.StartWith(true)
|
||||
.Select(passed =>
|
||||
{
|
||||
if (passed) return ErrorResponse.Success;
|
||||
return ErrorResponse.Fail(DoesNotPassFiltersText);
|
||||
})
|
||||
.Replay(1)
|
||||
.RefCount();
|
||||
|
||||
_errorState = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.Exists)
|
||||
.Select(exists => ErrorResponse.Create(successful: exists, exists ? default(string) : "Path does not exist")),
|
||||
Observable.CombineLatest(
|
||||
this.WhenAny(x => x.Exists),
|
||||
doExistsCheck,
|
||||
resultSelector: (exists, doExists) => !doExists || exists)
|
||||
.Select(exists => ErrorResponse.Create(successful: exists, exists ? default(string) : PathDoesNotExistText)),
|
||||
passesFilters,
|
||||
this.WhenAny(x => x.AdditionalError)
|
||||
.Select(x => x ?? Observable.Return<IErrorResponse>(ErrorResponse.Success))
|
||||
.Switch(),
|
||||
resultSelector: (exist, err) =>
|
||||
resultSelector: (existCheck, filter, err) =>
|
||||
{
|
||||
if (exist.Failed) return exist;
|
||||
if (existCheck.Failed) return existCheck;
|
||||
if (filter.Failed) return filter;
|
||||
return ErrorResponse.Convert(err);
|
||||
})
|
||||
.ToProperty(this, nameof(ErrorState));
|
||||
@ -159,14 +226,20 @@ namespace Wabbajack
|
||||
// Doesn't derive from ErrorState, as we want to bubble non-empty tooltips,
|
||||
// which is slightly different logic
|
||||
_errorTooltip = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.Exists)
|
||||
.Select(exists => exists ? default(string) : "Path does not exist"),
|
||||
Observable.CombineLatest(
|
||||
this.WhenAny(x => x.Exists),
|
||||
doExistsCheck,
|
||||
resultSelector: (exists, doExists) => !doExists || exists)
|
||||
.Select(exists => exists ? default(string) : PathDoesNotExistText),
|
||||
passesFilters
|
||||
.Select(x => x.Reason),
|
||||
this.WhenAny(x => x.AdditionalError)
|
||||
.Select(x => x ?? Observable.Return<IErrorResponse>(ErrorResponse.Success))
|
||||
.Switch(),
|
||||
resultSelector: (exists, err) =>
|
||||
resultSelector: (exists, filters, err) =>
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(exists)) return exists;
|
||||
if (!string.IsNullOrWhiteSpace(filters)) return filters;
|
||||
return err?.Reason;
|
||||
})
|
||||
.ToProperty(this, nameof(ErrorTooltip));
|
||||
@ -201,7 +274,7 @@ namespace Wabbajack
|
||||
Multiselect = false,
|
||||
ShowPlacesList = true,
|
||||
};
|
||||
foreach (var filter in Filters)
|
||||
foreach (var filter in Filters.Items)
|
||||
{
|
||||
dlg.Filters.Add(filter);
|
||||
}
|
@ -18,8 +18,10 @@ namespace Wabbajack.Lib
|
||||
{
|
||||
var img = new BitmapImage();
|
||||
img.BeginInit();
|
||||
img.CacheOption = BitmapCacheOption.OnLoad;
|
||||
img.StreamSource = stream;
|
||||
img.EndInit();
|
||||
img.Freeze();
|
||||
return img;
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,6 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="Syroot.KnownFolders" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Design" />
|
||||
@ -119,6 +118,7 @@
|
||||
<Compile Include="Downloaders\GameFileSourceDownloader.cs" />
|
||||
<Compile Include="Downloaders\LoversLabDownloader.cs" />
|
||||
<Compile Include="Downloaders\SteamWorkshopDownloader.cs" />
|
||||
<Compile Include="Extensions\ReactiveUIExt.cs" />
|
||||
<Compile Include="LibCefHelpers\Init.cs" />
|
||||
<Compile Include="MO2Compiler.cs" />
|
||||
<Compile Include="Data.cs" />
|
||||
@ -145,6 +145,7 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ReportBuilder.cs" />
|
||||
<Compile Include="StatusMessages\ConfirmUpdateOfExistingInstall.cs" />
|
||||
<Compile Include="UI\FilePickerVM.cs" />
|
||||
<Compile Include="UI\UIUtils.cs" />
|
||||
<Compile Include="Validation\DTOs.cs" />
|
||||
<Compile Include="Validation\ValidateModlist.cs" />
|
||||
@ -210,6 +211,9 @@
|
||||
<PackageReference Include="ReactiveUI">
|
||||
<Version>11.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ReactiveUI.Fody">
|
||||
<Version>11.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SharpCompress">
|
||||
<Version>0.24.0</Version>
|
||||
</PackageReference>
|
||||
|
368
Wabbajack.Test/FilePickerTests.cs
Normal file
368
Wabbajack.Test/FilePickerTests.cs
Normal file
@ -0,0 +1,368 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DynamicData;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
|
||||
namespace Wabbajack.Test
|
||||
{
|
||||
[TestClass]
|
||||
public class FilePickerTests
|
||||
{
|
||||
public static TempFile CreateSetFile(FilePickerVM vm)
|
||||
{
|
||||
var temp = new TempFile();
|
||||
using (new FileStream(temp.File.FullName, FileMode.CreateNew)) { }
|
||||
vm.TargetPath = temp.File.FullName;
|
||||
return temp;
|
||||
}
|
||||
|
||||
public static TempFolder CreateSetFolder(FilePickerVM vm)
|
||||
{
|
||||
var temp = new TempFolder();
|
||||
Directory.CreateDirectory(temp.Dir.FullName);
|
||||
vm.TargetPath = temp.Dir.FullName;
|
||||
return temp;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Stock()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
Assert.AreEqual(FilePickerVM.PathTypeOptions.Off, vm.PathType);
|
||||
Assert.AreEqual(FilePickerVM.CheckOptions.Off, vm.ExistCheckOption);
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FileNoExistsCheck_DoesNotExist()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.File;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.Off;
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FileNoExistsCheck_Exists()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
using (CreateSetFile(vm))
|
||||
{
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.File;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.Off;
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task ExistCheckTypeOff_DoesNotExist()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.Off;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.On;
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task ExistCheckTypeOff_Exists()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
using (CreateSetFile(vm))
|
||||
{
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.Off;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.On;
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FileIfNotEmptyCheck_DoesNotExist()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.File;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty;
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FileIfNotEmptyCheck_SetPath_DoesNotExist()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.File;
|
||||
vm.TargetPath = "SomePath.jpg";
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty;
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsFalse(vm.ErrorState.Succeeded);
|
||||
Assert.IsTrue(vm.InError);
|
||||
Assert.AreEqual(FilePickerVM.PathDoesNotExistText, vm.ErrorTooltip);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FileIfNotEmptyCheck_Exists()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
using (CreateSetFile(vm))
|
||||
{
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.File;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty;
|
||||
await Task.Delay(250);
|
||||
Assert.IsTrue(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FileOnExistsCheck_DoesNotExist()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.File;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.On;
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsFalse(vm.ErrorState.Succeeded);
|
||||
Assert.IsTrue(vm.InError);
|
||||
Assert.AreEqual(FilePickerVM.PathDoesNotExistText, vm.ErrorTooltip);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FileOnExistsCheck_Exists()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
using (CreateSetFile(vm))
|
||||
{
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.File;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.On;
|
||||
await Task.Delay(250);
|
||||
Assert.IsTrue(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FolderIfNotEmptyCheck_DoesNotExist()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.Folder;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty;
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FolderIfNotEmptyCheck_SetPath_DoesNotExist()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.Folder;
|
||||
vm.TargetPath = "SomePath.jpg";
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty;
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsFalse(vm.ErrorState.Succeeded);
|
||||
Assert.IsTrue(vm.InError);
|
||||
Assert.AreEqual(FilePickerVM.PathDoesNotExistText, vm.ErrorTooltip);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FolderIfNotEmptyCheck_Exists()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
using (CreateSetFolder(vm))
|
||||
{
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.Folder;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty;
|
||||
await Task.Delay(250);
|
||||
Assert.IsTrue(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FolderOnExistsCheck_DoesNotExist()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.Folder;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.On;
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsFalse(vm.ErrorState.Succeeded);
|
||||
Assert.IsTrue(vm.InError);
|
||||
Assert.AreEqual(FilePickerVM.PathDoesNotExistText, vm.ErrorTooltip);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FolderOnExistsCheck_Exists()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
using (CreateSetFolder(vm))
|
||||
{
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.Folder;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.On;
|
||||
await Task.Delay(250);
|
||||
Assert.IsTrue(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task AdditionalError_Success()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
vm.AdditionalError = Observable.Return<IErrorResponse>(ErrorResponse.Succeed());
|
||||
await Task.Delay(250);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task AdditionalError_Fail()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
string errText = "An error";
|
||||
vm.AdditionalError = Observable.Return<IErrorResponse>(ErrorResponse.Fail(errText));
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.ErrorState.Succeeded);
|
||||
Assert.IsTrue(vm.InError);
|
||||
Assert.AreEqual(errText, vm.ErrorTooltip);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FileExistsButSetToFolder()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
using (CreateSetFile(vm))
|
||||
{
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.Folder;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.On;
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsFalse(vm.ErrorState.Succeeded);
|
||||
Assert.IsTrue(vm.InError);
|
||||
Assert.AreEqual(FilePickerVM.PathDoesNotExistText, vm.ErrorTooltip);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FolderExistsButSetToFile()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
using (CreateSetFolder(vm))
|
||||
{
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.File;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.On;
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsFalse(vm.ErrorState.Succeeded);
|
||||
Assert.IsTrue(vm.InError);
|
||||
Assert.AreEqual(FilePickerVM.PathDoesNotExistText, vm.ErrorTooltip);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FileWithFilters_Passes()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
using (CreateSetFile(vm))
|
||||
{
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.File;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.Off;
|
||||
vm.Filters.Add(new Microsoft.WindowsAPICodePack.Dialogs.CommonFileDialogFilter("test", $"*.{Path.GetExtension(vm.TargetPath)}"));
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FileWithFilters_ExistsButFails()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
using (CreateSetFile(vm))
|
||||
{
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.File;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.Off;
|
||||
vm.Filters.Add(new Microsoft.WindowsAPICodePack.Dialogs.CommonFileDialogFilter("test", $"*.{Path.GetExtension(vm.TargetPath)}z"));
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsFalse(vm.ErrorState.Succeeded);
|
||||
Assert.IsTrue(vm.InError);
|
||||
Assert.AreEqual(FilePickerVM.DoesNotPassFiltersText, vm.ErrorTooltip);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FileWithFilters_PassesButDoesntExist()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.File;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.Off;
|
||||
vm.TargetPath = "SomePath.png";
|
||||
vm.Filters.Add(new Microsoft.WindowsAPICodePack.Dialogs.CommonFileDialogFilter("test", $"*.{Path.GetExtension(vm.TargetPath)}"));
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task FileWithFilters_IfNotEmptyCheck_DoesntExist()
|
||||
{
|
||||
var vm = new FilePickerVM();
|
||||
vm.PathType = FilePickerVM.PathTypeOptions.File;
|
||||
vm.ExistCheckOption = FilePickerVM.CheckOptions.Off;
|
||||
vm.FilterCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty;
|
||||
vm.Filters.Add(new Microsoft.WindowsAPICodePack.Dialogs.CommonFileDialogFilter("test", $"*.{Path.GetExtension(vm.TargetPath)}"));
|
||||
await Task.Delay(250);
|
||||
Assert.IsFalse(vm.Exists);
|
||||
Assert.IsTrue(vm.ErrorState.Succeeded);
|
||||
Assert.IsFalse(vm.InError);
|
||||
Assert.IsTrue(string.IsNullOrEmpty(vm.ErrorTooltip));
|
||||
}
|
||||
}
|
||||
}
|
@ -105,6 +105,7 @@
|
||||
<Compile Include="DownloaderTests.cs" />
|
||||
<Compile Include="EndToEndTests.cs" />
|
||||
<Compile Include="Extensions.cs" />
|
||||
<Compile Include="FilePickerTests.cs" />
|
||||
<Compile Include="MiscTests.cs" />
|
||||
<Compile Include="ModlistMetadataTests.cs" />
|
||||
<Compile Include="TestUtils.cs" />
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 3.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 512 B |
Binary file not shown.
Before Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 50 KiB |
@ -20,10 +20,11 @@
|
||||
<!-- Colors -->
|
||||
<Color x:Key="WindowBackgroundColor">#121212</Color>
|
||||
<Color x:Key="DarkBackgroundColor">#222222</Color>
|
||||
<Color x:Key="DarkHoverBackgroundColor">#272727</Color>
|
||||
<Color x:Key="LightBackgroundColor">#424242</Color>
|
||||
<Color x:Key="BackgroundColor">#323232</Color>
|
||||
<Color x:Key="DisabledBackgroundColor">#424242</Color>
|
||||
<Color x:Key="PressedBackgroundColor">#394140</Color>
|
||||
<Color x:Key="PressedBackgroundColor">#323232</Color>
|
||||
<Color x:Key="LightDisabledBackgroundColor">#666666</Color>
|
||||
<Color x:Key="HeatedBorderColor">#362675</Color>
|
||||
|
||||
@ -49,6 +50,7 @@
|
||||
<Color x:Key="LightSecondary">#8cede5</Color>
|
||||
<Color x:Key="IntenseSecondary">#00ffe7</Color>
|
||||
<Color x:Key="Complementary">#C7FC86</Color>
|
||||
<Color x:Key="DarkComplementary">#8eb55e</Color>
|
||||
<Color x:Key="IntenseComplementary">#abf74d</Color>
|
||||
<Color x:Key="Analogous1">#868CFC</Color>
|
||||
<Color x:Key="Analogous2">#F686FC</Color>
|
||||
@ -102,6 +104,7 @@
|
||||
<SolidColorBrush x:Key="ErrorBrush" Color="{StaticResource Red}" />
|
||||
|
||||
<SolidColorBrush x:Key="DarkBackgroundBrush" Color="{StaticResource DarkBackgroundColor}" />
|
||||
<SolidColorBrush x:Key="DarkHoverBackgroundBrush" Color="{StaticResource DarkHoverBackgroundColor}" />
|
||||
<SolidColorBrush x:Key="LightBackgroundBrush" Color="{StaticResource LightBackgroundColor}" />
|
||||
<SolidColorBrush x:Key="BackgroundBrush" Color="{StaticResource BackgroundColor}" />
|
||||
<SolidColorBrush x:Key="ForegroundBrush" Color="{StaticResource ForegroundColor}" />
|
||||
@ -122,6 +125,7 @@
|
||||
<SolidColorBrush x:Key="LightSecondaryBrush" Color="{StaticResource LightSecondary}" />
|
||||
<SolidColorBrush x:Key="IntenseSecondaryBrush" Color="{StaticResource IntenseSecondary}" />
|
||||
<SolidColorBrush x:Key="ComplementaryBrush" Color="{StaticResource Complementary}" />
|
||||
<SolidColorBrush x:Key="DarkComplementaryBrush" Color="{StaticResource DarkComplementary}" />
|
||||
<SolidColorBrush x:Key="IntenseComplementaryBrush" Color="{StaticResource IntenseComplementary}" />
|
||||
<SolidColorBrush x:Key="Analogous1Brush" Color="{StaticResource Analogous1}" />
|
||||
<SolidColorBrush x:Key="Analogous2Brush" Color="{StaticResource Analogous2}" />
|
||||
@ -1453,7 +1457,7 @@
|
||||
|
||||
<Style x:Key="MainButtonStyle" TargetType="{x:Type Button}">
|
||||
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}" />
|
||||
<Setter Property="Background" Value="{StaticResource ButtonBackground}" />
|
||||
<Setter Property="Background" Value="{StaticResource DarkBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{StaticResource ButtonBorder}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="Focusable" Value="False" />
|
||||
@ -1466,7 +1470,7 @@
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Grid>
|
||||
<Border
|
||||
Background="{StaticResource SecondaryBrush}"
|
||||
Background="{StaticResource ComplementaryBrush}"
|
||||
CornerRadius="3"
|
||||
Opacity="0.7">
|
||||
<Border.Effect>
|
||||
@ -1498,14 +1502,14 @@
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter Property="Background" Value="{StaticResource MouseOverButtonBackground}" />
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DarkSecondaryBrush}" />
|
||||
<Setter Property="Foreground" Value="{StaticResource MouseOverButtonForeground}" />
|
||||
<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 SecondaryBrush}" />
|
||||
<Setter Property="Foreground" Value="{StaticResource ButtonForeground}" />
|
||||
<Setter Property="BorderBrush" Value="{StaticResource ComplementaryBrush}" />
|
||||
<Setter Property="Foreground" Value="{StaticResource IntenseComplementaryBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledButtonForeground}" />
|
||||
@ -1552,6 +1556,40 @@
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IconBareButtonStyle" TargetType="ButtonBase">
|
||||
<Setter Property="Focusable" Value="False" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border Background="{TemplateBinding Background}" CornerRadius="3">
|
||||
<ContentPresenter
|
||||
Margin="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
RecognizesAccessKey="True"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledButtonForeground}" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="BorderBrush" Value="{StaticResource GrayBrush7}" />
|
||||
<Setter Property="Foreground" Value="{StaticResource IntenseComplementaryBrush}" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource BackgroundBrush}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- ToggleButton -->
|
||||
<Style TargetType="{x:Type ToggleButton}">
|
||||
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}" />
|
||||
|
25
Wabbajack/View Models/CPUDisplayVM.cs
Normal file
25
Wabbajack/View Models/CPUDisplayVM.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Wabbajack.Common;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
public class CPUDisplayVM
|
||||
{
|
||||
public CPUStatus Status { get; set; }
|
||||
public DateTime StartTime { get; set; }
|
||||
|
||||
public void AbsorbStatus(CPUStatus cpu)
|
||||
{
|
||||
bool starting = cpu.IsWorking && ((!Status?.IsWorking) ?? true);
|
||||
Status = cpu;
|
||||
if (starting)
|
||||
{
|
||||
StartTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,11 @@ using DynamicData.Binding;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Windows.Media.Imaging;
|
||||
@ -35,26 +39,48 @@ namespace Wabbajack
|
||||
private readonly ObservableAsPropertyHelper<float> _percentCompleted;
|
||||
public float PercentCompleted => _percentCompleted.Value;
|
||||
|
||||
public ObservableCollectionExtended<CPUStatus> StatusList { get; } = new ObservableCollectionExtended<CPUStatus>();
|
||||
public ObservableCollectionExtended<CPUDisplayVM> StatusList { get; } = new ObservableCollectionExtended<CPUDisplayVM>();
|
||||
|
||||
public ObservableCollectionExtended<IStatusMessage> Log => MWVM.Log;
|
||||
|
||||
public IReactiveCommand BackCommand { get; }
|
||||
public IReactiveCommand GoToModlistCommand { get; }
|
||||
public IReactiveCommand CloseWhenCompleteCommand { get; }
|
||||
|
||||
public FilePickerVM OutputLocation { get; }
|
||||
|
||||
private readonly ObservableAsPropertyHelper<IUserIntervention> _ActiveGlobalUserIntervention;
|
||||
public IUserIntervention ActiveGlobalUserIntervention => _ActiveGlobalUserIntervention.Value;
|
||||
|
||||
private readonly ObservableAsPropertyHelper<bool> _Completed;
|
||||
public bool Completed => _Completed.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Tracks whether compilation has begun
|
||||
/// </summary>
|
||||
[Reactive]
|
||||
public bool CompilationMode { get; set; }
|
||||
|
||||
public CompilerVM(MainWindowVM mainWindowVM)
|
||||
{
|
||||
MWVM = mainWindowVM;
|
||||
|
||||
OutputLocation = new FilePickerVM()
|
||||
{
|
||||
ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty,
|
||||
PathType = FilePickerVM.PathTypeOptions.Folder,
|
||||
PromptTitle = "Select the folder to place the resulting modlist.wabbajack file",
|
||||
};
|
||||
|
||||
// Load settings
|
||||
CompilerSettings settings = MWVM.Settings.Compiler;
|
||||
SelectedCompilerType = settings.LastCompiledModManager;
|
||||
OutputLocation.TargetPath = settings.OutputLocation;
|
||||
MWVM.Settings.SaveSignal
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
settings.LastCompiledModManager = SelectedCompilerType;
|
||||
settings.OutputLocation = OutputLocation.TargetPath;
|
||||
})
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
@ -108,39 +134,73 @@ namespace Wabbajack
|
||||
.ToProperty(this, nameof(Compiling));
|
||||
|
||||
BackCommand = ReactiveCommand.Create(
|
||||
execute: () => mainWindowVM.ActivePane = mainWindowVM.ModeSelectionVM,
|
||||
execute: () =>
|
||||
{
|
||||
mainWindowVM.ActivePane = mainWindowVM.ModeSelectionVM;
|
||||
CompilationMode = false;
|
||||
},
|
||||
canExecute: this.WhenAny(x => x.Compiling)
|
||||
.Select(x => !x));
|
||||
|
||||
// Compile progress updates and populate ObservableCollection
|
||||
Dictionary<int, CPUDisplayVM> cpuDisplays = new Dictionary<int, CPUDisplayVM>();
|
||||
this.WhenAny(x => x.Compiler.ActiveCompilation)
|
||||
.SelectMany(c => c?.QueueStatus ?? Observable.Empty<CPUStatus>())
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.ToObservableChangeSet(x => x.ID)
|
||||
// Attach start times to incoming CPU items
|
||||
.Scan(
|
||||
new CPUDisplayVM(),
|
||||
(_, cpu) =>
|
||||
{
|
||||
var ret = cpuDisplays.TryCreate(cpu.ID);
|
||||
ret.AbsorbStatus(cpu);
|
||||
return ret;
|
||||
})
|
||||
.ToObservableChangeSet(x => x.Status.ID)
|
||||
.Batch(TimeSpan.FromMilliseconds(250), RxApp.TaskpoolScheduler)
|
||||
.EnsureUniqueChanges()
|
||||
.Filter(i => i.IsWorking)
|
||||
.Filter(i => i.Status.IsWorking && i.Status.ID != WorkQueue.UnassignedCpuId)
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Sort(SortExpressionComparer<CPUStatus>.Ascending(s => s.ID), SortOptimisations.ComparesImmutableValuesOnly)
|
||||
.Sort(SortExpressionComparer<CPUDisplayVM>.Ascending(s => s.StartTime))
|
||||
.Bind(StatusList)
|
||||
.Subscribe()
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
_Completed = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.Compiling),
|
||||
this.WhenAny(x => x.CompilationMode),
|
||||
resultSelector: (installing, installingMode) =>
|
||||
{
|
||||
return installingMode && !installing;
|
||||
})
|
||||
.ToProperty(this, nameof(Completed));
|
||||
|
||||
_percentCompleted = this.WhenAny(x => x.Compiler.ActiveCompilation)
|
||||
.StartWith(default(ACompiler))
|
||||
.Pairwise()
|
||||
.Select(c =>
|
||||
{
|
||||
if (c.Current == null)
|
||||
.CombineLatest(
|
||||
this.WhenAny(x => x.Completed),
|
||||
(compiler, completed) =>
|
||||
{
|
||||
return Observable.Return<float>(c.Previous == null ? 0f : 1f);
|
||||
}
|
||||
return c.Current.PercentCompleted;
|
||||
})
|
||||
if (compiler == null)
|
||||
{
|
||||
return Observable.Return<float>(completed ? 1f : 0f);
|
||||
}
|
||||
return compiler.PercentCompleted;
|
||||
})
|
||||
.Switch()
|
||||
.Debounce(TimeSpan.FromMilliseconds(25))
|
||||
.ToProperty(this, nameof(PercentCompleted));
|
||||
|
||||
// When sub compiler begins an install, mark state variable
|
||||
this.WhenAny(x => x.Compiler.BeginCommand)
|
||||
.Select(x => x?.StartingExecution() ?? Observable.Empty<Unit>())
|
||||
.Switch()
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
CompilationMode = true;
|
||||
})
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
// Listen for user interventions, and compile a dynamic list of all unhandled ones
|
||||
var activeInterventions = this.WhenAny(x => x.Compiler.ActiveCompilation)
|
||||
.SelectMany(c => c?.LogMessages ?? Observable.Empty<IStatusMessage>())
|
||||
@ -156,6 +216,27 @@ namespace Wabbajack
|
||||
.QueryWhenChanged(query => query.FirstOrDefault())
|
||||
.ObserveOnGuiThread()
|
||||
.ToProperty(this, nameof(ActiveGlobalUserIntervention));
|
||||
|
||||
CloseWhenCompleteCommand = ReactiveCommand.Create(
|
||||
canExecute: this.WhenAny(x => x.Completed),
|
||||
execute: () =>
|
||||
{
|
||||
MWVM.ShutdownApplication();
|
||||
});
|
||||
|
||||
GoToModlistCommand = ReactiveCommand.Create(
|
||||
canExecute: this.WhenAny(x => x.Completed),
|
||||
execute: () =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(OutputLocation.TargetPath))
|
||||
{
|
||||
Process.Start("explorer.exe", Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location));
|
||||
}
|
||||
else
|
||||
{
|
||||
Process.Start("explorer.exe", OutputLocation.TargetPath);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,7 @@ namespace Wabbajack
|
||||
|
||||
public FilePickerVM DownloadLocation { get; }
|
||||
|
||||
public FilePickerVM ModlistLocation { get; }
|
||||
|
||||
public FilePickerVM OutputLocation { get; }
|
||||
public FilePickerVM ModListLocation { get; }
|
||||
|
||||
public IReactiveCommand BeginCommand { get; }
|
||||
|
||||
@ -43,26 +41,20 @@ namespace Wabbajack
|
||||
public MO2CompilerVM(CompilerVM parent)
|
||||
{
|
||||
Parent = parent;
|
||||
ModlistLocation = new FilePickerVM()
|
||||
ModListLocation = new FilePickerVM()
|
||||
{
|
||||
ExistCheckOption = FilePickerVM.ExistCheckOptions.On,
|
||||
ExistCheckOption = FilePickerVM.CheckOptions.On,
|
||||
PathType = FilePickerVM.PathTypeOptions.File,
|
||||
PromptTitle = "Select modlist"
|
||||
};
|
||||
DownloadLocation = new FilePickerVM()
|
||||
{
|
||||
ExistCheckOption = FilePickerVM.ExistCheckOptions.On,
|
||||
ExistCheckOption = FilePickerVM.CheckOptions.On,
|
||||
PathType = FilePickerVM.PathTypeOptions.Folder,
|
||||
PromptTitle = "Select download location",
|
||||
};
|
||||
OutputLocation = new FilePickerVM()
|
||||
{
|
||||
ExistCheckOption = FilePickerVM.ExistCheckOptions.IfNotEmpty,
|
||||
PathType = FilePickerVM.PathTypeOptions.Folder,
|
||||
PromptTitle = "Select the folder to place the resulting modlist.wabbajack file",
|
||||
};
|
||||
|
||||
_mo2Folder = this.WhenAny(x => x.ModlistLocation.TargetPath)
|
||||
_mo2Folder = this.WhenAny(x => x.ModListLocation.TargetPath)
|
||||
.Select(loc =>
|
||||
{
|
||||
try
|
||||
@ -76,7 +68,7 @@ namespace Wabbajack
|
||||
}
|
||||
})
|
||||
.ToProperty(this, nameof(Mo2Folder));
|
||||
_moProfile = this.WhenAny(x => x.ModlistLocation.TargetPath)
|
||||
_moProfile = this.WhenAny(x => x.ModListLocation.TargetPath)
|
||||
.Select(loc =>
|
||||
{
|
||||
try
|
||||
@ -92,33 +84,64 @@ namespace Wabbajack
|
||||
.ToProperty(this, nameof(MOProfile));
|
||||
|
||||
// Wire missing Mo2Folder to signal error state for Modlist Location
|
||||
ModlistLocation.AdditionalError = this.WhenAny(x => x.Mo2Folder)
|
||||
ModListLocation.AdditionalError = this.WhenAny(x => x.Mo2Folder)
|
||||
.Select<string, IErrorResponse>(moFolder =>
|
||||
{
|
||||
if (Directory.Exists(moFolder)) return ErrorResponse.Success;
|
||||
return ErrorResponse.Fail($"MO2 Folder could not be located from the given modlist location.{Environment.NewLine}Make sure your modlist is inside a valid MO2 distribution.");
|
||||
});
|
||||
|
||||
// Load custom modlist settings per MO2 profile
|
||||
_modlistSettings = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModListLocation.ErrorState),
|
||||
this.WhenAny(x => x.ModListLocation.TargetPath),
|
||||
resultSelector: (state, path) => (State: state, Path: path))
|
||||
// A short throttle is a quick hack to make the above changes "atomic"
|
||||
.Throttle(TimeSpan.FromMilliseconds(25))
|
||||
.Select(u =>
|
||||
{
|
||||
if (u.State.Failed) return null;
|
||||
var modlistSettings = _settings.ModlistSettings.TryCreate(u.Path);
|
||||
return new ModlistSettingsEditorVM(modlistSettings)
|
||||
{
|
||||
ModListName = MOProfile
|
||||
};
|
||||
})
|
||||
// Interject and save old while loading new
|
||||
.Pairwise()
|
||||
.Do(pair =>
|
||||
{
|
||||
pair.Previous?.Save();
|
||||
pair.Current?.Init();
|
||||
})
|
||||
.Select(x => x.Current)
|
||||
// Save to property
|
||||
.ObserveOnGuiThread()
|
||||
.ToProperty(this, nameof(ModlistSettings));
|
||||
|
||||
// Wire start command
|
||||
BeginCommand = ReactiveCommand.CreateFromTask(
|
||||
canExecute: Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModlistLocation.InError),
|
||||
this.WhenAny(x => x.ModListLocation.InError),
|
||||
this.WhenAny(x => x.DownloadLocation.InError),
|
||||
this.WhenAny(x => x.OutputLocation.InError),
|
||||
resultSelector: (ml, down, output) => !ml && !down && !output)
|
||||
parent.WhenAny(x => x.OutputLocation.InError),
|
||||
this.WhenAny(x => x.ModlistSettings)
|
||||
.Select(x => x?.InError ?? Observable.Return(false))
|
||||
.Switch(),
|
||||
resultSelector: (ml, down, output, modlistSettings) => !ml && !down && !output && !modlistSettings)
|
||||
.ObserveOnGuiThread(),
|
||||
execute: async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
string outputFile;
|
||||
if (string.IsNullOrWhiteSpace(OutputLocation.TargetPath))
|
||||
if (string.IsNullOrWhiteSpace(parent.OutputLocation.TargetPath))
|
||||
{
|
||||
outputFile = MOProfile + ExtensionManager.Extension;
|
||||
}
|
||||
else
|
||||
{
|
||||
outputFile = Path.Combine(OutputLocation.TargetPath, MOProfile + ExtensionManager.Extension);
|
||||
outputFile = Path.Combine(parent.OutputLocation.TargetPath, MOProfile + ExtensionManager.Extension);
|
||||
}
|
||||
ActiveCompilation = new MO2Compiler(
|
||||
mo2Folder: Mo2Folder,
|
||||
@ -160,44 +183,15 @@ namespace Wabbajack
|
||||
|
||||
// Load settings
|
||||
_settings = parent.MWVM.Settings.Compiler.MO2Compilation;
|
||||
ModlistLocation.TargetPath = _settings.LastCompiledProfileLocation;
|
||||
ModListLocation.TargetPath = _settings.LastCompiledProfileLocation;
|
||||
if (!string.IsNullOrWhiteSpace(_settings.DownloadLocation))
|
||||
{
|
||||
DownloadLocation.TargetPath = _settings.DownloadLocation;
|
||||
}
|
||||
OutputLocation.TargetPath = parent.MWVM.Settings.Compiler.OutputLocation;
|
||||
parent.MWVM.Settings.SaveSignal
|
||||
.Subscribe(_ => Unload())
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
// Load custom modlist settings per MO2 profile
|
||||
_modlistSettings = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModlistLocation.ErrorState),
|
||||
this.WhenAny(x => x.ModlistLocation.TargetPath),
|
||||
resultSelector: (state, path) => (State: state, Path: path))
|
||||
// A short throttle is a quick hack to make the above changes "atomic"
|
||||
.Throttle(TimeSpan.FromMilliseconds(25))
|
||||
.Select(u =>
|
||||
{
|
||||
if (u.State.Failed) return null;
|
||||
var modlistSettings = _settings.ModlistSettings.TryCreate(u.Path);
|
||||
return new ModlistSettingsEditorVM(modlistSettings)
|
||||
{
|
||||
ModListName = MOProfile
|
||||
};
|
||||
})
|
||||
// Interject and save old while loading new
|
||||
.Pairwise()
|
||||
.Do(pair =>
|
||||
{
|
||||
pair.Previous?.Save();
|
||||
pair.Current?.Init();
|
||||
})
|
||||
.Select(x => x.Current)
|
||||
// Save to property
|
||||
.ObserveOnGuiThread()
|
||||
.ToProperty(this, nameof(ModlistSettings));
|
||||
|
||||
// If Mo2 folder changes and download location is empty, set it for convenience
|
||||
this.WhenAny(x => x.Mo2Folder)
|
||||
.DelayInitial(TimeSpan.FromMilliseconds(100))
|
||||
@ -217,8 +211,7 @@ namespace Wabbajack
|
||||
public void Unload()
|
||||
{
|
||||
_settings.DownloadLocation = DownloadLocation.TargetPath;
|
||||
_settings.LastCompiledProfileLocation = ModlistLocation.TargetPath;
|
||||
Parent.MWVM.Settings.Compiler.OutputLocation = OutputLocation.TargetPath;
|
||||
_settings.LastCompiledProfileLocation = ModListLocation.TargetPath;
|
||||
ModlistSettings?.Save();
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using Wabbajack.Lib;
|
||||
|
||||
@ -24,27 +27,30 @@ namespace Wabbajack
|
||||
[Reactive]
|
||||
public string Website { get; set; }
|
||||
|
||||
public IObservable<bool> InError { get; }
|
||||
|
||||
public ModlistSettingsEditorVM(CompilationModlistSettings settings)
|
||||
{
|
||||
this._settings = settings;
|
||||
ImagePath = new FilePickerVM()
|
||||
{
|
||||
ExistCheckOption = FilePickerVM.ExistCheckOptions.IfNotEmpty,
|
||||
ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty,
|
||||
PathType = FilePickerVM.PathTypeOptions.File,
|
||||
Filters =
|
||||
{
|
||||
new CommonFileDialogFilter("Banner image", "*.png")
|
||||
}
|
||||
};
|
||||
ImagePath.Filters.Add(new CommonFileDialogFilter("Banner image", "*.png"));
|
||||
ReadMeText = new FilePickerVM()
|
||||
{
|
||||
PathType = FilePickerVM.PathTypeOptions.File,
|
||||
ExistCheckOption = FilePickerVM.ExistCheckOptions.IfNotEmpty,
|
||||
Filters =
|
||||
{
|
||||
new CommonFileDialogFilter("Text", "*.txt"),
|
||||
}
|
||||
ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty,
|
||||
};
|
||||
ReadMeText.Filters.Add(new CommonFileDialogFilter("Text", "*.txt"));
|
||||
|
||||
InError = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ImagePath.ErrorState).Select(err => err.Failed),
|
||||
this.WhenAny(x => x.ReadMeText.ErrorState).Select(err => err.Failed),
|
||||
resultSelector: (img, readme) => img || readme)
|
||||
.Publish()
|
||||
.RefCount();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
@ -14,6 +15,8 @@ namespace Wabbajack
|
||||
{
|
||||
public class VortexCompilerVM : ViewModel, ISubCompilerVM
|
||||
{
|
||||
public CompilerVM Parent { get; }
|
||||
|
||||
private readonly VortexCompilationSettings _settings;
|
||||
|
||||
public IReactiveCommand BeginCommand { get; }
|
||||
@ -53,44 +56,74 @@ namespace Wabbajack
|
||||
|
||||
public VortexCompilerVM(CompilerVM parent)
|
||||
{
|
||||
Parent = parent;
|
||||
GameLocation = new FilePickerVM()
|
||||
{
|
||||
ExistCheckOption = FilePickerVM.ExistCheckOptions.On,
|
||||
ExistCheckOption = FilePickerVM.CheckOptions.On,
|
||||
PathType = FilePickerVM.PathTypeOptions.Folder,
|
||||
PromptTitle = "Select Game Folder Location"
|
||||
};
|
||||
DownloadsLocation = new FilePickerVM()
|
||||
{
|
||||
ExistCheckOption = FilePickerVM.ExistCheckOptions.On,
|
||||
ExistCheckOption = FilePickerVM.CheckOptions.On,
|
||||
PathType = FilePickerVM.PathTypeOptions.Folder,
|
||||
PromptTitle = "Select Downloads Folder"
|
||||
};
|
||||
StagingLocation = new FilePickerVM()
|
||||
{
|
||||
ExistCheckOption = FilePickerVM.ExistCheckOptions.On,
|
||||
ExistCheckOption = FilePickerVM.CheckOptions.On,
|
||||
PathType = FilePickerVM.PathTypeOptions.Folder,
|
||||
PromptTitle = "Select Staging Folder"
|
||||
};
|
||||
|
||||
// Load custom ModList settings when game type changes
|
||||
_modListSettings = this.WhenAny(x => x.SelectedGame)
|
||||
.Select(game =>
|
||||
{
|
||||
if (game == null) return null;
|
||||
var gameSettings = _settings.ModlistSettings.TryCreate(game.Game);
|
||||
return new ModlistSettingsEditorVM(gameSettings.ModlistSettings);
|
||||
})
|
||||
// Interject and save old while loading new
|
||||
.Pairwise()
|
||||
.Do(pair =>
|
||||
{
|
||||
var (previous, current) = pair;
|
||||
previous?.Save();
|
||||
current?.Init();
|
||||
})
|
||||
.Select(x => x.Current)
|
||||
// Save to property
|
||||
.ObserveOnGuiThread()
|
||||
.ToProperty(this, nameof(ModlistSettings));
|
||||
|
||||
// Wire start command
|
||||
BeginCommand = ReactiveCommand.CreateFromTask(
|
||||
canExecute: Observable.CombineLatest(
|
||||
this.WhenAny(x => x.GameLocation.InError),
|
||||
this.WhenAny(x => x.DownloadsLocation.InError),
|
||||
this.WhenAny(x => x.StagingLocation.InError),
|
||||
(g, d, s) => !g && !d && !s)
|
||||
this.WhenAny(x => x.ModlistSettings)
|
||||
.Select(x => x?.InError ?? Observable.Return(false))
|
||||
.Switch(),
|
||||
(g, d, s, ml) => !g && !d && !s && !ml)
|
||||
.ObserveOnGuiThread(),
|
||||
execute: async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
string outputFile = $"{ModlistSettings.ModListName}{ExtensionManager.Extension}";
|
||||
if (!string.IsNullOrWhiteSpace(parent.OutputLocation.TargetPath))
|
||||
{
|
||||
outputFile = Path.Combine(parent.OutputLocation.TargetPath, outputFile);
|
||||
}
|
||||
ActiveCompilation = new VortexCompiler(
|
||||
game: SelectedGame.Game,
|
||||
gamePath: GameLocation.TargetPath,
|
||||
vortexFolder: VortexCompiler.TypicalVortexFolder(),
|
||||
downloadsFolder: DownloadsLocation.TargetPath,
|
||||
stagingFolder: StagingLocation.TargetPath,
|
||||
outputFile: $"{ModlistSettings.ModListName}{ExtensionManager.Extension}")
|
||||
outputFile: outputFile)
|
||||
{
|
||||
ModListName = ModlistSettings.ModListName,
|
||||
ModListAuthor = ModlistSettings.AuthorText,
|
||||
@ -169,26 +202,6 @@ namespace Wabbajack
|
||||
})
|
||||
.DisposeWith(CompositeDisposable);
|
||||
|
||||
// Load custom ModList settings when game type changes
|
||||
_modListSettings = this.WhenAny(x => x.SelectedGame)
|
||||
.Select(game =>
|
||||
{
|
||||
var gameSettings = _settings.ModlistSettings.TryCreate(game.Game);
|
||||
return new ModlistSettingsEditorVM(gameSettings.ModlistSettings);
|
||||
})
|
||||
// Interject and save old while loading new
|
||||
.Pairwise()
|
||||
.Do(pair =>
|
||||
{
|
||||
var (previous, current) = pair;
|
||||
previous?.Save();
|
||||
current?.Init();
|
||||
})
|
||||
.Select(x => x.Current)
|
||||
// Save to property
|
||||
.ObserveOnGuiThread()
|
||||
.ToProperty(this, nameof(ModlistSettings));
|
||||
|
||||
// Find game commands
|
||||
FindGameInSteamCommand = ReactiveCommand.Create(SetGameToSteamLocation);
|
||||
FindGameInGogCommand = ReactiveCommand.Create(SetGameToGogLocation);
|
||||
|
@ -17,5 +17,6 @@ namespace Wabbajack
|
||||
void Unload();
|
||||
bool SupportsAfterInstallNavigation { get; }
|
||||
void AfterInstallNavigation();
|
||||
int ConfigVisualVerticalOffset { get; }
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
using Wabbajack.Common.StatusFeed;
|
||||
using System.Reactive;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
@ -46,7 +47,7 @@ namespace Wabbajack
|
||||
public bool Installing => _installing.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Tracks whether to show the installing pane
|
||||
/// Tracks whether installation has begun
|
||||
/// </summary>
|
||||
[Reactive]
|
||||
public bool InstallingMode { get; set; }
|
||||
@ -72,7 +73,7 @@ namespace Wabbajack
|
||||
private readonly ObservableAsPropertyHelper<float> _percentCompleted;
|
||||
public float PercentCompleted => _percentCompleted.Value;
|
||||
|
||||
public ObservableCollectionExtended<CPUStatus> StatusList { get; } = new ObservableCollectionExtended<CPUStatus>();
|
||||
public ObservableCollectionExtended<CPUDisplayVM> StatusList { get; } = new ObservableCollectionExtended<CPUDisplayVM>();
|
||||
public ObservableCollectionExtended<IStatusMessage> Log => MWVM.Log;
|
||||
|
||||
private readonly ObservableAsPropertyHelper<ModManager?> _TargetManager;
|
||||
@ -109,7 +110,7 @@ namespace Wabbajack
|
||||
|
||||
ModListLocation = new FilePickerVM()
|
||||
{
|
||||
ExistCheckOption = FilePickerVM.ExistCheckOptions.On,
|
||||
ExistCheckOption = FilePickerVM.CheckOptions.On,
|
||||
PathType = FilePickerVM.PathTypeOptions.File,
|
||||
PromptTitle = "Select a modlist to install"
|
||||
};
|
||||
@ -179,21 +180,35 @@ namespace Wabbajack
|
||||
});
|
||||
|
||||
BackCommand = ReactiveCommand.Create(
|
||||
execute: () => mainWindowVM.ActivePane = mainWindowVM.ModeSelectionVM,
|
||||
execute: () =>
|
||||
{
|
||||
InstallingMode = false;
|
||||
mainWindowVM.ActivePane = mainWindowVM.ModeSelectionVM;
|
||||
},
|
||||
canExecute: this.WhenAny(x => x.Installing)
|
||||
.Select(x => !x));
|
||||
|
||||
_Completed = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.Installing),
|
||||
this.WhenAny(x => x.InstallingMode),
|
||||
resultSelector: (installing, installingMode) =>
|
||||
{
|
||||
return installingMode && !installing;
|
||||
})
|
||||
.ToProperty(this, nameof(Completed));
|
||||
|
||||
_percentCompleted = this.WhenAny(x => x.Installer.ActiveInstallation)
|
||||
.StartWith(default(AInstaller))
|
||||
.Pairwise()
|
||||
.Select(c =>
|
||||
{
|
||||
if (c.Current == null)
|
||||
.CombineLatest(
|
||||
this.WhenAny(x => x.Completed),
|
||||
(installer, completed) =>
|
||||
{
|
||||
return Observable.Return<float>(c.Previous == null ? 0f : 1f);
|
||||
}
|
||||
return c.Current.PercentCompleted;
|
||||
})
|
||||
if (installer == null)
|
||||
{
|
||||
return Observable.Return<float>(completed ? 1f : 0f);
|
||||
}
|
||||
return installer.PercentCompleted;
|
||||
})
|
||||
.Switch()
|
||||
.Debounce(TimeSpan.FromMilliseconds(25))
|
||||
.ToProperty(this, nameof(PercentCompleted));
|
||||
@ -205,8 +220,8 @@ namespace Wabbajack
|
||||
_image = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModList.Error),
|
||||
this.WhenAny(x => x.ModList)
|
||||
.SelectMany(x => x?.ImageObservable ?? Observable.Empty<BitmapImage>())
|
||||
.NotNull()
|
||||
.Select(x => x?.ImageObservable ?? Observable.Empty<BitmapImage>())
|
||||
.Switch()
|
||||
.StartWith(WabbajackLogo),
|
||||
this.WhenAny(x => x.Slideshow.Image)
|
||||
.StartWith(default(BitmapImage)),
|
||||
@ -217,7 +232,8 @@ namespace Wabbajack
|
||||
{
|
||||
return WabbajackErrLogo;
|
||||
}
|
||||
return installing ? slideshow : modList;
|
||||
var ret = installing ? slideshow : modList;
|
||||
return ret ?? WabbajackLogo;
|
||||
})
|
||||
.Select<BitmapImage, ImageSource>(x => x)
|
||||
.ToProperty(this, nameof(Image));
|
||||
@ -277,16 +293,26 @@ namespace Wabbajack
|
||||
})
|
||||
.ToProperty(this, nameof(ProgressTitle));
|
||||
|
||||
Dictionary<int, CPUDisplayVM> cpuDisplays = new Dictionary<int, CPUDisplayVM>();
|
||||
// Compile progress updates and populate ObservableCollection
|
||||
this.WhenAny(x => x.Installer.ActiveInstallation)
|
||||
.SelectMany(c => c?.QueueStatus ?? Observable.Empty<CPUStatus>())
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.ToObservableChangeSet(x => x.ID)
|
||||
// Attach start times to incoming CPU items
|
||||
.Scan(
|
||||
new CPUDisplayVM(),
|
||||
(_, cpu) =>
|
||||
{
|
||||
var ret = cpuDisplays.TryCreate(cpu.ID);
|
||||
ret.AbsorbStatus(cpu);
|
||||
return ret;
|
||||
})
|
||||
.ToObservableChangeSet(x => x.Status.ID)
|
||||
.Batch(TimeSpan.FromMilliseconds(250), RxApp.TaskpoolScheduler)
|
||||
.EnsureUniqueChanges()
|
||||
.Filter(i => i.IsWorking)
|
||||
.Filter(i => i.Status.IsWorking && i.Status.ID != WorkQueue.UnassignedCpuId)
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Sort(SortExpressionComparer<CPUStatus>.Ascending(s => s.ID), SortOptimisations.ComparesImmutableValuesOnly)
|
||||
.Sort(SortExpressionComparer<CPUDisplayVM>.Ascending(s => s.StartTime))
|
||||
.Bind(StatusList)
|
||||
.Subscribe()
|
||||
.DisposeWith(CompositeDisposable);
|
||||
@ -317,15 +343,6 @@ namespace Wabbajack
|
||||
.ObserveOnGuiThread()
|
||||
.ToProperty(this, nameof(ActiveGlobalUserIntervention));
|
||||
|
||||
_Completed = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.Installing),
|
||||
this.WhenAny(x => x.InstallingMode),
|
||||
resultSelector: (installing, installingMode) =>
|
||||
{
|
||||
return installingMode && !installing;
|
||||
})
|
||||
.ToProperty(this, nameof(Completed));
|
||||
|
||||
CloseWhenCompleteCommand = ReactiveCommand.Create(
|
||||
canExecute: this.WhenAny(x => x.Completed),
|
||||
execute: () =>
|
||||
|
@ -35,13 +35,15 @@ namespace Wabbajack
|
||||
[Reactive]
|
||||
public bool AutomaticallyOverwrite { get; set; }
|
||||
|
||||
public int ConfigVisualVerticalOffset => 25;
|
||||
|
||||
public MO2InstallerVM(InstallerVM installerVM)
|
||||
{
|
||||
Parent = installerVM;
|
||||
|
||||
Location = new FilePickerVM()
|
||||
{
|
||||
ExistCheckOption = FilePickerVM.ExistCheckOptions.Off,
|
||||
ExistCheckOption = FilePickerVM.CheckOptions.Off,
|
||||
PathType = FilePickerVM.PathTypeOptions.Folder,
|
||||
PromptTitle = "Select Installation Directory",
|
||||
};
|
||||
@ -49,7 +51,7 @@ namespace Wabbajack
|
||||
.Select(x => Utils.IsDirectoryPathValid(x));
|
||||
DownloadLocation = new FilePickerVM()
|
||||
{
|
||||
ExistCheckOption = FilePickerVM.ExistCheckOptions.Off,
|
||||
ExistCheckOption = FilePickerVM.CheckOptions.Off,
|
||||
PathType = FilePickerVM.PathTypeOptions.Folder,
|
||||
PromptTitle = "Select a location for MO2 downloads",
|
||||
};
|
||||
|
@ -31,6 +31,8 @@ namespace Wabbajack
|
||||
|
||||
public bool SupportsAfterInstallNavigation => false;
|
||||
|
||||
public int ConfigVisualVerticalOffset => 0;
|
||||
|
||||
public VortexInstallerVM(InstallerVM installerVM)
|
||||
{
|
||||
Parent = installerVM;
|
||||
|
@ -3,11 +3,13 @@ using DynamicData.Binding;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Common.StatusFeed;
|
||||
@ -38,6 +40,9 @@ namespace Wabbajack
|
||||
public readonly UserInterventionHandlers UserInterventionHandlers;
|
||||
public Dispatcher ViewDispatcher { get; set; }
|
||||
|
||||
public ICommand CopyVersionCommand { get; }
|
||||
public string VersionDisplay { get; }
|
||||
|
||||
public MainWindowVM(MainWindow mainWindow, MainSettings settings)
|
||||
{
|
||||
MainWindow = mainWindow;
|
||||
@ -79,6 +84,22 @@ namespace Wabbajack
|
||||
// Start on mode selection
|
||||
ActivePane = ModeSelectionVM;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
|
||||
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
|
||||
VersionDisplay = $"v{fvi.FileVersion}";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Utils.Error(ex);
|
||||
VersionDisplay = "ERROR";
|
||||
}
|
||||
CopyVersionCommand = ReactiveCommand.Create(() =>
|
||||
{
|
||||
Clipboard.SetText($"Wabbajack {VersionDisplay}\n{ThisAssembly.Git.Sha}");
|
||||
});
|
||||
}
|
||||
|
||||
private static bool IsStartingFromModlist(out string modlistPath)
|
||||
|
@ -68,15 +68,10 @@ namespace Wabbajack
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Select(memStream =>
|
||||
{
|
||||
if (memStream == null) return default(BitmapImage);
|
||||
try
|
||||
{
|
||||
var image = new BitmapImage();
|
||||
image.BeginInit();
|
||||
image.CacheOption = BitmapCacheOption.OnLoad;
|
||||
image.StreamSource = memStream;
|
||||
image.EndInit();
|
||||
image.Freeze();
|
||||
return image;
|
||||
return UIUtils.BitmapImageFromStream(memStream);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -69,13 +69,7 @@ namespace Wabbajack
|
||||
if (memStream == null) return default(BitmapImage);
|
||||
try
|
||||
{
|
||||
var image = new BitmapImage();
|
||||
image.BeginInit();
|
||||
image.CacheOption = BitmapCacheOption.OnLoad;
|
||||
image.StreamSource = memStream;
|
||||
image.EndInit();
|
||||
image.Freeze();
|
||||
return image;
|
||||
return UIUtils.BitmapImageFromStream(memStream);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -28,16 +28,16 @@
|
||||
BorderThickness="0"
|
||||
Foreground="Transparent"
|
||||
Maximum="1"
|
||||
Value="{Binding ProgressPercent, Mode=OneWay}" />
|
||||
Value="{Binding Status.ProgressPercent, Mode=OneWay}" />
|
||||
<mahapps:MetroProgressBar
|
||||
Grid.Column="0"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Foreground="{StaticResource PrimaryVariantBrush}"
|
||||
Maximum="1"
|
||||
Opacity="{Binding ProgressPercent, Mode=OneWay}"
|
||||
Value="{Binding ProgressPercent, Mode=OneWay}" />
|
||||
<TextBlock Grid.Column="0" Text="{Binding Msg}" />
|
||||
Opacity="{Binding Status.ProgressPercent, Mode=OneWay}"
|
||||
Value="{Binding Status.ProgressPercent, Mode=OneWay}" />
|
||||
<TextBlock Grid.Column="0" Text="{Binding Status.Msg}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
|
@ -27,20 +27,20 @@
|
||||
Margin="5,1,-2,1"
|
||||
VerticalContentAlignment="Center"
|
||||
Background="{StaticResource DarkBackgroundBrush}"
|
||||
Text="{Binding TargetPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Visibility="{Binding ShowTextBoxInput}" />
|
||||
Text="{Binding PickerVM.TargetPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
|
||||
Visibility="{Binding PickerVM.ShowTextBoxInput, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
|
||||
<Grid Grid.Column="1" HorizontalAlignment="Right">
|
||||
<Border
|
||||
Margin="3,1,0,1"
|
||||
HorizontalAlignment="Right"
|
||||
Background="{StaticResource WarningBrush}"
|
||||
CornerRadius="3"
|
||||
ToolTip="{Binding ErrorTooltip}">
|
||||
ToolTip="{Binding PickerVM.ErrorTooltip, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Width" Value="25" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding InError}" Value="True">
|
||||
<DataTrigger Binding="{Binding PickerVM.InError, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Value="True">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
@ -79,7 +79,7 @@
|
||||
HorizontalAlignment="Left"
|
||||
Background="{StaticResource TextBoxBackground}"
|
||||
CornerRadius="3">
|
||||
<Button Command="{Binding SetTargetPathCommand}" ToolTip="Set target path">
|
||||
<Button Command="{Binding PickerVM.SetTargetPathCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" ToolTip="Set target path">
|
||||
<icon:PackIconMaterial
|
||||
Width="16"
|
||||
Height="12"
|
||||
|
@ -1,4 +1,7 @@
|
||||
using System.Windows.Controls;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using Wabbajack.Lib;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
@ -7,6 +10,16 @@ namespace Wabbajack
|
||||
/// </summary>
|
||||
public partial class FilePicker : UserControl
|
||||
{
|
||||
// This exists, as utilizing the datacontext directly seemed to bug out the exit animations
|
||||
// "Bouncing" off this property seems to fix it, though. Could perhaps be done other ways.
|
||||
public FilePickerVM PickerVM
|
||||
{
|
||||
get => (FilePickerVM)GetValue(PickerVMProperty);
|
||||
set => SetValue(PickerVMProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty PickerVMProperty = DependencyProperty.Register(nameof(PickerVM), typeof(FilePickerVM), typeof(FilePicker),
|
||||
new FrameworkPropertyMetadata(default(FilePickerVM)));
|
||||
|
||||
public FilePicker()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
139
Wabbajack/Views/Compilers/CompilationCompleteView.xaml
Normal file
139
Wabbajack/Views/Compilers/CompilationCompleteView.xaml
Normal file
@ -0,0 +1,139 @@
|
||||
<UserControl
|
||||
x:Class="Wabbajack.CompilationCompleteView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:icon="http://metro.mahapps.com/winfx/xaml/iconpacks"
|
||||
xmlns:local="clr-namespace:Wabbajack"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<Border ClipToBounds="True" Style="{StaticResource AttentionBorderStyle}">
|
||||
<Grid Margin="5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="3*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Bottom"
|
||||
FontFamily="Lucida Sans"
|
||||
FontSize="22"
|
||||
FontWeight="Black"
|
||||
Text="Compilation Complete">
|
||||
<TextBlock.Effect>
|
||||
<DropShadowEffect BlurRadius="25" Opacity="0.5" />
|
||||
</TextBlock.Effect>
|
||||
</TextBlock>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Button
|
||||
Grid.Row="0"
|
||||
Width="55"
|
||||
Height="55"
|
||||
Command="{Binding BackCommand}"
|
||||
Style="{StaticResource CircleButtonStyle}">
|
||||
<icon:PackIconMaterial
|
||||
Width="28"
|
||||
Height="28"
|
||||
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
|
||||
Kind="ArrowLeft" />
|
||||
</Button>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="0,10,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Text="Main Menu" />
|
||||
</Grid>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{Binding CompilerSupportsAfterCompileNavigation, Converter={StaticResource bool2VisibilityConverter}}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Button
|
||||
Width="55"
|
||||
Height="55"
|
||||
Command="{Binding GoToModlistCommand}"
|
||||
Style="{StaticResource CircleButtonStyle}">
|
||||
<icon:PackIconMaterial
|
||||
Width="25"
|
||||
Height="25"
|
||||
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
|
||||
Kind="FolderMove" />
|
||||
</Button>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="0,10,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Text="Go To Modlist" />
|
||||
</Grid>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Background="Transparent">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<!--<Button
|
||||
Width="55"
|
||||
Height="55"
|
||||
Background="{StaticResource PrimaryVariantBrush}"
|
||||
BorderBrush="{StaticResource PrimaryVariantBrush}"
|
||||
IsHitTestVisible="False"
|
||||
Style="{StaticResource CircleButtonStyle}">
|
||||
<Button.Effect>
|
||||
<BlurEffect Radius="35" />
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
<Button
|
||||
Width="55"
|
||||
Height="55"
|
||||
Background="{StaticResource SecondaryBrush}"
|
||||
BorderBrush="{StaticResource SecondaryBrush}"
|
||||
IsHitTestVisible="False"
|
||||
Style="{StaticResource CircleButtonStyle}">
|
||||
<Button.Effect>
|
||||
<BlurEffect Radius="15" />
|
||||
</Button.Effect>
|
||||
</Button>-->
|
||||
<Button
|
||||
Width="55"
|
||||
Height="55"
|
||||
Command="{Binding CloseWhenCompleteCommand}"
|
||||
Style="{StaticResource CircleButtonStyle}">
|
||||
<icon:PackIconMaterial
|
||||
Width="30"
|
||||
Height="30"
|
||||
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
|
||||
Kind="Check" />
|
||||
</Button>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="0,10,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Text="Close" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</UserControl>
|
28
Wabbajack/Views/Compilers/CompilationCompleteView.xaml.cs
Normal file
28
Wabbajack/Views/Compilers/CompilationCompleteView.xaml.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for CompilationCompleteView.xaml
|
||||
/// </summary>
|
||||
public partial class CompilationCompleteView : UserControl
|
||||
{
|
||||
public CompilationCompleteView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
@ -143,7 +143,7 @@
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock Margin="{StaticResource TitleMargin}" Text="Image" />
|
||||
<local:FilePicker
|
||||
DataContext="{Binding ImagePath}"
|
||||
PickerVM="{Binding ImagePath}"
|
||||
Style="{StaticResource PickerStyle}"
|
||||
ToolTip="Path to an image to display for the modlist." />
|
||||
<TextBlock Margin="{StaticResource TitleMargin}" Text="Website" />
|
||||
@ -153,7 +153,7 @@
|
||||
Text="Readme Path"
|
||||
ToolTip="Path to a readme file." />
|
||||
<local:FilePicker
|
||||
DataContext="{Binding ReadMeText}"
|
||||
PickerVM="{Binding ReadMeText}"
|
||||
Style="{StaticResource PickerStyle}"
|
||||
ToolTip="Path to a readme file." />
|
||||
</StackPanel>
|
||||
@ -174,7 +174,7 @@
|
||||
Margin="35,0,35,0"
|
||||
VerticalAlignment="Center"
|
||||
ClipToBounds="False"
|
||||
Visibility="{Binding Compiling, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}">
|
||||
Visibility="{Binding CompilationMode, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
@ -240,11 +240,11 @@
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="5"
|
||||
Margin="5"
|
||||
Visibility="{Binding Compiling, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Hidden}">
|
||||
Visibility="{Binding CompilationMode, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Hidden}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="3*" />
|
||||
<ColumnDefinition Width="4*" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="2*" />
|
||||
<ColumnDefinition Width="3*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<local:LogView Grid.Column="0" ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" />
|
||||
<local:CpuView
|
||||
@ -259,6 +259,7 @@
|
||||
<local:ConfirmationInterventionView DataContext="{Binding ActiveGlobalUserIntervention}" Visibility="{Binding ActiveGlobalUserIntervention, Converter={StaticResource IsTypeVisibilityConverter}, ConverterParameter={x:Type common:ConfirmationIntervention}}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<local:CompilationCompleteView Grid.Column="2" Visibility="{Binding Completed, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Collapsed}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
@ -34,7 +34,7 @@
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding ModlistLocation}"
|
||||
PickerVM="{Binding ModListLocation}"
|
||||
FontSize="14"
|
||||
ToolTip="The MO2 modlist.txt file you want to use as your source" />
|
||||
<TextBlock
|
||||
@ -51,7 +51,7 @@
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding DownloadLocation}"
|
||||
PickerVM="{Binding DownloadLocation}"
|
||||
FontSize="14"
|
||||
ToolTip="The folder where MO2 downloads your mods." />
|
||||
<TextBlock
|
||||
@ -68,7 +68,7 @@
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding OutputLocation}"
|
||||
PickerVM="{Binding Parent.OutputLocation}"
|
||||
FontSize="14"
|
||||
ToolTip="The folder to place the resulting modlist.wabbajack file" />
|
||||
</Grid>
|
||||
|
@ -20,13 +20,12 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="40" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
@ -35,7 +34,7 @@
|
||||
TextAlignment="Center"
|
||||
ToolTip="The game you wish to target" />
|
||||
<ComboBox
|
||||
Grid.Row="1"
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
@ -51,7 +50,7 @@
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
@ -60,15 +59,15 @@
|
||||
TextAlignment="Center"
|
||||
ToolTip="The install folder for the game" />
|
||||
<local:FilePicker
|
||||
Grid.Row="2"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding GameLocation}"
|
||||
PickerVM="{Binding GameLocation}"
|
||||
FontSize="14"
|
||||
ToolTip="The install folder for the game" />
|
||||
<Grid
|
||||
Grid.Row="3"
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Height="28"
|
||||
HorizontalAlignment="Left"
|
||||
@ -97,36 +96,53 @@
|
||||
</Grid>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Row="0"
|
||||
Grid.Column="4"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="Download Location"
|
||||
TextAlignment="Center"
|
||||
ToolTip="The folder to downloads your mods" />
|
||||
ToolTip="The folder to download your mods" />
|
||||
<local:FilePicker
|
||||
Grid.Row="1"
|
||||
Grid.Row="0"
|
||||
Grid.Column="6"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding DownloadsLocation}"
|
||||
PickerVM="{Binding DownloadsLocation}"
|
||||
FontSize="14"
|
||||
ToolTip="The folder to downloads your mods" />
|
||||
ToolTip="The folder to download your mods" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Row="1"
|
||||
Grid.Column="4"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="Staging Location"
|
||||
TextAlignment="Center" />
|
||||
<local:FilePicker
|
||||
Grid.Row="1"
|
||||
Grid.Column="6"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
PickerVM="{Binding StagingLocation}"
|
||||
FontSize="14" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="4"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="Output Location"
|
||||
TextAlignment="Center"
|
||||
ToolTip="The folder to place the resulting modlist.wabbajack file" />
|
||||
<local:FilePicker
|
||||
Grid.Row="2"
|
||||
Grid.Column="6"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding StagingLocation}"
|
||||
FontSize="14" />
|
||||
PickerVM="{Binding Parent.OutputLocation}"
|
||||
FontSize="14"
|
||||
ToolTip="The folder to place the resulting modlist.wabbajack file" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
@ -9,7 +9,7 @@
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<Border Style="{StaticResource AttentionBorderStyle}" ClipToBounds="True">
|
||||
<Border ClipToBounds="True" Style="{StaticResource AttentionBorderStyle}">
|
||||
<Grid Margin="5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
@ -19,11 +19,12 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Grid.ColumnSpan="4"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Bottom"
|
||||
FontFamily="Lucida Sans"
|
||||
@ -44,13 +45,13 @@
|
||||
</Grid.RowDefinitions>
|
||||
<Button
|
||||
Grid.Row="0"
|
||||
Width="55"
|
||||
Height="55"
|
||||
Width="50"
|
||||
Height="50"
|
||||
Command="{Binding BackCommand}"
|
||||
Style="{StaticResource CircleButtonStyle}">
|
||||
<icon:PackIconMaterial
|
||||
Width="28"
|
||||
Height="28"
|
||||
Width="25"
|
||||
Height="25"
|
||||
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
|
||||
Kind="ArrowLeft" />
|
||||
</Button>
|
||||
@ -70,13 +71,13 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Button
|
||||
Width="55"
|
||||
Height="55"
|
||||
Width="50"
|
||||
Height="50"
|
||||
Command="{Binding GoToInstallCommand}"
|
||||
Style="{StaticResource CircleButtonStyle}">
|
||||
<icon:PackIconMaterial
|
||||
Width="25"
|
||||
Height="25"
|
||||
Width="23"
|
||||
Height="23"
|
||||
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
|
||||
Kind="FolderMove" />
|
||||
</Button>
|
||||
@ -84,7 +85,7 @@
|
||||
Grid.Row="1"
|
||||
Margin="0,10,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Text="Open Install Folder" />
|
||||
Text="Install Folder" />
|
||||
</Grid>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
@ -95,36 +96,40 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<!--<Button
|
||||
Width="55"
|
||||
Height="55"
|
||||
Background="{StaticResource PrimaryVariantBrush}"
|
||||
BorderBrush="{StaticResource PrimaryVariantBrush}"
|
||||
IsHitTestVisible="False"
|
||||
Style="{StaticResource CircleButtonStyle}">
|
||||
<Button.Effect>
|
||||
<BlurEffect Radius="35" />
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
<Button
|
||||
Width="55"
|
||||
Height="55"
|
||||
Background="{StaticResource SecondaryBrush}"
|
||||
BorderBrush="{StaticResource SecondaryBrush}"
|
||||
IsHitTestVisible="False"
|
||||
Style="{StaticResource CircleButtonStyle}">
|
||||
<Button.Effect>
|
||||
<BlurEffect Radius="15" />
|
||||
</Button.Effect>
|
||||
</Button>-->
|
||||
<Button
|
||||
Width="55"
|
||||
Height="55"
|
||||
Width="50"
|
||||
Height="50"
|
||||
Command="{Binding OpenReadmeCommand}"
|
||||
Style="{StaticResource CircleButtonStyle}">
|
||||
<icon:PackIconFontAwesome
|
||||
Width="25"
|
||||
Height="25"
|
||||
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
|
||||
Kind="ReadmeBrands" />
|
||||
</Button>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="0,10,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Text="Readme" />
|
||||
</Grid>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Grid.Column="3"
|
||||
VerticalAlignment="Center"
|
||||
Background="Transparent">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Button
|
||||
Width="50"
|
||||
Height="50"
|
||||
Command="{Binding CloseWhenCompleteCommand}"
|
||||
Style="{StaticResource CircleButtonStyle}">
|
||||
<icon:PackIconMaterial
|
||||
Width="30"
|
||||
Height="30"
|
||||
Width="25"
|
||||
Height="25"
|
||||
Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
|
||||
Kind="Check" />
|
||||
</Button>
|
||||
|
@ -256,23 +256,74 @@
|
||||
Grid.Row="0"
|
||||
Margin="30,5"
|
||||
Command="{Binding OpenReadmeCommand}"
|
||||
Content="Readme"
|
||||
FontSize="20"
|
||||
ToolTip="Open the readme for the modlist" />
|
||||
ToolTip="Open the readme for the modlist">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="30" />
|
||||
<ColumnDefinition Width="82" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<icon:PackIconFontAwesome
|
||||
Grid.Column="0"
|
||||
Width="30"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
Kind="ReadmeBrands" />
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="10,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Readme" />
|
||||
</Grid>
|
||||
</Button>
|
||||
<Button
|
||||
Grid.Row="1"
|
||||
Margin="30,5"
|
||||
Command="{Binding VisitWebsiteCommand}"
|
||||
Content="Website"
|
||||
FontSize="20"
|
||||
ToolTip="Open the webpage for the modlist" />
|
||||
ToolTip="Open the webpage for the modlist">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="30" />
|
||||
<ColumnDefinition Width="82" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<icon:PackIconMaterial
|
||||
Grid.Column="0"
|
||||
Width="30"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
Kind="Web" />
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="10,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Website" />
|
||||
</Grid>
|
||||
</Button>
|
||||
<Button
|
||||
Grid.Row="2"
|
||||
Margin="30,5"
|
||||
Command="{Binding ShowReportCommand}"
|
||||
Content="Manifest"
|
||||
FontSize="20"
|
||||
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.ColumnDefinitions>
|
||||
<ColumnDefinition Width="30" />
|
||||
<ColumnDefinition Width="82" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<icon:PackIconOcticons
|
||||
Grid.Column="0"
|
||||
Width="30"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
Kind="Checklist" />
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="10,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Manifest" />
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="InstallationConfigurationView"
|
||||
@ -283,15 +334,44 @@
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ScrollViewer
|
||||
<Grid
|
||||
Grid.Column="0"
|
||||
Margin="5"
|
||||
VerticalAlignment="Center"
|
||||
Background="Transparent"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
Visibility="{Binding InstallingMode, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}">
|
||||
<ContentPresenter
|
||||
Margin="0"
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="5" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" MinWidth="120" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Rectangle Grid.Row="0" Height="{Binding Installer.ConfigVisualVerticalOffset, Mode=OneWay}" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="Target Modlist"
|
||||
TextAlignment="Center" />
|
||||
<local:FilePicker
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
PickerVM="{Binding ModListLocation}" />
|
||||
<ContentPresenter
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
VerticalAlignment="Top"
|
||||
Content="{Binding Installer}">
|
||||
<ContentPresenter.Resources>
|
||||
<DataTemplate DataType="{x:Type local:MO2InstallerVM}">
|
||||
@ -302,7 +382,7 @@
|
||||
</DataTemplate>
|
||||
</ContentPresenter.Resources>
|
||||
</ContentPresenter>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
<local:BeginButton
|
||||
Grid.Column="2"
|
||||
Margin="0,0,25,0"
|
||||
@ -316,9 +396,9 @@
|
||||
Margin="5,0,5,5"
|
||||
Visibility="{Binding InstallingMode, Converter={StaticResource bool2VisibilityConverter}, FallbackValue=Hidden}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="3*" />
|
||||
<ColumnDefinition Width="4*" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="2*" />
|
||||
<ColumnDefinition Width="3*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<local:LogView Grid.Column="0" ProgressPercent="{Binding PercentCompleted, Mode=OneWay}" />
|
||||
<local:CpuView
|
||||
|
@ -16,29 +16,12 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="20" />
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="20" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="Target Modlist"
|
||||
TextAlignment="Center" />
|
||||
<local:FilePicker
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding Parent.ModListLocation}"
|
||||
FontSize="14" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
@ -46,14 +29,14 @@
|
||||
Text="Installation Location"
|
||||
TextAlignment="Center" />
|
||||
<local:FilePicker
|
||||
Grid.Row="2"
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding Location}"
|
||||
FontSize="14" />
|
||||
FontSize="14"
|
||||
PickerVM="{Binding Location}" />
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
@ -61,14 +44,14 @@
|
||||
Text="Download Location"
|
||||
TextAlignment="Center" />
|
||||
<local:FilePicker
|
||||
Grid.Row="3"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding DownloadLocation}"
|
||||
FontSize="14" />
|
||||
FontSize="14"
|
||||
PickerVM="{Binding DownloadLocation}" />
|
||||
<CheckBox
|
||||
Grid.Row="4"
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Right"
|
||||
Content="Overwrite Installation"
|
||||
|
@ -9,28 +9,5 @@
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" MinWidth="120" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="40" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="Target Modlist"
|
||||
TextAlignment="Center" />
|
||||
<local:FilePicker
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DataContext="{Binding Parent.ModListLocation}"
|
||||
FontSize="14" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
@ -3,6 +3,7 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:icon="http://metro.mahapps.com/winfx/xaml/iconpacks"
|
||||
xmlns:local="clr-namespace:Wabbajack"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
@ -12,23 +13,39 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.Resources>
|
||||
<Style TargetType="Image">
|
||||
<Setter Property="Margin" Value="5" />
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
<Image
|
||||
Name="GitHub"
|
||||
<Button
|
||||
Grid.Column="0"
|
||||
MouseLeftButtonDown="GitHub_MouseLeftButtonDown" Source="../Resources/Icons/github.png"/>
|
||||
<Image
|
||||
Name="Patreon"
|
||||
Width="35"
|
||||
Height="35"
|
||||
Click="GitHub_Click"
|
||||
Style="{StaticResource IconBareButtonStyle}">
|
||||
<icon:PackIconMaterial
|
||||
Width="25"
|
||||
Height="25"
|
||||
Kind="GithubCircle" />
|
||||
</Button>
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
MouseLeftButtonDown="Patreon_MouseLeftButtonDown" Source="../Resources/Icons/patreon.png"/>
|
||||
<Image
|
||||
Name="Discord"
|
||||
Width="35"
|
||||
Height="35"
|
||||
Margin="4,0,0,0"
|
||||
Click="Patreon_Click"
|
||||
Style="{StaticResource IconBareButtonStyle}">
|
||||
<icon:PackIconMaterial
|
||||
Width="25"
|
||||
Height="25"
|
||||
Kind="Patreon" />
|
||||
</Button>
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
MouseLeftButtonDown="Discord_MouseLeftButtonDown"
|
||||
Source="../Resources/Icons/discord.png" />
|
||||
Width="35"
|
||||
Height="35"
|
||||
Click="Discord_Click"
|
||||
Style="{StaticResource IconBareButtonStyle}">
|
||||
<icon:PackIconMaterial
|
||||
Width="25"
|
||||
Height="25"
|
||||
Kind="Discord" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
@ -26,19 +26,19 @@ namespace Wabbajack
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void GitHub_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
private void GitHub_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start("https://github.com/wabbajack-tools/wabbajack");
|
||||
}
|
||||
|
||||
private void Patreon_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
private void Discord_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start("https://discord.gg/wabbajack");
|
||||
}
|
||||
|
||||
private void Patreon_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Process.Start("https://www.patreon.com/user?u=11907933");
|
||||
}
|
||||
|
||||
private void Discord_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
Process.Start("https://discord.gg/zgbrkmA");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,4 +38,16 @@
|
||||
</DataTemplate>
|
||||
</ContentPresenter.Resources>
|
||||
</ContentPresenter>
|
||||
|
||||
<mahapps:MetroWindow.RightWindowCommands>
|
||||
<mahapps:WindowCommands>
|
||||
<Button Command="{Binding CopyVersionCommand}" Content="{Binding VersionDisplay}">
|
||||
<Button.ToolTip>
|
||||
<TextBlock>
|
||||
Wabbajack Version<LineBreak />
|
||||
Click to copy to clipboard</TextBlock>
|
||||
</Button.ToolTip>
|
||||
</Button>
|
||||
</mahapps:WindowCommands>
|
||||
</mahapps:MetroWindow.RightWindowCommands>
|
||||
</mahapps:MetroWindow>
|
||||
|
@ -222,24 +222,6 @@
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.Resources>
|
||||
<Style
|
||||
x:Key="ModlistButtonStyle"
|
||||
BasedOn="{StaticResource IconCircleButtonStyle}"
|
||||
TargetType="Button">
|
||||
<Style.Triggers>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsMouseOver, ElementName=ModListTile}" Value="True" />
|
||||
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="True" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<MultiDataTrigger.Setters>
|
||||
<Setter Property="Foreground" Value="{StaticResource IntenseComplementaryBrush}" />
|
||||
</MultiDataTrigger.Setters>
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
<Button
|
||||
Grid.Row="0"
|
||||
Width="40"
|
||||
@ -247,7 +229,7 @@
|
||||
Margin="5,0"
|
||||
VerticalAlignment="Bottom"
|
||||
Command="{Binding OpenWebsiteCommand}"
|
||||
Style="{StaticResource ModlistButtonStyle}">
|
||||
Style="{StaticResource IconBareButtonStyle}">
|
||||
<iconPacks:Material
|
||||
Width="20"
|
||||
Height="20"
|
||||
@ -262,7 +244,7 @@
|
||||
VerticalAlignment="Top"
|
||||
Command="{Binding ExecuteCommand}">
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource ModlistButtonStyle}" TargetType="Button">
|
||||
<Style BasedOn="{StaticResource IconBareButtonStyle}" TargetType="Button">
|
||||
<Setter Property="Content">
|
||||
<Setter.Value>
|
||||
<iconPacks:Material
|
||||
|
@ -505,5 +505,12 @@
|
||||
</Grid>
|
||||
</Button>
|
||||
</Grid>
|
||||
<local:LinksView
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="0"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
@ -173,6 +173,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="Converters\IsTypeVisibilityConverter.cs" />
|
||||
<Compile Include="View Models\CPUDisplayVM.cs" />
|
||||
<Compile Include="Views\Compilers\CompilationCompleteView.xaml.cs">
|
||||
<DependentUpon>CompilationCompleteView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Views\Installers\InstallationCompleteView.xaml.cs">
|
||||
<DependentUpon>InstallationCompleteView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@ -228,19 +232,16 @@
|
||||
<Compile Include="Views\Common\DetailImageView.xaml.cs">
|
||||
<DependentUpon>DetailImageView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Extensions\EnumerableExt.cs" />
|
||||
<Compile Include="Views\Common\TopProgressView.xaml.cs">
|
||||
<DependentUpon>TopProgressView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="View Models\FilePickerVM.cs" />
|
||||
<Compile Include="View Models\ModListVM.cs" />
|
||||
<Compile Include="View Models\ModVM.cs" />
|
||||
<Compile Include="Views\Compilers\CompilerView.xaml.cs">
|
||||
<DependentUpon>CompilerView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Converters\IsNotNullVisibilityConverter.cs" />
|
||||
<Compile Include="Extensions\ReactiveUIExt.cs" />
|
||||
<Compile Include="View Models\ModeSelectionVM.cs" />
|
||||
<Compile Include="Views\Common\FilePicker.xaml.cs">
|
||||
<DependentUpon>FilePicker.xaml</DependentUpon>
|
||||
@ -269,6 +270,10 @@
|
||||
<Compile Include="Views\WebBrowserView.xaml.cs">
|
||||
<DependentUpon>WebBrowserView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Page Include="Views\Compilers\CompilationCompleteView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Views\Installers\InstallationCompleteView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@ -437,12 +442,6 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\banner_small.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Icons\discord.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Icons\next.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Banner_Dark.png" />
|
||||
</ItemGroup>
|
||||
@ -541,10 +540,6 @@
|
||||
<Resource Include="Resources\Icons\gog.png" />
|
||||
<Resource Include="Resources\Icons\steam.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Icons\github.png" />
|
||||
<Resource Include="Resources\Icons\patreon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Wabba_Mouth_No_Text.png" />
|
||||
</ItemGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user