Merge branch 'VM-split-and-styling'
BIN
Branding/PNGs/Wabba_Mouth.png
Normal file
After Width: | Height: | Size: 272 KiB |
BIN
Branding/Project files/Wabba_Mouth.psd
Normal file
24
Wabbajack.Lib/Extensions/TaskExt.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
public static class TaskExt
|
||||
{
|
||||
public static async void FireAndForget(this Task task, Action<Exception> onException = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await task.ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
when (onException != null)
|
||||
{
|
||||
onException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -62,15 +62,36 @@ namespace Wabbajack.Lib
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BitmapImage BitmapImageFromResource(string name)
|
||||
public static BitmapImage BitmapImageFromResource(string name) => BitmapImageFromStream(Utils.GetResourceStream(name));
|
||||
|
||||
public static BitmapImage BitmapImageFromStream(Stream stream)
|
||||
{
|
||||
var img = new BitmapImage();
|
||||
img.BeginInit();
|
||||
img.StreamSource = Utils.GetResourceStream(name);
|
||||
img.StreamSource = stream;
|
||||
img.EndInit();
|
||||
return img;
|
||||
}
|
||||
|
||||
public static bool TryGetBitmapImageFromFile(string path, out BitmapImage bitmapImage)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
bitmapImage = default;
|
||||
return false;
|
||||
}
|
||||
bitmapImage = new BitmapImage(new Uri(path, UriKind.RelativeOrAbsolute));
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
bitmapImage = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static string OpenFileDialog(string filter)
|
||||
{
|
||||
OpenFileDialog ofd = new OpenFileDialog();
|
||||
|
@ -160,6 +160,7 @@
|
||||
<Compile Include="Downloaders\MEGADownloader.cs" />
|
||||
<Compile Include="Downloaders\ModDBDownloader.cs" />
|
||||
<Compile Include="Downloaders\NexusDownloader.cs" />
|
||||
<Compile Include="Extensions\TaskExt.cs" />
|
||||
<Compile Include="Installer.cs" />
|
||||
<Compile Include="ModListRegistry\ModListMetadata.cs" />
|
||||
<Compile Include="NexusApi\Dtos.cs" />
|
||||
|
@ -6,6 +6,9 @@
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
|
||||
<ResourceDictionary Source="Themes\Styles.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
|
@ -13,22 +13,14 @@ namespace Wabbajack
|
||||
{
|
||||
public App()
|
||||
{
|
||||
/*
|
||||
Utils.Log($"Wabbajack Build - {ThisAssembly.Git.Sha}");
|
||||
SetupHandlers();
|
||||
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
if (args.Length > 1)
|
||||
// Wire any unhandled crashing exceptions to log before exiting
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
|
||||
{
|
||||
Utils.SetLoggerFn(f => { });
|
||||
WorkQueue.Init((a, b, c) => { }, (a, b) => { });
|
||||
var updater = new CheckForUpdates(args[1]);
|
||||
if (updater.FindOutdatedMods())
|
||||
{
|
||||
Environment.Exit(0);
|
||||
}
|
||||
Environment.Exit(1);
|
||||
}*/
|
||||
// Don't do any special logging side effects
|
||||
Utils.SetLoggerFn((s) => { });
|
||||
Utils.Log("Uncaught error:");
|
||||
Utils.Log(((Exception)e.ExceptionObject).ExceptionToString());
|
||||
};
|
||||
|
||||
var appPath = Assembly.GetExecutingAssembly().Location;
|
||||
if (!ExtensionManager.IsAssociated() || ExtensionManager.NeedsUpdating(appPath))
|
||||
@ -37,22 +29,11 @@ namespace Wabbajack
|
||||
}
|
||||
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
StartupUri = new Uri("UI/ModeSelectionWindow.xaml", UriKind.Relative);
|
||||
StartupUri = new Uri("Views/ModeSelectionWindow.xaml", UriKind.Relative);
|
||||
if (args.Length != 3) return;
|
||||
if (!args[1].Contains("-i")) return;
|
||||
// modlists gets loaded using a shell command
|
||||
StartupUri = new Uri("UI/MainWindow.xaml", UriKind.Relative);
|
||||
}
|
||||
|
||||
private void SetupHandlers()
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += AppHandler;
|
||||
}
|
||||
|
||||
private void AppHandler(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
Utils.Log("Uncaught error:");
|
||||
Utils.Log(((Exception)e.ExceptionObject).ExceptionToString());
|
||||
StartupUri = new Uri("Views/MainWindow.xaml", UriKind.Relative);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,427 +0,0 @@
|
||||
using Syroot.Windows.IO;
|
||||
using System;
|
||||
using ReactiveUI;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Threading;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib.Downloaders;
|
||||
using Wabbajack.Lib.NexusApi;
|
||||
using Wabbajack.UI;
|
||||
using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
using System.Reactive;
|
||||
using System.Text;
|
||||
using Wabbajack.Lib;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
public class AppState : ViewModel, IDataErrorInfo
|
||||
{
|
||||
public SlideShow Slideshow { get; }
|
||||
|
||||
public readonly string WabbajackVersion = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).FileVersion;
|
||||
|
||||
private string _mo2Folder;
|
||||
|
||||
public readonly BitmapImage _noneImage = UIUtils.BitmapImageFromResource("Wabbajack.UI.none.jpg");
|
||||
|
||||
private readonly Subject<CPUStatus> _statusSubject = new Subject<CPUStatus>();
|
||||
public ObservableCollectionExtended<CPUStatus> Status { get; } = new ObservableCollectionExtended<CPUStatus>();
|
||||
|
||||
private ModList _ModList;
|
||||
public ModList ModList { get => _ModList; private set => this.RaiseAndSetIfChanged(ref _ModList, value); }
|
||||
|
||||
private string _ModListPath;
|
||||
public string ModListPath { get => _ModListPath; private set => this.RaiseAndSetIfChanged(ref _ModListPath, value); }
|
||||
|
||||
private RunMode _Mode;
|
||||
public RunMode Mode { get => _Mode; private set => this.RaiseAndSetIfChanged(ref _Mode, value); }
|
||||
|
||||
private string _ModListName;
|
||||
public string ModListName { get => _ModListName; set => this.RaiseAndSetIfChanged(ref _ModListName, value); }
|
||||
|
||||
private bool _UIReady;
|
||||
public bool UIReady { get => _UIReady; set => this.RaiseAndSetIfChanged(ref _UIReady, value); }
|
||||
|
||||
private string _HTMLReport;
|
||||
public string HTMLReport { get => _HTMLReport; set => this.RaiseAndSetIfChanged(ref _HTMLReport, value); }
|
||||
|
||||
private bool _Installing;
|
||||
public bool Installing { get => _Installing; set => this.RaiseAndSetIfChanged(ref _Installing, value); }
|
||||
|
||||
// Command properties
|
||||
public IReactiveCommand ChangePathCommand { get; }
|
||||
public IReactiveCommand ChangeDownloadPathCommand { get; }
|
||||
public IReactiveCommand BeginCommand { get; }
|
||||
public IReactiveCommand ShowReportCommand { get; }
|
||||
public IReactiveCommand OpenReadmeCommand { get; }
|
||||
public IReactiveCommand OpenModListPropertiesCommand { get; }
|
||||
|
||||
public AppState(RunMode mode)
|
||||
{
|
||||
if (Path.GetDirectoryName(Assembly.GetEntryAssembly().Location.ToLower()) == KnownFolders.Downloads.Path.ToLower())
|
||||
{
|
||||
MessageBox.Show(
|
||||
"Wabbajack is running inside your Downloads folder. This folder is often highly monitored by antivirus software and these can often " +
|
||||
"conflict with the operations Wabbajack needs to perform. Please move this executable outside of your Downloads folder and then restart the app.",
|
||||
"Cannot run inside Downloads",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
Mode = mode;
|
||||
|
||||
// Define commands
|
||||
this.ChangePathCommand = ReactiveCommand.Create(ExecuteChangePath);
|
||||
this.ChangeDownloadPathCommand = ReactiveCommand.Create(ExecuteChangeDownloadPath);
|
||||
this.ShowReportCommand = ReactiveCommand.Create(ShowReport);
|
||||
this.OpenModListPropertiesCommand = ReactiveCommand.Create(
|
||||
execute: OpenModListProperties,
|
||||
canExecute: this.WhenAny(x => x.UIReady)
|
||||
.ObserveOnGuiThread());
|
||||
this.OpenReadmeCommand = ReactiveCommand.Create(
|
||||
execute: this.OpenReadmeWindow,
|
||||
canExecute: this.WhenAny(x => x.ModList)
|
||||
.Select(modList => !string.IsNullOrEmpty(modList?.Readme))
|
||||
.ObserveOnGuiThread());
|
||||
this.BeginCommand = ReactiveCommand.Create(
|
||||
execute: this.ExecuteBegin,
|
||||
canExecute: this.WhenAny(x => x.UIReady)
|
||||
.ObserveOnGuiThread());
|
||||
|
||||
this.Slideshow = new SlideShow(this);
|
||||
|
||||
// Initialize work queue
|
||||
WorkQueue.Init(
|
||||
report_function: (id, msg, progress) => this._statusSubject.OnNext(new CPUStatus() { ID = id, Msg = msg, Progress = progress }),
|
||||
report_queue_size: (max, current) => this.SetQueueSize(max, current));
|
||||
// Compile progress updates and populate ObservableCollection
|
||||
this._statusSubject
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.ToObservableChangeSet(x => x.ID)
|
||||
.Batch(TimeSpan.FromMilliseconds(250))
|
||||
.EnsureUniqueChanges()
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Sort(SortExpressionComparer<CPUStatus>.Ascending(s => s.ID), SortOptimisations.ComparesImmutableValuesOnly)
|
||||
.Bind(this.Status)
|
||||
.Subscribe()
|
||||
.DisposeWith(this.CompositeDisposable);
|
||||
}
|
||||
|
||||
public ObservableCollection<string> Log { get; } = new ObservableCollection<string>();
|
||||
|
||||
private string _Location;
|
||||
public string Location { get => _Location; set => this.RaiseAndSetIfChanged(ref _Location, value); }
|
||||
|
||||
private string _LocationLabel;
|
||||
public string LocationLabel { get => _LocationLabel; set => this.RaiseAndSetIfChanged(ref _LocationLabel, value); }
|
||||
|
||||
private string _DownloadLocation;
|
||||
public string DownloadLocation { get => _DownloadLocation; set => this.RaiseAndSetIfChanged(ref _DownloadLocation, value); }
|
||||
|
||||
private int _queueProgress;
|
||||
public int QueueProgress { get => _queueProgress; set => this.RaiseAndSetIfChanged(ref _queueProgress, value); }
|
||||
|
||||
public string LogFile { get; }
|
||||
|
||||
private void ExecuteChangePath()
|
||||
{
|
||||
switch (this.Mode)
|
||||
{
|
||||
case RunMode.Compile:
|
||||
Location = UIUtils.ShowFolderSelectionDialog("Select Your MO2 profile directory");
|
||||
break;
|
||||
case RunMode.Install:
|
||||
var folder = UIUtils.ShowFolderSelectionDialog("Select Installation directory");
|
||||
if (folder == null) return;
|
||||
Location = folder;
|
||||
if (DownloadLocation == null)
|
||||
{
|
||||
DownloadLocation = Path.Combine(Location, "downloads");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteChangeDownloadPath()
|
||||
{
|
||||
var folder = UIUtils.ShowFolderSelectionDialog("Select a location for MO2 downloads");
|
||||
if (folder != null) DownloadLocation = folder;
|
||||
}
|
||||
|
||||
private void ShowReport()
|
||||
{
|
||||
var file = Path.GetTempFileName() + ".html";
|
||||
File.WriteAllText(file, HTMLReport);
|
||||
Process.Start(file);
|
||||
}
|
||||
|
||||
private ModlistPropertiesWindow modlistPropertiesWindow;
|
||||
public string newImagePath;
|
||||
public string readmePath;
|
||||
public bool ChangedProperties;
|
||||
private void OpenModListProperties()
|
||||
{
|
||||
if (UIReady)
|
||||
{
|
||||
if (modlistPropertiesWindow == null)
|
||||
{
|
||||
modlistPropertiesWindow = new ModlistPropertiesWindow(this);
|
||||
newImagePath = null;
|
||||
ChangedProperties = false;
|
||||
|
||||
}
|
||||
if(!modlistPropertiesWindow.IsClosed)
|
||||
modlistPropertiesWindow.Show();
|
||||
else
|
||||
{
|
||||
modlistPropertiesWindow = null;
|
||||
OpenModListProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenReadmeWindow()
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.ModList.Readme)) return;
|
||||
using (var fs = new FileStream(this.ModListPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
using (var ar = new ZipArchive(fs, ZipArchiveMode.Read))
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
var entry = ar.GetEntry(this.ModList.Readme);
|
||||
using (var e = entry.Open())
|
||||
{
|
||||
e.CopyTo(ms);
|
||||
}
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
using (var reader = new StreamReader(ms))
|
||||
{
|
||||
var viewer = new TextViewer(reader.ReadToEnd(), this.ModListName);
|
||||
viewer.Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Error => "Error";
|
||||
|
||||
public string this[string columnName] => Validate(columnName);
|
||||
|
||||
private string Validate(string columnName)
|
||||
{
|
||||
string validationMessage = null;
|
||||
switch (columnName)
|
||||
{
|
||||
case "Location":
|
||||
if (Location == null)
|
||||
{
|
||||
validationMessage = null;
|
||||
}
|
||||
else switch (Mode)
|
||||
{
|
||||
case RunMode.Compile when Location != null && Directory.Exists(Location) && File.Exists(Path.Combine(Location, "modlist.txt")):
|
||||
Location = Path.Combine(Location, "modlist.txt");
|
||||
validationMessage = null;
|
||||
ConfigureForBuild();
|
||||
break;
|
||||
case RunMode.Install when Location != null && Directory.Exists(Location) && !Directory.EnumerateFileSystemEntries(Location).Any():
|
||||
validationMessage = null;
|
||||
break;
|
||||
case RunMode.Install when Location != null && Directory.Exists(Location) && Directory.EnumerateFileSystemEntries(Location).Any():
|
||||
validationMessage = "You have selected a non-empty directory. Installing the modlist here might result in a broken install!";
|
||||
break;
|
||||
default:
|
||||
validationMessage = "Invalid Mod Organizer profile directory";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return validationMessage;
|
||||
}
|
||||
|
||||
public void LogMsg(string msg)
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => Log.Add(msg));
|
||||
}
|
||||
|
||||
public void SetQueueSize(int max, int current)
|
||||
{
|
||||
if (max == 0)
|
||||
max = 1;
|
||||
var total = current * 100 / max;
|
||||
QueueProgress = total;
|
||||
}
|
||||
|
||||
private void ConfigureForBuild()
|
||||
{
|
||||
var profile_folder = Path.GetDirectoryName(Location);
|
||||
var mo2folder = Path.GetDirectoryName(Path.GetDirectoryName(profile_folder));
|
||||
if (!File.Exists(Path.Combine(mo2folder, "ModOrganizer.exe")))
|
||||
LogMsg($"Error! No ModOrganizer2.exe found in {mo2folder}");
|
||||
|
||||
var profile_name = Path.GetFileName(profile_folder);
|
||||
this.ModListName = profile_name;
|
||||
this.Mode = RunMode.Compile;
|
||||
|
||||
if (Utils.IsMO2Running(mo2folder))
|
||||
{
|
||||
MessageBox.Show("You need to close MO2 before running Wabbajack!",
|
||||
"Error", MessageBoxButton.OK);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
var tmp_compiler = new Compiler(mo2folder);
|
||||
DownloadLocation = tmp_compiler.MO2DownloadsFolder;
|
||||
|
||||
_mo2Folder = mo2folder;
|
||||
}
|
||||
|
||||
internal void ConfigureForInstall(string source, ModList modlist)
|
||||
{
|
||||
this.ModList = modlist;
|
||||
this.ModListPath = source;
|
||||
this.Mode = RunMode.Install;
|
||||
ModListName = this.ModList.Name;
|
||||
HTMLReport = this.ModList.ReportHTML;
|
||||
Location = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
|
||||
var currentWJVersion = new Version(WabbajackVersion);
|
||||
var modlistWJVersion = new Version(modlist.WabbajackVersion);
|
||||
|
||||
if (currentWJVersion > modlistWJVersion)
|
||||
{
|
||||
MessageBox.Show(
|
||||
"The selected Modlist was build with an earlier version of Wabbajack. " +
|
||||
$"Current Version: {WabbajackVersion}, " +
|
||||
$"Version used to build the Modlist: {modlist.WabbajackVersion}",
|
||||
"Information",
|
||||
MessageBoxButton.OK);
|
||||
}
|
||||
else if(currentWJVersion < modlistWJVersion)
|
||||
{
|
||||
MessageBox.Show(
|
||||
"The selected Modlist was build with a newer version of Wabbajack. " +
|
||||
$"Current Version: {WabbajackVersion}, " +
|
||||
$"Version used to build the Modlist: {modlist.WabbajackVersion}",
|
||||
"Information",
|
||||
MessageBoxButton.OK);
|
||||
}
|
||||
|
||||
this.Slideshow.SlideShowElements = modlist.Archives
|
||||
.Select(m => m.State)
|
||||
.OfType<NexusDownloader.State>()
|
||||
.Select(m =>
|
||||
new Slide(NexusApiUtils.FixupSummary(m.ModName),m.ModID,
|
||||
NexusApiUtils.FixupSummary(m.Summary), NexusApiUtils.FixupSummary(m.Author),
|
||||
m.Adult,m.NexusURL,m.SlideShowPic)).ToList();
|
||||
|
||||
|
||||
this.Slideshow.PreloadSlideShow();
|
||||
}
|
||||
|
||||
private void ExecuteBegin()
|
||||
{
|
||||
UIReady = false;
|
||||
if (this.Mode == RunMode.Install)
|
||||
{
|
||||
this.Installing = true;
|
||||
var installer = new Installer(this.ModListPath, this.ModList, Location)
|
||||
{
|
||||
DownloadFolder = DownloadLocation
|
||||
};
|
||||
var th = new Thread(() =>
|
||||
{
|
||||
UIReady = false;
|
||||
try
|
||||
{
|
||||
installer.Install();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
while (ex.InnerException != null) ex = ex.InnerException;
|
||||
LogMsg(ex.StackTrace);
|
||||
LogMsg(ex.ToString());
|
||||
LogMsg($"{ex.Message} - Can't continue");
|
||||
}
|
||||
finally
|
||||
{
|
||||
UIReady = true;
|
||||
this.Installing = false;
|
||||
}
|
||||
})
|
||||
{
|
||||
Priority = ThreadPriority.BelowNormal
|
||||
};
|
||||
th.Start();
|
||||
}
|
||||
else if (_mo2Folder != null)
|
||||
{
|
||||
var compiler = new Compiler(_mo2Folder)
|
||||
{
|
||||
MO2Profile = ModListName,
|
||||
ModListName = ChangedProperties ? this.Slideshow.ModName : null,
|
||||
ModListAuthor = ChangedProperties ? this.Slideshow.AuthorName : null,
|
||||
ModListDescription = ChangedProperties ? this.Slideshow.Summary : null,
|
||||
ModListImage = ChangedProperties ? newImagePath : null,
|
||||
ModListWebsite = ChangedProperties ? this.Slideshow.NexusSiteURL : null,
|
||||
ModListReadme = ChangedProperties ? readmePath : null,
|
||||
WabbajackVersion = WabbajackVersion
|
||||
};
|
||||
var th = new Thread(() =>
|
||||
{
|
||||
UIReady = false;
|
||||
try
|
||||
{
|
||||
compiler.Compile();
|
||||
if (compiler.ModList != null && compiler.ModList.ReportHTML != null)
|
||||
HTMLReport = compiler.ModList.ReportHTML;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
while (ex.InnerException != null) ex = ex.InnerException;
|
||||
LogMsg(ex.StackTrace);
|
||||
LogMsg(ex.ToString());
|
||||
LogMsg($"{ex.Message} - Can't continue");
|
||||
}
|
||||
finally
|
||||
{
|
||||
UIReady = true;
|
||||
}
|
||||
})
|
||||
{
|
||||
Priority = ThreadPriority.BelowNormal
|
||||
};
|
||||
th.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
Utils.Log("Cannot compile modlist: no valid Mod Organizer profile directory selected.");
|
||||
UIReady = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CPUStatus
|
||||
{
|
||||
public int Progress { get; internal set; }
|
||||
public string Msg { get; internal set; }
|
||||
public int ID { get; internal set; }
|
||||
}
|
||||
}
|
36
Wabbajack/Converters/BoolToVisibilityConverter.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
[ValueConversion(typeof(Visibility), typeof(bool))]
|
||||
public class BoolToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (targetType != typeof(Visibility))
|
||||
throw new InvalidOperationException($"The target must be of type {nameof(Visibility)}");
|
||||
bool compareTo = true;
|
||||
if (parameter is bool p)
|
||||
{
|
||||
compareTo = p;
|
||||
}
|
||||
else if (parameter is string str && str.ToUpper().Equals("FALSE"))
|
||||
{
|
||||
compareTo = false;
|
||||
}
|
||||
return ((bool)value) == compareTo ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ using System.Reactive;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using DynamicData;
|
||||
using DynamicData.Kernel;
|
||||
using ReactiveUI;
|
||||
@ -151,6 +152,57 @@ namespace Wabbajack
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<Unit> SelectTask<T>(this IObservable<T> source, Func<T, Task> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(async i =>
|
||||
{
|
||||
await task(i).ConfigureAwait(false);
|
||||
return System.Reactive.Unit.Default;
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<Unit> SelectTask<T>(this IObservable<T> source, Func<Task> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(async _ =>
|
||||
{
|
||||
await task().ConfigureAwait(false);
|
||||
return System.Reactive.Unit.Default;
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<R> SelectTask<T, R>(this IObservable<T> source, Func<Task<R>> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(_ => task());
|
||||
}
|
||||
|
||||
public static IObservable<R> SelectTask<T, R>(this IObservable<T> source, Func<T, Task<R>> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(x => task(x));
|
||||
}
|
||||
|
||||
public static IObservable<T> DoTask<T>(this IObservable<T> source, Func<T, Task> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(async (x) =>
|
||||
{
|
||||
await task(x).ConfigureAwait(false);
|
||||
return x;
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<R> WhereCastable<T, R>(this IObservable<T> source)
|
||||
where R : class
|
||||
where T : class
|
||||
{
|
||||
return source
|
||||
.Select(x => x as R)
|
||||
.NotNull();
|
||||
}
|
||||
|
||||
/// These snippets were provided by RolandPheasant (author of DynamicData)
|
||||
/// They'll be going into the official library at some point, but are here for now.
|
||||
#region Dynamic Data EnsureUniqueChanges
|
||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 512 B |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 139 KiB |
BIN
Wabbajack/Resources/Wabba_Mouth.png
Normal file
After Width: | Height: | Size: 272 KiB |
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 122 KiB |
Before Width: | Height: | Size: 139 KiB After Width: | Height: | Size: 139 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 129 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
@ -7,7 +7,7 @@
|
||||
mc:Ignorable="d">
|
||||
|
||||
<!--Converters-->
|
||||
<BooleanToVisibilityConverter x:Key="bool2VisibilityConverter"/>
|
||||
<local:BoolToVisibilityConverter x:Key="bool2VisibilityConverter" />
|
||||
<local:IsNotNullVisibilityConverter x:Key="IsNotNullVisibilityConverter"/>
|
||||
|
||||
<!--Colors-->
|
||||
@ -22,12 +22,43 @@
|
||||
|
||||
<Color x:Key="HighlightColor">#BDBDBD</Color>
|
||||
<Color x:Key="HotColor">#525252</Color>
|
||||
|
||||
<!--Brushes-->
|
||||
|
||||
<Color x:Key="Yellow">#ffc400</Color>
|
||||
<Color x:Key="Red">#e83a40</Color>
|
||||
<Color x:Key="Green">#52b545</Color>
|
||||
|
||||
<Color x:Key="Primary">#BB86FC</Color>
|
||||
<Color x:Key="PrimaryVariant">#3700B3</Color>
|
||||
<Color x:Key="Secondary">#03DAC6</Color>
|
||||
<Color x:Key="Complementary">#C7FC86</Color>
|
||||
<Color x:Key="Analogous1">#868CFC</Color>
|
||||
<Color x:Key="Analogous2">#F686FC</Color>
|
||||
<Color x:Key="Triadic1">#FC86C7</Color>
|
||||
<Color x:Key="Triadic2">#FCBB86</Color>
|
||||
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="YellowBrush" Color="{StaticResource Yellow}" />
|
||||
<SolidColorBrush x:Key="GreenBrush" Color="{StaticResource Green}" />
|
||||
<SolidColorBrush x:Key="RedBrush" Color="{StaticResource Red}" />
|
||||
<SolidColorBrush x:Key="WarningBrush" Color="{StaticResource Yellow}" />
|
||||
<SolidColorBrush x:Key="ErrorBrush" Color="{StaticResource Red}" />
|
||||
|
||||
<SolidColorBrush x:Key="DarkBackgroundBrush" Color="{StaticResource DarkBackgroundColor}" />
|
||||
<SolidColorBrush x:Key="LightBackgroundBrush" Color="{StaticResource LightBackgroundColor}" />
|
||||
<SolidColorBrush x:Key="BackgroundBrush" Color="{StaticResource BackgroundColor}" />
|
||||
<SolidColorBrush x:Key="ForegroundBrush" Color="{StaticResource ForegroundColor}"/>
|
||||
<SolidColorBrush x:Key="MouseOverForegroundBrush" Color="{StaticResource DarkBackgroundColor}"/>
|
||||
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="{StaticResource WindowBackgroundColor}"/>
|
||||
|
||||
<SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource Primary}" />
|
||||
<SolidColorBrush x:Key="PrimaryVariantBrush" Color="{StaticResource PrimaryVariant}" />
|
||||
<SolidColorBrush x:Key="SecondaryBrush" Color="{StaticResource Secondary}" />
|
||||
<SolidColorBrush x:Key="ComplementaryBrush" Color="{StaticResource Complementary}" />
|
||||
<SolidColorBrush x:Key="Analogous1Brush" Color="{StaticResource Analogous1}" />
|
||||
<SolidColorBrush x:Key="Analogous2Brush" Color="{StaticResource Analogous2}" />
|
||||
<SolidColorBrush x:Key="Triadic1Brush" Color="{StaticResource Triadic1}" />
|
||||
<SolidColorBrush x:Key="Triadic2Brush" Color="{StaticResource Triadic2}" />
|
||||
|
||||
<SolidColorBrush x:Key="TabControlNormalBorderBrush" Color="{StaticResource WindowBackgroundColor}"/>
|
||||
|
||||
<SolidColorBrush x:Key="TabItemHotBackground" Color="{StaticResource HotColor}"/>
|
||||
@ -807,7 +838,7 @@
|
||||
</Style>
|
||||
|
||||
<!-- TextBox -->
|
||||
<Style BasedOn="{StaticResource {x:Type Control}}" TargetType="{x:Type TextBox}">
|
||||
<Style x:Key="MainTextBoxStyle" BasedOn="{StaticResource {x:Type Control}}" TargetType="{x:Type TextBox}">
|
||||
<Setter Property="Background" Value="{StaticResource TextBoxBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
@ -852,6 +883,7 @@
|
||||
</MultiTrigger>-->
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style BasedOn="{StaticResource MainTextBoxStyle}" TargetType="TextBox" />
|
||||
|
||||
<!-- ComboBox -->
|
||||
<Style x:Key="ComboBoxFocusVisual">
|
||||
@ -1151,6 +1183,7 @@
|
||||
<Setter Property="Background" Value="{StaticResource ButtonBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource ButtonBorder}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Focusable" Value="False" />
|
||||
<Setter Property="Foreground" Value="{StaticResource ButtonForeground}"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
@ -1189,6 +1222,10 @@
|
||||
</Style>
|
||||
<Style BasedOn="{StaticResource MainButtonStyle}" TargetType="{x:Type Button}" />
|
||||
|
||||
<Style TargetType="ButtonBase" x:Key="CircleButtonStyle" BasedOn="{StaticResource MahApps.Metro.Styles.MetroCircleButtonStyle}" >
|
||||
<Setter Property="Focusable" Value="False" />
|
||||
</Style>
|
||||
|
||||
<!-- ToggleButton-->
|
||||
<Style TargetType="{x:Type ToggleButton}">
|
||||
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
|
||||
|
@ -1,103 +0,0 @@
|
||||
using Alphaleonis.Win32.Filesystem;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
using Application = System.Windows.Application;
|
||||
using MessageBox = System.Windows.MessageBox;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private AppState _state;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
|
||||
if (args.Length != 3) return;
|
||||
var modlistPath = args[2];
|
||||
var mainWindow = new MainWindow(RunMode.Install, modlistPath);
|
||||
mainWindow.Show();
|
||||
Close();
|
||||
}
|
||||
|
||||
public MainWindow(RunMode mode, string source)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
var context = new AppState(mode);
|
||||
context.LogMsg($"Wabbajack Build - {ThisAssembly.Git.Sha}");
|
||||
SetupHandlers(context);
|
||||
DataContext = context;
|
||||
|
||||
Utils.SetLoggerFn(s => context.LogMsg(s));
|
||||
Utils.SetStatusFn((msg, progress) => WorkQueue.Report(msg, progress));
|
||||
|
||||
new Thread(() =>
|
||||
{
|
||||
if (mode == RunMode.Compile)
|
||||
{
|
||||
Utils.Log("Compiler ready to execute");
|
||||
context.Location = Path.GetDirectoryName(source);
|
||||
context.LocationLabel = "MO2 Profile:";
|
||||
}
|
||||
else if (mode == RunMode.Install)
|
||||
{
|
||||
context.UIReady = false;
|
||||
context.LocationLabel = "Installation Location:";
|
||||
var modlist = Installer.LoadFromFile(source);
|
||||
if (modlist == null)
|
||||
{
|
||||
MessageBox.Show("Invalid Modlist, or file not found.", "Invalid Modlist", MessageBoxButton.OK,
|
||||
MessageBoxImage.Error);
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
ExitWhenClosing = false;
|
||||
var window = new ModeSelectionWindow
|
||||
{
|
||||
ShowActivated = true
|
||||
};
|
||||
window.Show();
|
||||
Close();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
context.ConfigureForInstall(source, modlist);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
context.UIReady = true;
|
||||
}).Start();
|
||||
}
|
||||
|
||||
private void SetupHandlers(AppState state)
|
||||
{
|
||||
_state = state;
|
||||
AppDomain.CurrentDomain.UnhandledException += AppHandler;
|
||||
}
|
||||
|
||||
private void AppHandler(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
_state.LogMsg("Uncaught error:");
|
||||
_state.LogMsg(((Exception)e.ExceptionObject).ExceptionToString());
|
||||
}
|
||||
|
||||
|
||||
internal bool ExitWhenClosing = true;
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
if (ExitWhenClosing)
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
<Window x:Class="Wabbajack.ModeSelectionWindow"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Style="{StaticResource {x:Type Window}}" Icon="Icons/wabbajack.ico" WindowStyle="ToolWindow"
|
||||
xmlns:local="clr-namespace:Wabbajack"
|
||||
mc:Ignorable="d"
|
||||
Title="Wabbajack" Height="800" Width="1024" ResizeMode="CanResize"
|
||||
Closing="Close_Window">
|
||||
<Grid Margin="20">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="30"/>
|
||||
<ColumnDefinition Width="30"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="150"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="70"/>
|
||||
<RowDefinition Height="70"/>
|
||||
<RowDefinition Height="70"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Image MouseLeftButtonDown="GitHub_MouseLeftButtonDown" Margin="5,0,0,0" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" Name="GitHub"/>
|
||||
<Image MouseLeftButtonDown="Patreon_MouseLeftButtonDown" Margin="5,0,0,0" Grid.Row="0" Grid.Column="1" Name="Patreon"/>
|
||||
<Image MouseLeftButtonDown="Discord_MouseLeftButtonDown" Margin="5,0,0,0" Grid.Row="0" Grid.Column="2" Name="Discord"/>
|
||||
<Image Grid.Row="1" Grid.ColumnSpan="3" Name="Banner" Stretch="Uniform" Margin="2,0,2,0"/>
|
||||
<ListBox ScrollViewer.CanContentScroll="False" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Grid.Row="2" Grid.ColumnSpan="3"
|
||||
ItemsSource="{Binding ModLists}" SelectedItem="{Binding Path=SelectedModList, Mode=TwoWay}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300"></ColumnDefinition>
|
||||
<ColumnDefinition Width="20"></ColumnDefinition>
|
||||
<ColumnDefinition Width="200"></ColumnDefinition>
|
||||
<ColumnDefinition Width="200"></ColumnDefinition>
|
||||
<ColumnDefinition Width="200"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="20"></RowDefinition>
|
||||
<RowDefinition Height="15"></RowDefinition>
|
||||
<RowDefinition Height="150"></RowDefinition>
|
||||
<RowDefinition Height="20"></RowDefinition>
|
||||
|
||||
</Grid.RowDefinitions>
|
||||
<Image Source="{Binding Links.ImageUri}" Grid.Column="0" Grid.Row="0" Grid.RowSpan="4"></Image>
|
||||
<TextBlock Text="{Binding Title}" FontSize="20" Grid.Column="2" Grid.Row="0"></TextBlock>
|
||||
<TextBlock Text="{Binding Author}" Grid.Column="2" Grid.Row="1"></TextBlock>
|
||||
<TextBlock Text="{Binding Game}" HorizontalAlignment="Right" TextAlignment="Right" Grid.Column="4" Grid.Row="1"></TextBlock>
|
||||
<TextBlock Text="{Binding Description}" VerticalAlignment="Top" HorizontalAlignment="Left" TextWrapping="Wrap" Grid.Column="2" Grid.Row="2" Grid.ColumnSpan="3"></TextBlock>
|
||||
<Button Grid.Row="3" Grid.Column="2">More Info</Button>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Button Name="InstallModlist" Grid.ColumnSpan="3" Grid.Row="3" Margin="2" Click="InstallModlist_Click" IsEnabled="{Binding CanInstall}">
|
||||
<TextBlock FontSize="40">Download and Install</TextBlock>
|
||||
</Button>
|
||||
<Button Name="InstallFromList" Grid.ColumnSpan="3" Grid.Row="4" Margin="2" Click="InstallFromList_Click">
|
||||
<TextBlock FontSize="40">Install from Disk</TextBlock>
|
||||
</Button>
|
||||
<Button Name="CreateModlist" Grid.ColumnSpan="3" Grid.Row="5" Margin="2" Click="CreateModlist_Click">
|
||||
<TextBlock FontSize="40">Create a ModList</TextBlock>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Window>
|
@ -1,60 +0,0 @@
|
||||
<Window x:Class="Wabbajack.ModlistPropertiesWindow"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Wabbajack"
|
||||
mc:Ignorable="d"
|
||||
Title="Wabbajack (Modlist Properties)" Height="600" Width="900"
|
||||
Style="{StaticResource {x:Type Window}}" Icon="Icons/wabbajack.ico" WindowStyle="ToolWindow"
|
||||
ResizeMode="NoResize">
|
||||
<Grid Margin="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="300"/>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="30"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid Grid.Column="0" Grid.Row="0" Margin="5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="30"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Image Grid.Row="0" Stretch="Fill" Name="SplashScreenProperty"/>
|
||||
<Button Height="30" Grid.Row="1" Click="SetSplashScreen_Click" ToolTip="Use a 1400x900 png file for the best results">
|
||||
<TextBlock Text="Change splash screen image" FontSize="15" FontWeight="Bold"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Column="1" Grid.Row="0" Margin="0 5 0 5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBox Grid.Row="0" Text="ModList Name" Name="ModlistNameProperty" ToolTip="Change the name of your ModList" MaxLength="50" AcceptsTab="False" FontSize="15" FontWeight="Bold" Margin="0,0,0,5"/>
|
||||
<TextBox Grid.Row="1" Text="Author" Name="ModlistAuthorProperty" ToolTip="Change the name of the Author" MaxLength="50" AcceptsTab="False" FontSize="15" Margin="0 0 0 5" />
|
||||
<TextBox Grid.Row="2" Text="Description (700 characters max)" Name="ModlistDescriptionProperty" ToolTip="Change the description" MaxLength="700" AcceptsReturn="True" TextWrapping="Wrap" AcceptsTab="False" FontSize="15" Margin="0,0,0,0"/>
|
||||
</Grid>
|
||||
|
||||
<TextBox Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Text="Website" Name="ModlistWebsiteProperty" ToolTip="Change the website" MaxLength="80" AcceptsReturn="False" AcceptsTab="False" FontSize="15"/>
|
||||
<Grid Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" Height="30" Margin="0,10,0,-10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox Height="30" Grid.ColumnSpan="3" Text="Readme path" Name="ModlistReadmeProperty" AcceptsReturn="False" AcceptsTab="False" FontSize="15"/>
|
||||
<Button Height="30" Grid.Column="2" Content="Choose" Click="ChooseReadme_Click"/>
|
||||
</Grid>
|
||||
|
||||
<Button Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2" Click="SaveProperties_Click" Margin="0,160,0,-160" Height="30" VerticalAlignment="Bottom">
|
||||
<TextBlock Text="Save" FontSize="15" FontWeight="Bold"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Window>
|
@ -1,75 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Wabbajack.Lib;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ModlistPropertiesWindow.xaml
|
||||
/// </summary>
|
||||
public partial class ModlistPropertiesWindow : Window
|
||||
{
|
||||
internal string newBannerFile;
|
||||
internal readonly AppState state;
|
||||
internal ModlistPropertiesWindow(AppState _state)
|
||||
{
|
||||
InitializeComponent();
|
||||
var bannerImage = UIUtils.BitmapImageFromResource("Wabbajack.UI.Banner_Dark.png");
|
||||
SplashScreenProperty.Source = bannerImage;
|
||||
|
||||
newBannerFile = null;
|
||||
state = _state;
|
||||
}
|
||||
|
||||
private void SetSplashScreen_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var file = UIUtils.OpenFileDialog("Banner image|*.png");
|
||||
if (file != null)
|
||||
{
|
||||
newBannerFile = file;
|
||||
SplashScreenProperty.Source = new BitmapImage(new Uri(file));
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveProperties_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (state.UIReady)
|
||||
{
|
||||
if (newBannerFile != null)
|
||||
{
|
||||
BitmapImage splashScreen = new BitmapImage(new Uri(newBannerFile));
|
||||
state.newImagePath = newBannerFile;
|
||||
state.Slideshow.Image = splashScreen;
|
||||
}
|
||||
|
||||
state.Slideshow.ModName = ModlistNameProperty.Text;
|
||||
state.Slideshow.Summary = ModlistDescriptionProperty.Text;
|
||||
state.Slideshow.AuthorName = ModlistAuthorProperty.Text;
|
||||
state.Slideshow.NexusSiteURL = ModlistWebsiteProperty.Text;
|
||||
state.readmePath = ModlistReadmeProperty.Text;
|
||||
|
||||
state.ChangedProperties = true;
|
||||
|
||||
Hide();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsClosed { get; private set; }
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
IsClosed = true;
|
||||
}
|
||||
|
||||
private void ChooseReadme_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var file = UIUtils.OpenFileDialog("Readme|*.txt");
|
||||
if (file != null)
|
||||
{
|
||||
ModlistReadmeProperty.Text = file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Wabbajack.SlideshowView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Wabbajack"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DataContext="{d:DesignInstance local:SlideShow}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="4" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Grid.Column="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="30" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
Source="{Binding Image}"
|
||||
Stretch="Fill" />
|
||||
<Button
|
||||
Grid.Row="1"
|
||||
FontSize="15"
|
||||
FontWeight="Bold">
|
||||
<Button.Style>
|
||||
<Style TargetType="Button" BasedOn="{StaticResource MainButtonStyle}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding AppState.Mode}" Value="{x:Static local:RunMode.Install}">
|
||||
<Setter Property="Command" Value="{Binding AppState.OpenReadmeCommand}" />
|
||||
<Setter Property="Content" Value="Open README" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding AppState.Mode}" Value="{x:Static local:RunMode.Compile}">
|
||||
<Setter Property="Command" Value="{Binding AppState.OpenModListPropertiesCommand}" />
|
||||
<Setter Property="Content" Value="Modlist Properties" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Grid.Column="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
FontSize="30"
|
||||
FontWeight="Bold"
|
||||
Margin="6,0,0,0"
|
||||
Text="{Binding ModName}" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
FontSize="15"
|
||||
FontWeight="Bold"
|
||||
Margin="6,0,0,6"
|
||||
Text="{Binding AuthorName}" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
FontSize="15"
|
||||
FontWeight="Bold"
|
||||
Padding="5"
|
||||
Background="{StaticResource TextBoxBackground}"
|
||||
Text="{Binding Summary}"
|
||||
TextWrapping="Wrap" />
|
||||
<Grid Grid.Row="3" VerticalAlignment="Bottom">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="48" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<CheckBox
|
||||
Margin="6,0,0,0"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
IsChecked="{Binding Enable}">
|
||||
Enable the Slideshow
|
||||
</CheckBox>
|
||||
<CheckBox
|
||||
Grid.Column="1"
|
||||
Margin="15,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
IsChecked="{Binding ShowNSFW}">
|
||||
Show NSFW Mods in the Slideshow
|
||||
</CheckBox>
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding SlideShowNextItemCommand}"
|
||||
ToolTip="Skip to next slide">
|
||||
<DockPanel>
|
||||
<Image Source="{Binding NextIcon}" Stretch="Fill" />
|
||||
</DockPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Button
|
||||
Grid.Row="4"
|
||||
Height="30"
|
||||
Command="{Binding VisitNexusSiteCommand}">
|
||||
<TextBlock
|
||||
FontSize="15"
|
||||
FontWeight="Bold"
|
||||
Text="View Nexus Site" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,15 +0,0 @@
|
||||
<Window x:Class="Wabbajack.UI.TextViewer"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Wabbajack.UI"
|
||||
Style="{StaticResource {x:Type Window}}"
|
||||
mc:Ignorable="d"
|
||||
Icon="Icons/wabbajack.ico"
|
||||
WindowStyle="ToolWindow"
|
||||
Title="TextViewer" Height="450" Width="800">
|
||||
<Grid>
|
||||
<TextBlock FontSize="20" Name="TextBlock" TextWrapping="Wrap"/>
|
||||
</Grid>
|
||||
</Window>
|
15
Wabbajack/Util/CPUStatus.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
public class CPUStatus
|
||||
{
|
||||
public int Progress { get; internal set; }
|
||||
public string Msg { get; internal set; }
|
||||
public int ID { get; internal set; }
|
||||
}
|
||||
}
|
148
Wabbajack/View Models/CompilerVM.cs
Normal file
@ -0,0 +1,148 @@
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
public class CompilerVM : ViewModel
|
||||
{
|
||||
public MainWindowVM MWVM { get; }
|
||||
|
||||
private string _Mo2Folder;
|
||||
public string Mo2Folder { get => _Mo2Folder; set => this.RaiseAndSetIfChanged(ref _Mo2Folder, value); }
|
||||
|
||||
private string _MOProfile;
|
||||
public string MOProfile { get => _MOProfile; set => this.RaiseAndSetIfChanged(ref _MOProfile, value); }
|
||||
|
||||
private string _ModListName;
|
||||
public string ModListName { get => _ModListName; set => this.RaiseAndSetIfChanged(ref _ModListName, value); }
|
||||
|
||||
private string _Location;
|
||||
public string Location { get => _Location; set => this.RaiseAndSetIfChanged(ref _Location, value); }
|
||||
|
||||
private bool _UIReady = true;
|
||||
public bool UIReady { get => _UIReady; set => this.RaiseAndSetIfChanged(ref _UIReady, value); }
|
||||
|
||||
private string _AuthorName;
|
||||
public string AuthorName { get => _AuthorName; set => this.RaiseAndSetIfChanged(ref _AuthorName, value); }
|
||||
|
||||
private string _Summary = "Description (700 characters max)";
|
||||
public string Summary { get => _Summary; set => this.RaiseAndSetIfChanged(ref _Summary, value); }
|
||||
|
||||
private string _ImagePath;
|
||||
public string ImagePath { get => _ImagePath; set => this.RaiseAndSetIfChanged(ref _ImagePath, value); }
|
||||
|
||||
private readonly ObservableAsPropertyHelper<BitmapImage> _Image;
|
||||
public BitmapImage Image => _Image.Value;
|
||||
|
||||
private string _NexusSiteURL;
|
||||
public string NexusSiteURL { get => _NexusSiteURL; set => this.RaiseAndSetIfChanged(ref _NexusSiteURL, value); }
|
||||
|
||||
private string _ReadMeText;
|
||||
public string ReadMeText { get => _ReadMeText; set => this.RaiseAndSetIfChanged(ref _ReadMeText, value); }
|
||||
|
||||
private string _HTMLReport;
|
||||
public string HTMLReport { get => _HTMLReport; set => this.RaiseAndSetIfChanged(ref _HTMLReport, value); }
|
||||
|
||||
private string _DownloadLocation;
|
||||
public string DownloadLocation { get => _DownloadLocation; set => this.RaiseAndSetIfChanged(ref _DownloadLocation, value); }
|
||||
|
||||
public IReactiveCommand BeginCommand { get; }
|
||||
|
||||
public CompilerVM(MainWindowVM mainWindowVM, string source)
|
||||
{
|
||||
this.MWVM = mainWindowVM;
|
||||
this.Location = source;
|
||||
|
||||
this.BeginCommand = ReactiveCommand.CreateFromTask(
|
||||
execute: this.ExecuteBegin,
|
||||
canExecute: this.WhenAny(x => x.UIReady)
|
||||
.ObserveOnGuiThread());
|
||||
|
||||
this._Image = this.WhenAny(x => x.ImagePath)
|
||||
.Select(path =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path)) return UIUtils.BitmapImageFromResource("Wabbajack.Resources.Banner_Dark.png");
|
||||
if (UIUtils.TryGetBitmapImageFromFile(path, out var image))
|
||||
{
|
||||
return image;
|
||||
}
|
||||
return UIUtils.BitmapImageFromResource("Wabbajack.Resources.none.png");
|
||||
})
|
||||
.ToProperty(this, nameof(this.Image));
|
||||
|
||||
ConfigureForBuild(source);
|
||||
}
|
||||
|
||||
private void ConfigureForBuild(string location)
|
||||
{
|
||||
var profile_folder = Path.GetDirectoryName(location);
|
||||
this.Mo2Folder = Path.GetDirectoryName(Path.GetDirectoryName(profile_folder));
|
||||
if (!File.Exists(Path.Combine(this.Mo2Folder, "ModOrganizer.exe")))
|
||||
{
|
||||
this.Log().Error($"Error! No ModOrganizer2.exe found in {this.Mo2Folder}");
|
||||
}
|
||||
|
||||
this.MOProfile = Path.GetFileName(profile_folder);
|
||||
this.ModListName = this.MOProfile;
|
||||
|
||||
var tmp_compiler = new Compiler(this.Mo2Folder);
|
||||
this.DownloadLocation = tmp_compiler.MO2DownloadsFolder;
|
||||
}
|
||||
|
||||
private async Task ExecuteBegin()
|
||||
{
|
||||
if (this.Mo2Folder != null)
|
||||
{
|
||||
var compiler = new Compiler(this.Mo2Folder)
|
||||
{
|
||||
MO2Profile = this.MOProfile,
|
||||
ModListName = this.ModListName,
|
||||
ModListAuthor = this.AuthorName,
|
||||
ModListDescription = this.Summary,
|
||||
ModListImage = this.ImagePath,
|
||||
ModListWebsite = this.NexusSiteURL,
|
||||
ModListReadme = this.ReadMeText,
|
||||
};
|
||||
await Task.Run(() =>
|
||||
{
|
||||
UIReady = false;
|
||||
try
|
||||
{
|
||||
compiler.Compile();
|
||||
if (compiler.ModList?.ReportHTML != null)
|
||||
{
|
||||
this.HTMLReport = compiler.ModList.ReportHTML;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
while (ex.InnerException != null) ex = ex.InnerException;
|
||||
this.Log().Warn(ex, "Can't continue");
|
||||
}
|
||||
finally
|
||||
{
|
||||
UIReady = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Log().Warn("Cannot compile modlist: no valid Mod Organizer profile directory selected.");
|
||||
UIReady = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
320
Wabbajack/View Models/InstallerVM.cs
Normal file
@ -0,0 +1,320 @@
|
||||
using Syroot.Windows.IO;
|
||||
using System;
|
||||
using ReactiveUI;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Threading;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib.Downloaders;
|
||||
using Wabbajack.Lib.NexusApi;
|
||||
using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
using System.Reactive;
|
||||
using System.Text;
|
||||
using Wabbajack.Lib;
|
||||
using Splat;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
public class InstallerVM : ViewModel
|
||||
{
|
||||
public SlideShow Slideshow { get; }
|
||||
|
||||
public MainWindowVM MWVM { get; }
|
||||
|
||||
public BitmapImage WabbajackLogo { get; } = UIUtils.BitmapImageFromResource("Wabbajack.Resources.Wabba_Mouth.png");
|
||||
|
||||
private readonly ObservableAsPropertyHelper<ModList> _ModList;
|
||||
public ModList ModList => _ModList.Value;
|
||||
|
||||
private string _ModListPath;
|
||||
public string ModListPath { get => _ModListPath; set => this.RaiseAndSetIfChanged(ref _ModListPath, value); }
|
||||
|
||||
private bool _UIReady;
|
||||
public bool UIReady { get => _UIReady; set => this.RaiseAndSetIfChanged(ref _UIReady, value); }
|
||||
|
||||
private readonly ObservableAsPropertyHelper<string> _HTMLReport;
|
||||
public string HTMLReport => _HTMLReport.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Tracks whether an install is currently in progress
|
||||
/// </summary>
|
||||
private bool _Installing;
|
||||
public bool Installing { get => _Installing; set => this.RaiseAndSetIfChanged(ref _Installing, value); }
|
||||
|
||||
/// <summary>
|
||||
/// Tracks whether to show the installing pane
|
||||
/// </summary>
|
||||
private bool _InstallingMode;
|
||||
public bool InstallingMode { get => _InstallingMode; set => this.RaiseAndSetIfChanged(ref _InstallingMode, value); }
|
||||
|
||||
private string _Location = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
public string Location { get => _Location; set => this.RaiseAndSetIfChanged(ref _Location, value); }
|
||||
|
||||
private string _DownloadLocation;
|
||||
public string DownloadLocation { get => _DownloadLocation; set => this.RaiseAndSetIfChanged(ref _DownloadLocation, value); }
|
||||
|
||||
private readonly ObservableAsPropertyHelper<float> _ProgressPercent;
|
||||
public float ProgressPercent => _ProgressPercent.Value;
|
||||
|
||||
private readonly ObservableAsPropertyHelper<BitmapImage> _Image;
|
||||
public BitmapImage Image => _Image.Value;
|
||||
|
||||
private readonly ObservableAsPropertyHelper<string> _TitleText;
|
||||
public string TitleText => _TitleText.Value;
|
||||
|
||||
private readonly ObservableAsPropertyHelper<string> _AuthorText;
|
||||
public string AuthorText => _AuthorText.Value;
|
||||
|
||||
private readonly ObservableAsPropertyHelper<string> _Description;
|
||||
public string Description => _Description.Value;
|
||||
|
||||
// Command properties
|
||||
public IReactiveCommand BeginCommand { get; }
|
||||
public IReactiveCommand ShowReportCommand { get; }
|
||||
public IReactiveCommand OpenReadmeCommand { get; }
|
||||
public IReactiveCommand VisitWebsiteCommand { get; }
|
||||
|
||||
public InstallerVM(MainWindowVM mainWindowVM)
|
||||
{
|
||||
if (Path.GetDirectoryName(Assembly.GetEntryAssembly().Location.ToLower()) == KnownFolders.Downloads.Path.ToLower())
|
||||
{
|
||||
MessageBox.Show(
|
||||
"Wabbajack is running inside your Downloads folder. This folder is often highly monitored by antivirus software and these can often " +
|
||||
"conflict with the operations Wabbajack needs to perform. Please move this executable outside of your Downloads folder and then restart the app.",
|
||||
"Cannot run inside Downloads",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
this.MWVM = mainWindowVM;
|
||||
|
||||
this._ModList = this.WhenAny(x => x.ModListPath)
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.Select(source =>
|
||||
{
|
||||
if (source == null) return default;
|
||||
var modlist = Installer.LoadFromFile(source);
|
||||
if (modlist == null)
|
||||
{
|
||||
MessageBox.Show("Invalid Modlist, or file not found.", "Invalid Modlist", MessageBoxButton.OK,
|
||||
MessageBoxImage.Error);
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
this.MWVM.MainWindow.ExitWhenClosing = false;
|
||||
var window = new ModeSelectionWindow
|
||||
{
|
||||
ShowActivated = true
|
||||
};
|
||||
window.Show();
|
||||
this.MWVM.MainWindow.Close();
|
||||
});
|
||||
return default;
|
||||
}
|
||||
return modlist;
|
||||
})
|
||||
.ObserveOnGuiThread()
|
||||
.StartWith(default(ModList))
|
||||
.ToProperty(this, nameof(this.ModList));
|
||||
this._HTMLReport = this.WhenAny(x => x.ModList)
|
||||
.Select(modList => modList?.ReportHTML)
|
||||
.ToProperty(this, nameof(this.HTMLReport));
|
||||
this._ProgressPercent = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.Installing),
|
||||
this.WhenAny(x => x.InstallingMode),
|
||||
resultSelector: (installing, mode) => !installing && mode)
|
||||
.Select(show => show ? 1f : 0f)
|
||||
// Disable for now, until more reliable
|
||||
//this.WhenAny(x => x.MWVM.QueueProgress)
|
||||
// .Select(i => i / 100f)
|
||||
.ToProperty(this, nameof(this.ProgressPercent));
|
||||
|
||||
this.Slideshow = new SlideShow(this);
|
||||
|
||||
// Locate and create modlist image if it exists
|
||||
var modListImage = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModList),
|
||||
this.WhenAny(x => x.ModListPath),
|
||||
(modList, modListPath) => (modList, modListPath))
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.Select(u =>
|
||||
{
|
||||
if (u.modList == null
|
||||
|| u.modListPath == null
|
||||
|| !File.Exists(u.modListPath)
|
||||
|| string.IsNullOrEmpty(u.modList.Image)
|
||||
|| u.modList.Image.Length != 36)
|
||||
{
|
||||
return WabbajackLogo;
|
||||
}
|
||||
try
|
||||
{
|
||||
using (var fs = new FileStream(u.modListPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
using (var ar = new ZipArchive(fs, ZipArchiveMode.Read))
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
var entry = ar.GetEntry(u.modList.Image);
|
||||
using (var e = entry.Open())
|
||||
e.CopyTo(ms);
|
||||
var image = new BitmapImage();
|
||||
image.BeginInit();
|
||||
image.CacheOption = BitmapCacheOption.OnLoad;
|
||||
image.StreamSource = ms;
|
||||
image.EndInit();
|
||||
image.Freeze();
|
||||
|
||||
return image;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Log().Warn(ex, "Error loading modlist splash image.");
|
||||
return WabbajackLogo;
|
||||
}
|
||||
})
|
||||
.ObserveOnGuiThread()
|
||||
.StartWith(default(BitmapImage))
|
||||
.Replay(1)
|
||||
.RefCount();
|
||||
|
||||
// Set display items to modlist if configuring or complete,
|
||||
// or to the current slideshow data if installing
|
||||
this._Image = Observable.CombineLatest(
|
||||
modListImage
|
||||
.StartWith(default(BitmapImage)),
|
||||
this.WhenAny(x => x.Slideshow.Image)
|
||||
.StartWith(default(BitmapImage)),
|
||||
this.WhenAny(x => x.Installing),
|
||||
resultSelector: (modList, slideshow, installing) => installing ? slideshow : modList)
|
||||
.ToProperty(this, nameof(this.Image));
|
||||
this._TitleText = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModList.Name),
|
||||
this.WhenAny(x => x.Slideshow.ModName),
|
||||
this.WhenAny(x => x.Installing),
|
||||
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
||||
.ToProperty(this, nameof(this.TitleText));
|
||||
this._AuthorText = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModList.Author),
|
||||
this.WhenAny(x => x.Slideshow.AuthorName),
|
||||
this.WhenAny(x => x.Installing),
|
||||
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
||||
.ToProperty(this, nameof(this.AuthorText));
|
||||
this._Description = Observable.CombineLatest(
|
||||
this.WhenAny(x => x.ModList.Description),
|
||||
this.WhenAny(x => x.Slideshow.Description),
|
||||
this.WhenAny(x => x.Installing),
|
||||
resultSelector: (modList, mod, installing) => installing ? mod : modList)
|
||||
.ToProperty(this, nameof(this.Description));
|
||||
|
||||
// Define commands
|
||||
this.ShowReportCommand = ReactiveCommand.Create(ShowReport);
|
||||
this.OpenReadmeCommand = ReactiveCommand.Create(
|
||||
execute: this.OpenReadmeWindow,
|
||||
canExecute: this.WhenAny(x => x.ModList)
|
||||
.Select(modList => !string.IsNullOrEmpty(modList?.Readme))
|
||||
.ObserveOnGuiThread());
|
||||
this.BeginCommand = ReactiveCommand.Create(
|
||||
execute: this.ExecuteBegin,
|
||||
canExecute: this.WhenAny(x => x.Installing)
|
||||
.Select(installing => !installing)
|
||||
.ObserveOnGuiThread());
|
||||
this.VisitWebsiteCommand = ReactiveCommand.Create(
|
||||
execute: () => Process.Start(this.ModList.Website),
|
||||
canExecute: this.WhenAny(x => x.ModList.Website)
|
||||
.Select(x => x?.StartsWith("https://") ?? false)
|
||||
.ObserveOnGuiThread());
|
||||
|
||||
// Have Installation location updates modify the downloads location if empty
|
||||
this.WhenAny(x => x.Location)
|
||||
.Subscribe(installPath =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(this.DownloadLocation))
|
||||
{
|
||||
this.DownloadLocation = Path.Combine(installPath, "downloads");
|
||||
}
|
||||
})
|
||||
.DisposeWith(this.CompositeDisposable);
|
||||
}
|
||||
|
||||
private void ShowReport()
|
||||
{
|
||||
var file = Path.GetTempFileName() + ".html";
|
||||
File.WriteAllText(file, HTMLReport);
|
||||
Process.Start(file);
|
||||
}
|
||||
|
||||
private void OpenReadmeWindow()
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.ModList.Readme)) return;
|
||||
using (var fs = new FileStream(this.ModListPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
using (var ar = new ZipArchive(fs, ZipArchiveMode.Read))
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
var entry = ar.GetEntry(this.ModList.Readme);
|
||||
if (entry == null)
|
||||
{
|
||||
Utils.Log($"Tried to open a non-existant readme: {this.ModList.Readme}");
|
||||
return;
|
||||
}
|
||||
using (var e = entry.Open())
|
||||
{
|
||||
e.CopyTo(ms);
|
||||
}
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
using (var reader = new StreamReader(ms))
|
||||
{
|
||||
var viewer = new TextViewer(reader.ReadToEnd(), this.ModList.Name);
|
||||
viewer.Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ExecuteBegin()
|
||||
{
|
||||
this.Installing = true;
|
||||
this.InstallingMode = true;
|
||||
var installer = new Installer(this.ModListPath, this.ModList, Location)
|
||||
{
|
||||
DownloadFolder = DownloadLocation
|
||||
};
|
||||
var th = new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
installer.Install();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
while (ex.InnerException != null) ex = ex.InnerException;
|
||||
Utils.Log(ex.StackTrace);
|
||||
Utils.Log(ex.ToString());
|
||||
Utils.Log($"{ex.Message} - Can't continue");
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
this.Installing = false;
|
||||
}
|
||||
})
|
||||
{
|
||||
Priority = ThreadPriority.BelowNormal
|
||||
};
|
||||
th.Start();
|
||||
}
|
||||
}
|
||||
}
|
115
Wabbajack/View Models/MainWindowVM.cs
Normal file
@ -0,0 +1,115 @@
|
||||
using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
using ReactiveUI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
/// <summary>
|
||||
/// Main View Model for the application.
|
||||
/// Keeps track of which sub view is being shown in the window, and has some singleton wiring like WorkQueue and Logging.
|
||||
/// </summary>
|
||||
public class MainWindowVM : ViewModel
|
||||
{
|
||||
public MainWindow MainWindow { get; }
|
||||
|
||||
private readonly ObservableAsPropertyHelper<ViewModel> _ActivePane;
|
||||
public ViewModel ActivePane => _ActivePane.Value;
|
||||
|
||||
private int _QueueProgress;
|
||||
public int QueueProgress { get => _QueueProgress; set => this.RaiseAndSetIfChanged(ref _QueueProgress, value); }
|
||||
|
||||
private readonly Subject<CPUStatus> _statusSubject = new Subject<CPUStatus>();
|
||||
public IObservable<CPUStatus> StatusObservable => _statusSubject;
|
||||
public ObservableCollectionExtended<CPUStatus> StatusList { get; } = new ObservableCollectionExtended<CPUStatus>();
|
||||
|
||||
private Subject<string> _logSubj = new Subject<string>();
|
||||
public ObservableCollectionExtended<string> Log { get; } = new ObservableCollectionExtended<string>();
|
||||
|
||||
private RunMode _Mode;
|
||||
public RunMode Mode { get => _Mode; set => this.RaiseAndSetIfChanged(ref _Mode, value); }
|
||||
|
||||
public MainWindowVM(RunMode mode, string source, MainWindow mainWindow)
|
||||
{
|
||||
this.Mode = mode;
|
||||
this.MainWindow = mainWindow;
|
||||
|
||||
// Set up logging
|
||||
_logSubj
|
||||
.ToObservableChangeSet()
|
||||
.Buffer(TimeSpan.FromMilliseconds(250))
|
||||
.Where(l => l.Count > 0)
|
||||
.FlattenBufferResult()
|
||||
.Top(5000)
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Bind(this.Log)
|
||||
.Subscribe()
|
||||
.DisposeWith(this.CompositeDisposable);
|
||||
Utils.SetLoggerFn(s => _logSubj.OnNext(s));
|
||||
Utils.SetStatusFn((msg, progress) => WorkQueue.Report(msg, progress));
|
||||
|
||||
// Wire mode to drive the active pane
|
||||
this._ActivePane = this.WhenAny(x => x.Mode)
|
||||
.Select<RunMode, ViewModel>(m =>
|
||||
{
|
||||
switch (m)
|
||||
{
|
||||
case RunMode.Compile:
|
||||
return new CompilerVM(this, source);
|
||||
case RunMode.Install:
|
||||
return new InstallerVM(this);
|
||||
default:
|
||||
return default;
|
||||
}
|
||||
})
|
||||
.ToProperty(this, nameof(this.ActivePane));
|
||||
this.WhenAny(x => x.ActivePane)
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.WhereCastable<ViewModel, InstallerVM>()
|
||||
.Subscribe(vm => vm.ModListPath = source)
|
||||
.DisposeWith(this.CompositeDisposable);
|
||||
|
||||
// Initialize work queue
|
||||
WorkQueue.Init(
|
||||
report_function: (id, msg, progress) => this._statusSubject.OnNext(new CPUStatus() { ID = id, Msg = msg, Progress = progress }),
|
||||
report_queue_size: (max, current) => this.SetQueueSize(max, current));
|
||||
|
||||
// Compile progress updates and populate ObservableCollection
|
||||
this._statusSubject
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.ToObservableChangeSet(x => x.ID)
|
||||
.Batch(TimeSpan.FromMilliseconds(250))
|
||||
.EnsureUniqueChanges()
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Sort(SortExpressionComparer<CPUStatus>.Ascending(s => s.ID), SortOptimisations.ComparesImmutableValuesOnly)
|
||||
.Bind(this.StatusList)
|
||||
.Subscribe()
|
||||
.DisposeWith(this.CompositeDisposable);
|
||||
}
|
||||
|
||||
private void SetQueueSize(int max, int current)
|
||||
{
|
||||
if (max == 0)
|
||||
max = 1;
|
||||
QueueProgress = current * 100 / max;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
Utils.SetLoggerFn(s => { });
|
||||
}
|
||||
}
|
||||
}
|
@ -11,22 +11,9 @@ using Wabbajack.Lib.ModListRegistry;
|
||||
|
||||
namespace Wabbajack.UI
|
||||
{
|
||||
public class ModeSelectionWindowViewModel : ViewModel
|
||||
public class ModeSelectionWindowVM : ViewModel
|
||||
{
|
||||
|
||||
|
||||
public ModeSelectionWindowViewModel()
|
||||
{
|
||||
_modLists = new ObservableCollection<ModlistMetadata>(ModlistMetadata.LoadFromGithub());
|
||||
}
|
||||
|
||||
private ObservableCollection<ModlistMetadata> _modLists;
|
||||
|
||||
public ObservableCollection<ModlistMetadata> ModLists
|
||||
{
|
||||
get => _modLists;
|
||||
}
|
||||
|
||||
public ObservableCollection<ModlistMetadata> ModLists { get; } = new ObservableCollection<ModlistMetadata>(ModlistMetadata.LoadFromGithub());
|
||||
|
||||
private ModlistMetadata _selectedModList;
|
||||
public ModlistMetadata SelectedModList
|
||||
@ -60,7 +47,6 @@ namespace Wabbajack.UI
|
||||
if (window.Result == DownloadWindow.WindowResult.Completed)
|
||||
return dest;
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@ -13,6 +14,7 @@ using System.Threading.Tasks;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Wabbajack.Common;
|
||||
using Wabbajack.Lib;
|
||||
using Wabbajack.Lib.Downloaders;
|
||||
using Wabbajack.Lib.NexusApi;
|
||||
|
||||
namespace Wabbajack
|
||||
@ -30,10 +32,9 @@ namespace Wabbajack
|
||||
|
||||
public Queue<Slide> SlidesQueue { get; }
|
||||
|
||||
public AppState AppState { get; }
|
||||
public InstallerVM Installer { get; }
|
||||
|
||||
public BitmapImage NextIcon { get; } = UIUtils.BitmapImageFromResource("Wabbajack.UI.Icons.next.png");
|
||||
public BitmapImage WabbajackLogo { get; } = UIUtils.BitmapImageFromResource("Wabbajack.UI.Banner_Dark.png");
|
||||
public BitmapImage NextIcon { get; } = UIUtils.BitmapImageFromResource("Wabbajack.Resources.Icons.next.png");
|
||||
|
||||
private bool _ShowNSFW;
|
||||
public bool ShowNSFW { get => _ShowNSFW; set => this.RaiseAndSetIfChanged(ref _ShowNSFW, value); }
|
||||
@ -53,8 +54,8 @@ namespace Wabbajack
|
||||
private string _AuthorName = "Halgari & the Wabbajack Team";
|
||||
public string AuthorName { get => _AuthorName; set => this.RaiseAndSetIfChanged(ref _AuthorName, value); }
|
||||
|
||||
private string _Summary;
|
||||
public string Summary { get => _Summary; set => this.RaiseAndSetIfChanged(ref _Summary, value); }
|
||||
private string _Description;
|
||||
public string Description { get => _Description; set => this.RaiseAndSetIfChanged(ref _Description, value); }
|
||||
|
||||
private string _NexusSiteURL = "https://github.com/wabbajack-tools/wabbajack";
|
||||
public string NexusSiteURL { get => _NexusSiteURL; set => this.RaiseAndSetIfChanged(ref _NexusSiteURL, value); }
|
||||
@ -62,13 +63,13 @@ namespace Wabbajack
|
||||
public IReactiveCommand SlideShowNextItemCommand { get; } = ReactiveCommand.Create(() => { });
|
||||
public IReactiveCommand VisitNexusSiteCommand { get; }
|
||||
|
||||
public SlideShow(AppState appState)
|
||||
public SlideShow(InstallerVM appState)
|
||||
{
|
||||
SlideShowElements = NexusApiClient.CachedSlideShow.ToList();
|
||||
CachedSlides = new Dictionary<string, Slide>();
|
||||
SlidesQueue = new Queue<Slide>();
|
||||
_random = new Random();
|
||||
AppState = appState;
|
||||
Installer = appState;
|
||||
|
||||
this.VisitNexusSiteCommand = ReactiveCommand.Create(
|
||||
execute: () => Process.Start(this.NexusSiteURL),
|
||||
@ -77,91 +78,44 @@ namespace Wabbajack
|
||||
.ObserveOnGuiThread());
|
||||
|
||||
// Apply modlist properties when it changes
|
||||
this.WhenAny(x => x.AppState.ModList)
|
||||
this.WhenAny(x => x.Installer.ModList)
|
||||
.NotNull()
|
||||
.Subscribe(modList =>
|
||||
.ObserveOnGuiThread()
|
||||
.Do(modList =>
|
||||
{
|
||||
this.NexusSiteURL = modList.Website;
|
||||
this.ModName = modList.Name;
|
||||
this.AuthorName = modList.Author;
|
||||
this.Summary = modList.Description;
|
||||
this.SlideShowElements = modList.Archives
|
||||
.Select(m => m.State)
|
||||
.OfType<NexusDownloader.State>()
|
||||
.Select(m =>
|
||||
new Slide(NexusApiUtils.FixupSummary(m.ModName), m.ModID,
|
||||
NexusApiUtils.FixupSummary(m.Summary), NexusApiUtils.FixupSummary(m.Author),
|
||||
m.Adult, m.NexusURL, m.SlideShowPic)).ToList();
|
||||
})
|
||||
.DisposeWith(this.CompositeDisposable);
|
||||
|
||||
// Update splashscreen when modlist changes
|
||||
Observable.CombineLatest(
|
||||
(this).WhenAny(x => x.AppState.ModList),
|
||||
(this).WhenAny(x => x.AppState.ModListPath),
|
||||
(this).WhenAny(x => x.Enable),
|
||||
(modList, modListPath, enabled) => (modList, modListPath, enabled))
|
||||
// Do any potential unzipping on a background thread
|
||||
.ObserveOn(RxApp.TaskpoolScheduler)
|
||||
.Select(u =>
|
||||
.Do(modList =>
|
||||
{
|
||||
if (u.enabled
|
||||
&& u.modList != null
|
||||
&& u.modListPath != null
|
||||
&& File.Exists(u.modListPath)
|
||||
&& !string.IsNullOrEmpty(u.modList.Image)
|
||||
&& u.modList.Image.Length == 36)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var fs = new FileStream(u.modListPath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
using (var ar = new ZipArchive(fs, ZipArchiveMode.Read))
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
var entry = ar.GetEntry(u.modList.Image);
|
||||
using (var e = entry.Open())
|
||||
e.CopyTo(ms);
|
||||
var image = new BitmapImage();
|
||||
image.BeginInit();
|
||||
image.CacheOption = BitmapCacheOption.OnLoad;
|
||||
image.StreamSource = ms;
|
||||
image.EndInit();
|
||||
image.Freeze();
|
||||
|
||||
return image;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
this.AppState.LogMsg("Error loading splash image.");
|
||||
}
|
||||
}
|
||||
return this.WabbajackLogo;
|
||||
// This takes a while, and is currently blocking
|
||||
this.PreloadSlideShow();
|
||||
})
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.StartWith(this.WabbajackLogo)
|
||||
.Subscribe(bitmap => this.Image = bitmap)
|
||||
.Subscribe()
|
||||
.DisposeWith(this.CompositeDisposable);
|
||||
|
||||
/// Wire slideshow updates
|
||||
var intervalSeconds = 10;
|
||||
// Compile all the sources that trigger a slideshow update
|
||||
// Merge all the sources that trigger a slideshow update
|
||||
Observable.Merge(
|
||||
// If user requests one manually
|
||||
this.SlideShowNextItemCommand.StartingExecution(),
|
||||
// If the natural timer fires
|
||||
Observable.Merge(
|
||||
// Start with an initial timer
|
||||
Observable.Return(Observable.Interval(TimeSpan.FromSeconds(intervalSeconds))),
|
||||
// but reset timer if user requests one
|
||||
this.SlideShowNextItemCommand.StartingExecution()
|
||||
.Select(_ => Observable.Interval(TimeSpan.FromSeconds(intervalSeconds))))
|
||||
// When a new timer comes in, swap to it
|
||||
.Switch()
|
||||
.Unit())
|
||||
// When filter switch enabled, fire an initial signal
|
||||
Observable.Interval(TimeSpan.FromSeconds(10))
|
||||
.Unit()
|
||||
// Only if enabled
|
||||
.FilterSwitch(this.WhenAny(x => x.Enable)),
|
||||
// If user requests one manually
|
||||
this.SlideShowNextItemCommand.StartingExecution())
|
||||
// When installing fire an initial signal
|
||||
.StartWith(Unit.Default)
|
||||
// Only subscribe to slideshow triggers if enabled and installing
|
||||
.FilterSwitch(
|
||||
Observable.CombineLatest(
|
||||
this.WhenAny(x => x.Enable),
|
||||
this.WhenAny(x => x.AppState.Installing),
|
||||
resultSelector: (enabled, installing) => enabled && installing))
|
||||
// Don't ever update more than once every half second.
|
||||
.Debounce(TimeSpan.FromMilliseconds(500), RxApp.MainThreadScheduler)
|
||||
// Only subscribe to slideshow triggers if installing
|
||||
.FilterSwitch(this.WhenAny(x => x.Installer.Installing))
|
||||
// Don't ever update more than once every half second. ToDo: Update to debounce
|
||||
.Throttle(TimeSpan.FromMilliseconds(500), RxApp.MainThreadScheduler)
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Subscribe(_ => this.UpdateSlideShowItem())
|
||||
.DisposeWith(this.CompositeDisposable);
|
||||
@ -203,7 +157,7 @@ namespace Wabbajack
|
||||
|
||||
if (!slide.IsNSFW || (slide.IsNSFW && ShowNSFW))
|
||||
{
|
||||
this.Image = AppState._noneImage;
|
||||
this.Image = UIUtils.BitmapImageFromResource("Wabbajack.Resources.none.jpg");
|
||||
if (slide.ImageURL != null && slide.Image != null)
|
||||
{
|
||||
if (!CachedSlides.ContainsKey(slide.ModID)) return;
|
||||
@ -212,7 +166,7 @@ namespace Wabbajack
|
||||
|
||||
this.ModName = slide.ModName;
|
||||
this.AuthorName = slide.ModAuthor;
|
||||
this.Summary = slide.ModDescription;
|
||||
this.Description = slide.ModDescription;
|
||||
this.NexusSiteURL = slide.ModURL;
|
||||
}
|
||||
|
@ -1,20 +1,12 @@
|
||||
<Window
|
||||
x:Class="Wabbajack.MainWindow"
|
||||
<UserControl
|
||||
x:Class="Wabbajack.CompilerView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Wabbajack"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="Wabbajack"
|
||||
Width="1280"
|
||||
Height="960"
|
||||
MinWidth="1024"
|
||||
MinHeight="768"
|
||||
Closing="Window_Closing"
|
||||
Icon="Icons/wabbajack.ico"
|
||||
ResizeMode="CanResize"
|
||||
Style="{StaticResource {x:Type Window}}"
|
||||
WindowStyle="ToolWindow"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<Viewbox Stretch="Uniform">
|
||||
<Grid Margin="4,0,4,0">
|
||||
@ -29,8 +21,9 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="640" />
|
||||
<ColumnDefinition Width="640" />
|
||||
<ColumnDefinition Width="638" />
|
||||
<ColumnDefinition Width="4" />
|
||||
<ColumnDefinition Width="638" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel
|
||||
@ -40,28 +33,101 @@
|
||||
<TextBlock
|
||||
FontSize="16"
|
||||
FontWeight="Bold"
|
||||
Text="{Binding Mode}" />
|
||||
Text="Compiling" />
|
||||
<TextBlock FontSize="16" Text=" : " />
|
||||
<TextBlock FontSize="16" Text="{Binding ModListName}" />
|
||||
<TextBlock FontSize="16" Text="{Binding MOProfile}" />
|
||||
</StackPanel>
|
||||
|
||||
<local:SlideshowView
|
||||
x:Name="Slideshow"
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="0,0,0,4"
|
||||
DataContext="{Binding Slideshow}" />
|
||||
Margin="0,8,0,8"
|
||||
IsEnabled="{Binding UIReady}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
Source="{Binding Image}"
|
||||
Stretch="Fill" />
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0" Content="Splash Screen Path:" />
|
||||
<local:FilePicker
|
||||
Grid.Column="1"
|
||||
Width="534"
|
||||
HorizontalAlignment="Left"
|
||||
DoExistsCheck="False"
|
||||
Filter="Banner image|*.png"
|
||||
IsEnabled="{Binding UIReady}"
|
||||
PathType="File"
|
||||
TargetPath="{Binding ImagePath}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<ScrollViewer
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Background="Transparent"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
IsEnabled="{Binding UIReady}"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Background="Transparent" Orientation="Vertical">
|
||||
<StackPanel.Resources>
|
||||
<Thickness
|
||||
x:Key="TitleMargin"
|
||||
Bottom="1"
|
||||
Left="5" />
|
||||
<Style
|
||||
x:Key="ValueStyle"
|
||||
BasedOn="{StaticResource MainTextBoxStyle}"
|
||||
TargetType="TextBox">
|
||||
<Setter Property="MaxLength" Value="50" />
|
||||
<Setter Property="AcceptsTab" Value="False" />
|
||||
<Setter Property="FontSize" Value="15" />
|
||||
<Setter Property="Margin" Value="0,0,0,6" />
|
||||
</Style>
|
||||
</StackPanel.Resources>
|
||||
<TextBlock Margin="{StaticResource TitleMargin}" Text="ModList Name" />
|
||||
<TextBox Style="{StaticResource ValueStyle}" Text="{Binding ModListName}" />
|
||||
<TextBlock Margin="{StaticResource TitleMargin}" Text="Author" />
|
||||
<TextBox Style="{StaticResource ValueStyle}" Text="{Binding AuthorName}" />
|
||||
<TextBlock Margin="{StaticResource TitleMargin}" Text="Description" />
|
||||
<TextBox
|
||||
Height="150"
|
||||
AcceptsReturn="True"
|
||||
AcceptsTab="False"
|
||||
MaxLength="700"
|
||||
Style="{StaticResource ValueStyle}"
|
||||
Text="{Binding Summary}"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock Margin="{StaticResource TitleMargin}" Text="Website" />
|
||||
<TextBox Style="{StaticResource ValueStyle}" Text="{Binding NexusSiteURL}" />
|
||||
<TextBlock
|
||||
Margin="{StaticResource TitleMargin}"
|
||||
Text="Readme Path"
|
||||
ToolTip="Path to a readme file." />
|
||||
<local:FilePicker
|
||||
DoExistsCheck="False"
|
||||
PathType="File"
|
||||
TargetPath="{Binding ReadMeText}"
|
||||
ToolTip="Path to a readme file." />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<ProgressBar
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="1,0,1,0"
|
||||
Background="#444444"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Value="{Binding QueueProgress}" />
|
||||
Value="{Binding MWVM.QueueProgress}" />
|
||||
|
||||
<!-- Log -->
|
||||
<TextBlock
|
||||
@ -73,7 +139,7 @@
|
||||
Grid.Row="4"
|
||||
Margin="0,0,2,0"
|
||||
local:AutoScrollBehavior.ScrollOnNewItem="True"
|
||||
ItemsSource="{Binding Log}" />
|
||||
ItemsSource="{Binding MWVM.Log}" />
|
||||
<!-- End Log -->
|
||||
|
||||
<!-- Location -->
|
||||
@ -81,12 +147,11 @@
|
||||
Grid.Row="5"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="0"
|
||||
Margin="-4,10,2,10"
|
||||
Margin="-4,10,0,10"
|
||||
HorizontalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
@ -96,35 +161,27 @@
|
||||
<Label
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Content="{Binding LocationLabel}" />
|
||||
<TextBox
|
||||
Content="Installation Location:" />
|
||||
<local:FilePicker
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
DoExistsCheck="False"
|
||||
IsEnabled="{Binding UIReady}"
|
||||
Text="{Binding Location, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />
|
||||
<Button
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
MinWidth="80"
|
||||
Command="{Binding ChangePathCommand}"
|
||||
Content="Select"
|
||||
IsEnabled="{Binding UIReady}" />
|
||||
PathType="Folder"
|
||||
SetTargetPathCommand="{Binding ChangePathCommand}"
|
||||
TargetPath="{Binding Location}" />
|
||||
<Label
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Content="Download Location:" />
|
||||
<TextBox
|
||||
<local:FilePicker
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
DoExistsCheck="False"
|
||||
IsEnabled="{Binding UIReady}"
|
||||
Text="{Binding DownloadLocation}" />
|
||||
<Button
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
MinWidth="80"
|
||||
Command="{Binding ChangeDownloadPathCommand}"
|
||||
Content="Select"
|
||||
IsEnabled="{Binding UIReady}" />
|
||||
PathType="Folder"
|
||||
SetTargetPathCommand="{Binding ChangeDownloadPathCommand}"
|
||||
TargetPath="{Binding DownloadLocation}" />
|
||||
</Grid>
|
||||
<!-- End Location -->
|
||||
|
||||
@ -132,18 +189,17 @@
|
||||
<!-- Work Queue Start -->
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Margin="2,16,0,8"
|
||||
Grid.Column="2"
|
||||
Margin="0,16,0,8"
|
||||
FontSize="14"
|
||||
Text="Work Queue:" />
|
||||
|
||||
<ListBox
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Grid.Column="2"
|
||||
Width="Auto"
|
||||
Margin="2,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding Status}">
|
||||
ItemsSource="{Binding MWVM.StatusList}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid HorizontalAlignment="Stretch">
|
||||
@ -184,8 +240,8 @@
|
||||
<Grid
|
||||
Grid.Row="5"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="1"
|
||||
Margin="2,10,0,10">
|
||||
Grid.Column="2"
|
||||
Margin="0,10,0,10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30" />
|
||||
<RowDefinition Height="30" />
|
||||
@ -206,4 +262,4 @@
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Viewbox>
|
||||
</Window>
|
||||
</UserControl>
|
@ -16,11 +16,11 @@ using System.Windows.Shapes;
|
||||
namespace Wabbajack
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for SlideshowView.xaml
|
||||
/// Interaction logic for CompilerView.xaml
|
||||
/// </summary>
|
||||
public partial class SlideshowView : UserControl
|
||||
public partial class CompilerView : UserControl
|
||||
{
|
||||
public SlideshowView()
|
||||
public CompilerView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
45
Wabbajack/Views/FilePicker.xaml
Normal file
@ -0,0 +1,45 @@
|
||||
<local:UserControlRx
|
||||
x:Class="Wabbajack.FilePicker"
|
||||
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="35"
|
||||
d:DesignWidth="400"
|
||||
BorderBrush="{StaticResource DarkBackgroundBrush}"
|
||||
mc:Ignorable="d">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox
|
||||
Grid.Column="0"
|
||||
Margin="0,0,-4,0"
|
||||
VerticalContentAlignment="Center"
|
||||
Background="{StaticResource DarkBackgroundBrush}"
|
||||
Text="{Binding TargetPath, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Visibility="{Binding ShowTextBoxInput, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
|
||||
<icon:PackIconMaterial
|
||||
Margin="0,4,4,4"
|
||||
Padding="0,3"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource WarningBrush}"
|
||||
Kind="Circle"
|
||||
ToolTip="Path does not exist"
|
||||
Visibility="{Binding Exists, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}" />
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
Command="{Binding SetTargetPathCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
|
||||
ToolTip="Set target path">
|
||||
<icon:PackIconMaterial
|
||||
Width="16"
|
||||
Height="12"
|
||||
Margin="4"
|
||||
Kind="DotsHorizontal" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</local:UserControlRx>
|
180
Wabbajack/Views/FilePicker.xaml.cs
Normal file
@ -0,0 +1,180 @@
|
||||
using Microsoft.WindowsAPICodePack.Dialogs;
|
||||
using ReactiveUI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for FilePicker.xaml
|
||||
/// </summary>
|
||||
public partial class FilePicker : UserControlRx
|
||||
{
|
||||
public enum PathTypeOptions
|
||||
{
|
||||
Off,
|
||||
Either,
|
||||
File,
|
||||
Folder
|
||||
}
|
||||
|
||||
public ICommand SetTargetPathCommand
|
||||
{
|
||||
get => (ICommand)GetValue(SetTargetPathCommandProperty);
|
||||
set => SetValue(SetTargetPathCommandProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty SetTargetPathCommandProperty = DependencyProperty.Register(nameof(SetTargetPathCommand), typeof(ICommand), typeof(FilePicker),
|
||||
new FrameworkPropertyMetadata(default(ICommand)));
|
||||
|
||||
public string TargetPath
|
||||
{
|
||||
get { return (string)GetValue(TargetPathProperty); }
|
||||
set { SetValue(TargetPathProperty, value); }
|
||||
}
|
||||
public static readonly DependencyProperty TargetPathProperty = DependencyProperty.Register(nameof(TargetPath), typeof(string), typeof(FilePicker),
|
||||
new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, WireNotifyPropertyChanged));
|
||||
|
||||
public bool ShowTextBoxInput
|
||||
{
|
||||
get => (bool)GetValue(ShowTextBoxInputProperty);
|
||||
set => SetValue(ShowTextBoxInputProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ShowTextBoxInputProperty = DependencyProperty.Register(nameof(ShowTextBoxInput), typeof(bool), typeof(FilePicker),
|
||||
new FrameworkPropertyMetadata(true));
|
||||
|
||||
public PathTypeOptions PathType
|
||||
{
|
||||
get => (PathTypeOptions)GetValue(PathTypeProperty);
|
||||
set => SetValue(PathTypeProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty PathTypeProperty = DependencyProperty.Register(nameof(PathType), typeof(PathTypeOptions), typeof(FilePicker),
|
||||
new FrameworkPropertyMetadata(PathTypeOptions.Off, WireNotifyPropertyChanged));
|
||||
|
||||
public bool Exists
|
||||
{
|
||||
get => (bool)GetValue(ExistsProperty);
|
||||
set => SetValue(ExistsProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty ExistsProperty = DependencyProperty.Register(nameof(Exists), typeof(bool), typeof(FilePicker),
|
||||
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, WireNotifyPropertyChanged));
|
||||
|
||||
public bool DoExistsCheck
|
||||
{
|
||||
get => (bool)GetValue(DoExistsCheckProperty);
|
||||
set => SetValue(DoExistsCheckProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty DoExistsCheckProperty = DependencyProperty.Register(nameof(DoExistsCheck), typeof(bool), typeof(FilePicker),
|
||||
new FrameworkPropertyMetadata(true, WireNotifyPropertyChanged));
|
||||
|
||||
public string PromptTitle
|
||||
{
|
||||
get => (string)GetValue(PromptTitleProperty);
|
||||
set => SetValue(PromptTitleProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty PromptTitleProperty = DependencyProperty.Register(nameof(PromptTitle), typeof(string), typeof(FilePicker),
|
||||
new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||
|
||||
public string Filter
|
||||
{
|
||||
get => (string)GetValue(FilterProperty);
|
||||
set => SetValue(FilterProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty FilterProperty = DependencyProperty.Register(nameof(Filter), typeof(string), typeof(FilePicker),
|
||||
new FrameworkPropertyMetadata(default(string)));
|
||||
|
||||
public FilePicker()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.SetTargetPathCommand = ReactiveCommand.Create(
|
||||
execute: () =>
|
||||
{
|
||||
string dirPath;
|
||||
if (File.Exists(this.TargetPath))
|
||||
{
|
||||
dirPath = System.IO.Path.GetDirectoryName(this.TargetPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
dirPath = this.TargetPath;
|
||||
}
|
||||
var dlg = new CommonOpenFileDialog();
|
||||
dlg.Title = this.PromptTitle;
|
||||
dlg.IsFolderPicker = this.PathType == PathTypeOptions.Folder;
|
||||
dlg.InitialDirectory = this.TargetPath;
|
||||
|
||||
dlg.AddToMostRecentlyUsedList = false;
|
||||
dlg.AllowNonFileSystemItems = false;
|
||||
dlg.DefaultDirectory = this.TargetPath;
|
||||
dlg.EnsureFileExists = true;
|
||||
dlg.EnsurePathExists = true;
|
||||
dlg.EnsureReadOnly = false;
|
||||
if (!string.IsNullOrWhiteSpace(this.Filter))
|
||||
{
|
||||
var split = this.Filter.Split('|');
|
||||
if (split.Length == 2)
|
||||
{
|
||||
dlg.Filters.Add(new CommonFileDialogFilter(split[0], split[1]));
|
||||
}
|
||||
}
|
||||
dlg.EnsureValidNames = true;
|
||||
dlg.Multiselect = false;
|
||||
dlg.ShowPlacesList = true;
|
||||
if (dlg.ShowDialog() != CommonFileDialogResult.Ok) return;
|
||||
this.TargetPath = dlg.FileName;
|
||||
});
|
||||
|
||||
// Check that file exists
|
||||
Observable.Interval(TimeSpan.FromSeconds(3))
|
||||
.FilterSwitch(
|
||||
Observable.CombineLatest(
|
||||
this.WhenAny(x => x.PathType),
|
||||
this.WhenAny(x => x.DoExistsCheck),
|
||||
resultSelector: (type, doExists) => type != PathTypeOptions.Off && doExists))
|
||||
.Unit()
|
||||
// Also do it when fields change
|
||||
.Merge(this.WhenAny(x => x.PathType).Unit())
|
||||
.Merge(this.WhenAny(x => x.DoExistsCheck).Unit())
|
||||
.CombineLatest(
|
||||
this.WhenAny(x => x.DoExistsCheck),
|
||||
this.WhenAny(x => x.PathType),
|
||||
this.WhenAny(x => x.TargetPath)
|
||||
.Throttle(TimeSpan.FromMilliseconds(200)),
|
||||
resultSelector: (_, DoExists, Type, Path) => (DoExists, Type, Path))
|
||||
// Refresh exists
|
||||
.Select(t =>
|
||||
{
|
||||
if (!t.DoExists) return true;
|
||||
switch (t.Type)
|
||||
{
|
||||
case PathTypeOptions.Either:
|
||||
return File.Exists(t.Path) || Directory.Exists(t.Path);
|
||||
case PathTypeOptions.File:
|
||||
return File.Exists(t.Path);
|
||||
case PathTypeOptions.Folder:
|
||||
return Directory.Exists(t.Path);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.DistinctUntilChanged()
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Subscribe(exists => this.Exists = exists)
|
||||
.DisposeWith(this.CompositeDisposable);
|
||||
}
|
||||
}
|
||||
}
|
772
Wabbajack/Views/InstallationView.xaml
Normal file
@ -0,0 +1,772 @@
|
||||
<UserControl
|
||||
x:Class="Wabbajack.InstallationView"
|
||||
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:mahapps="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DesignHeight="500"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<Color x:Key="TextBackgroundFill">#92000000</Color>
|
||||
<SolidColorBrush x:Key="TextBackgroundFillBrush" Color="{StaticResource TextBackgroundFill}" />
|
||||
<Color x:Key="TextBackgroundHoverFill">#DF000000</Color>
|
||||
<Style x:Key="BackgroundBlurStyle" TargetType="TextBlock">
|
||||
<Setter Property="Background" Value="{StaticResource TextBackgroundFillBrush}" />
|
||||
<Setter Property="Foreground" Value="Transparent" />
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsMouseOver, ElementName=TextHoverTrigger}" Value="True">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ColorAnimation
|
||||
Storyboard.TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)"
|
||||
To="{StaticResource TextBackgroundHoverFill}"
|
||||
Duration="0:0:0.06" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<ColorAnimation
|
||||
Storyboard.TargetProperty="(TextBlock.Background).(SolidColorBrush.Color)"
|
||||
To="{StaticResource TextBackgroundFill}"
|
||||
Duration="0:0:0.06" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Image}" Value="{x:Null}">
|
||||
<Setter Property="Visibility" Value="Hidden" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="SlideshowButton"
|
||||
BasedOn="{StaticResource CircleButtonStyle}"
|
||||
TargetType="ButtonBase">
|
||||
<Setter Property="Width" Value="40" />
|
||||
<Setter Property="Height" Value="40" />
|
||||
<Setter Property="Margin" Value="4" />
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="5" />
|
||||
<RowDefinition Height="4*" />
|
||||
<RowDefinition Height="*" MinHeight="150" />
|
||||
</Grid.RowDefinitions>
|
||||
<Rectangle
|
||||
x:Name="BorderEdgeFadeDown"
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="3">
|
||||
<Rectangle.Fill>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientStop Offset="0" Color="#191919" />
|
||||
<GradientStop Offset="0.4" Color="#00191919" />
|
||||
</LinearGradientBrush>
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
<!-- Slideshow -->
|
||||
<Border
|
||||
x:Name="Slideshow"
|
||||
Grid.Row="2"
|
||||
Margin="5,0,5,5"
|
||||
BorderBrush="#171717"
|
||||
BorderThickness="1,0,1,1"
|
||||
UseLayoutRounding="True">
|
||||
<Grid ClipToBounds="True">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="5*" />
|
||||
<ColumnDefinition Width="3*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Rectangle
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="4"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Fill="{StaticResource WindowBackgroundBrush}" />
|
||||
<Viewbox
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="4"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Stretch="UniformToFill">
|
||||
<Image Source="{Binding Image}" />
|
||||
</Viewbox>
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="4"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Width="60"
|
||||
Height="60"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Source="{Binding ModlistImage}" />
|
||||
<TextBlock
|
||||
x:Name="TitleTextShadow"
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="-20,15,40,-10"
|
||||
Padding="40,10"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Bottom"
|
||||
FontFamily="Lucida Sans"
|
||||
FontSize="65"
|
||||
FontWeight="Bold"
|
||||
Style="{StaticResource BackgroundBlurStyle}"
|
||||
Text="{Binding TitleText}"
|
||||
TextWrapping="WrapWithOverflow">
|
||||
<TextBlock.Effect>
|
||||
<BlurEffect Radius="85" />
|
||||
</TextBlock.Effect>
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
x:Name="ArtistTextShadow"
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="35,-10,-10,10"
|
||||
Padding="30,10"
|
||||
HorizontalAlignment="Left"
|
||||
FontFamily="Lucida Sans"
|
||||
FontSize="30"
|
||||
FontWeight="Bold"
|
||||
Style="{StaticResource BackgroundBlurStyle}"
|
||||
TextWrapping="WrapWithOverflow">
|
||||
<TextBlock.Effect>
|
||||
<BlurEffect Radius="55" />
|
||||
</TextBlock.Effect>
|
||||
<Run FontSize="15" Text="by" />
|
||||
<Run Text="{Binding AuthorText, Mode=OneWay}" />
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="20,25,20,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Bottom"
|
||||
FontFamily="Lucida Sans"
|
||||
FontSize="65"
|
||||
FontWeight="Bold"
|
||||
Text="{Binding TitleText}"
|
||||
TextWrapping="WrapWithOverflow">
|
||||
<TextBlock.Effect>
|
||||
<DropShadowEffect />
|
||||
</TextBlock.Effect>
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="55,0,20,20"
|
||||
FontFamily="Lucida Sans"
|
||||
FontSize="30"
|
||||
FontWeight="Bold"
|
||||
TextWrapping="Wrap">
|
||||
<TextBlock.Effect>
|
||||
<DropShadowEffect />
|
||||
</TextBlock.Effect>
|
||||
<Run FontSize="15" Text="by" />
|
||||
<Run Text="{Binding AuthorText, Mode=OneWay}" />
|
||||
</TextBlock>
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="0,20,25,0"
|
||||
HorizontalAlignment="Right">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.Effect>
|
||||
<DropShadowEffect
|
||||
BlurRadius="25"
|
||||
Opacity="1"
|
||||
Color="Black" />
|
||||
</Grid.Effect>
|
||||
<Grid.Style>
|
||||
<Style TargetType="Grid">
|
||||
<Setter Property="Opacity" Value="0" />
|
||||
<Style.Triggers>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding IsMouseOver, ElementName=Slideshow}" Value="True" />
|
||||
<Condition Binding="{Binding Installing}" Value="True" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<MultiDataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="1"
|
||||
Duration="0:0:0.12" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</MultiDataTrigger.EnterActions>
|
||||
<MultiDataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Opacity">
|
||||
<LinearDoubleKeyFrame KeyTime="0:0:0.3" Value="1" />
|
||||
<LinearDoubleKeyFrame KeyTime="0:0:0.42" Value="0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</MultiDataTrigger.ExitActions>
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Grid.Style>
|
||||
<Button
|
||||
Grid.Column="3"
|
||||
Width="60"
|
||||
Height="60"
|
||||
Margin="6"
|
||||
Background="{StaticResource BackgroundBrush}"
|
||||
Command="{Binding Slideshow.SlideShowNextItemCommand}"
|
||||
Style="{StaticResource CircleButtonStyle}"
|
||||
ToolTip="Skip to the next mod">
|
||||
<icon:PackIconFontAwesome
|
||||
Width="28"
|
||||
Height="28"
|
||||
Kind="ChevronRightSolid" />
|
||||
</Button>
|
||||
<ToggleButton
|
||||
x:Name="PlayPauseButton"
|
||||
Grid.Column="2"
|
||||
Margin="6"
|
||||
Background="{StaticResource BackgroundBrush}"
|
||||
IsChecked="{Binding Slideshow.Enable}">
|
||||
<ToggleButton.Style>
|
||||
<Style BasedOn="{StaticResource SlideshowButton}" TargetType="ToggleButton">
|
||||
<Setter Property="ToolTip" Value="Play slideshow" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Slideshow.Enable}" Value="True">
|
||||
<Setter Property="ToolTip" Value="Pause slideshow" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ToggleButton.Style>
|
||||
<icon:PackIconMaterial>
|
||||
<icon:PackIconMaterial.Style>
|
||||
<Style TargetType="icon:PackIconMaterial">
|
||||
<Setter Property="Kind" Value="Pause" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Slideshow.Enable}" Value="True">
|
||||
<Setter Property="Kind" Value="Play" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</icon:PackIconMaterial.Style>
|
||||
</icon:PackIconMaterial>
|
||||
</ToggleButton>
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
Margin="6"
|
||||
Background="{StaticResource BackgroundBrush}"
|
||||
Command="{Binding Slideshow.VisitNexusSiteCommand}"
|
||||
Style="{StaticResource SlideshowButton}"
|
||||
ToolTip="Open Nexus Website">
|
||||
<icon:PackIconMaterial
|
||||
Width="28"
|
||||
Height="28"
|
||||
Kind="Web" />
|
||||
</Button>
|
||||
<ToggleButton
|
||||
Grid.Column="0"
|
||||
Background="{StaticResource BackgroundBrush}"
|
||||
IsChecked="{Binding Slideshow.ShowNSFW}"
|
||||
ToolTip="Show NSFW mods">
|
||||
<ToggleButton.Style>
|
||||
<Style BasedOn="{StaticResource SlideshowButton}" TargetType="ToggleButton">
|
||||
<Setter Property="ToolTip" Value="Show NSFW mods" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Slideshow.ShowNSFW}" Value="True">
|
||||
<Setter Property="ToolTip" Value="Hide NSFW mods" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ToggleButton.Style>
|
||||
<Grid>
|
||||
<TextBlock
|
||||
Margin="4"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="Lucida Sans"
|
||||
FontSize="9"
|
||||
FontWeight="Bold"
|
||||
Text="NSFW" />
|
||||
<icon:PackIconOcticons
|
||||
Width="40"
|
||||
Height="40"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="#88FFFFFF"
|
||||
Kind="CircleSlash"
|
||||
Visibility="{Binding Slideshow.ShowNSFW, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}" />
|
||||
</Grid>
|
||||
</ToggleButton>
|
||||
</Grid>
|
||||
<TextBlock
|
||||
x:Name="DescriptionTextShadow"
|
||||
Grid.Row="2"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="1"
|
||||
Margin="-10,15,-5,15"
|
||||
Padding="30,10"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
FontFamily="Lucida Sans"
|
||||
FontSize="16"
|
||||
Style="{StaticResource BackgroundBlurStyle}"
|
||||
Text="{Binding Description}"
|
||||
TextAlignment="Right"
|
||||
TextWrapping="Wrap">
|
||||
<TextBlock.Effect>
|
||||
<BlurEffect Radius="55" />
|
||||
</TextBlock.Effect>
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="1"
|
||||
Margin="20,25,25,25"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
FontFamily="Lucida Sans"
|
||||
FontSize="16"
|
||||
Text="{Binding Description}"
|
||||
TextAlignment="Right"
|
||||
TextWrapping="Wrap">
|
||||
<TextBlock.Effect>
|
||||
<DropShadowEffect />
|
||||
</TextBlock.Effect>
|
||||
</TextBlock>
|
||||
<Rectangle
|
||||
x:Name="TextHoverTrigger"
|
||||
Grid.Row="2"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Fill="Transparent" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- Top progress bar -->
|
||||
<!-- Comes after slideshow control, so that any effects/overlap goes on top -->
|
||||
<Rectangle
|
||||
Grid.Row="2"
|
||||
Height="25"
|
||||
Margin="6,0"
|
||||
VerticalAlignment="Top"
|
||||
IsHitTestVisible="False">
|
||||
<Rectangle.Fill>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientStop Offset="0" Color="#AA000000" />
|
||||
<GradientStop Offset="1" Color="#00000000" />
|
||||
</LinearGradientBrush>
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
<Rectangle Grid.Row="1" Fill="{StaticResource BackgroundBrush}" />
|
||||
<mahapps:MetroProgressBar
|
||||
x:Name="BottomProgressBarDarkGlow"
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="2"
|
||||
Height="16"
|
||||
Margin="-4"
|
||||
VerticalAlignment="Top"
|
||||
Background="Transparent"
|
||||
BorderBrush="Transparent"
|
||||
Foreground="{StaticResource PrimaryVariantBrush}"
|
||||
Maximum="1"
|
||||
Value="{Binding ProgressPercent, Mode=OneWay}">
|
||||
<mahapps:MetroProgressBar.Effect>
|
||||
<BlurEffect Radius="25" />
|
||||
</mahapps:MetroProgressBar.Effect>
|
||||
</mahapps:MetroProgressBar>
|
||||
<mahapps:MetroProgressBar
|
||||
x:Name="BottomProgressBarBrightGlow"
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="2"
|
||||
Height="6"
|
||||
Margin="-4"
|
||||
VerticalAlignment="Top"
|
||||
Background="Transparent"
|
||||
BorderBrush="Transparent"
|
||||
Foreground="{StaticResource PrimaryBrush}"
|
||||
Maximum="1"
|
||||
Value="{Binding ProgressPercent, Mode=OneWay}">
|
||||
<mahapps:MetroProgressBar.Effect>
|
||||
<BlurEffect Radius="20" />
|
||||
</mahapps:MetroProgressBar.Effect>
|
||||
</mahapps:MetroProgressBar>
|
||||
<Grid x:Name="TopBarGrid" Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<mahapps:MetroProgressBar
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="4"
|
||||
Background="{StaticResource WindowBackgroundBrush}"
|
||||
BorderThickness="0"
|
||||
Foreground="Transparent"
|
||||
Maximum="1"
|
||||
Value="{Binding ProgressPercent, Mode=OneWay}" />
|
||||
<mahapps:MetroProgressBar
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="4"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Foreground="{StaticResource PrimaryVariantBrush}"
|
||||
Maximum="1"
|
||||
Opacity="{Binding ProgressPercent, Mode=OneWay}"
|
||||
Value="{Binding ProgressPercent, Mode=OneWay}" />
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Width="90"
|
||||
Margin="10,0,0,8"
|
||||
VerticalAlignment="Bottom"
|
||||
FontFamily="Lucida Sans"
|
||||
FontWeight="Black"
|
||||
TextAlignment="Right">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Text" Value="Configuring" />
|
||||
<Setter Property="FontSize" Value="15" />
|
||||
<Style.Triggers>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding InstallingMode}" Value="True" />
|
||||
<Condition Binding="{Binding Installing}" Value="True" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<MultiDataTrigger.Setters>
|
||||
<Setter Property="Text" Value="Installing" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
</MultiDataTrigger.Setters>
|
||||
</MultiDataTrigger>
|
||||
<MultiDataTrigger>
|
||||
<MultiDataTrigger.Conditions>
|
||||
<Condition Binding="{Binding InstallingMode}" Value="True" />
|
||||
<Condition Binding="{Binding Installing}" Value="False" />
|
||||
</MultiDataTrigger.Conditions>
|
||||
<MultiDataTrigger.Setters>
|
||||
<Setter Property="Text" Value="Installed" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
</MultiDataTrigger.Setters>
|
||||
</MultiDataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="15,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="Lucida Sans"
|
||||
FontSize="25"
|
||||
FontWeight="Black"
|
||||
Text="{Binding ModListName}" />
|
||||
<!-- Readd when Pause/Stop implementations added -->
|
||||
<!--<Button Grid.Column="2"
|
||||
ToolTip="Pause Installation"
|
||||
Margin="0,0,0,5"
|
||||
Width="50"
|
||||
Visibility="{Binding InstallingMode, Converter={StaticResource bool2VisibilityConverter}}">
|
||||
<icon:PackIconMaterial
|
||||
Kind="Pause" />
|
||||
</Button>
|
||||
<Button Grid.Column="3"
|
||||
ToolTip="Stop Installation"
|
||||
Margin="0,0,0,5"
|
||||
Width="50"
|
||||
Visibility="{Binding InstallingMode, Converter={StaticResource bool2VisibilityConverter}}" >
|
||||
<icon:PackIconFontAwesome
|
||||
Width="25"
|
||||
Height="25"
|
||||
Kind="TimesCircleSolid" />
|
||||
</Button>-->
|
||||
</Grid>
|
||||
<mahapps:MetroProgressBar
|
||||
x:Name="BottomProgressBar"
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="2"
|
||||
Height="5"
|
||||
VerticalAlignment="Top"
|
||||
Background="Transparent"
|
||||
BorderBrush="Transparent"
|
||||
Foreground="{StaticResource PrimaryBrush}"
|
||||
Maximum="1"
|
||||
Value="{Binding ProgressPercent, Mode=OneWay}" />
|
||||
<mahapps:MetroProgressBar
|
||||
x:Name="BottomProgressBarHighlight"
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="2"
|
||||
Height="5"
|
||||
VerticalAlignment="Top"
|
||||
Background="Transparent"
|
||||
BorderBrush="Transparent"
|
||||
Maximum="1"
|
||||
Value="{Binding ProgressPercent, Mode=OneWay}">
|
||||
<mahapps:MetroProgressBar.Foreground>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientStop Offset="0" Color="#CCFFFFFF" />
|
||||
<GradientStop Offset="0.3" Color="#00FFFFFF" />
|
||||
<GradientStop Offset="0.7" Color="#00FFFFFF" />
|
||||
<GradientStop Offset="1" Color="#CCFFFFFF" />
|
||||
</LinearGradientBrush>
|
||||
</mahapps:MetroProgressBar.Foreground>
|
||||
</mahapps:MetroProgressBar>
|
||||
<!-- Bottom Area -->
|
||||
<Grid
|
||||
Grid.Row="3"
|
||||
Margin="5,0,5,5"
|
||||
ClipToBounds="True"
|
||||
Visibility="{Binding InstallingMode, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="4" />
|
||||
<ColumnDefinition Width="2*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Grid.Column="0" Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Button
|
||||
Grid.Row="0"
|
||||
Margin="30,5"
|
||||
Command="{Binding OpenReadmeCommand}"
|
||||
Content="Readme"
|
||||
FontSize="20"
|
||||
ToolTip="Open the readme for the modlist" />
|
||||
<Button
|
||||
Grid.Row="1"
|
||||
Margin="30,5"
|
||||
Command="{Binding VisitWebsiteCommand}"
|
||||
Content="Website"
|
||||
FontSize="20"
|
||||
ToolTip="Open the webpage for the modlist" />
|
||||
<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" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="InstallationConfigurationView"
|
||||
Grid.Column="2"
|
||||
Background="{StaticResource WindowBackgroundBrush}">
|
||||
<Border
|
||||
x:Name="ConfigurationBackgroundHaze"
|
||||
Height="120"
|
||||
Background="{StaticResource PrimaryVariantBrush}"
|
||||
CornerRadius="50"
|
||||
Opacity="0.10">
|
||||
<Border.Effect>
|
||||
<BlurEffect Radius="45" />
|
||||
</Border.Effect>
|
||||
</Border>
|
||||
<ScrollViewer
|
||||
Margin="5"
|
||||
Background="Transparent"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
Visibility="{Binding InstallingMode, Converter={StaticResource bool2VisibilityConverter}, ConverterParameter=False}">
|
||||
<Grid Margin="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="40" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Border
|
||||
x:Name="BeginButtonPurpleGlow"
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="5"
|
||||
Width="76"
|
||||
Height="76"
|
||||
Margin="0,0,14,0"
|
||||
HorizontalAlignment="Right"
|
||||
Background="{StaticResource PrimaryVariantBrush}"
|
||||
CornerRadius="43">
|
||||
<Border.Effect>
|
||||
<BlurEffect Radius="10" />
|
||||
</Border.Effect>
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Opacity" Value="0.5" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsMouseOver, ElementName=BeginButton}" Value="True">
|
||||
<Setter Property="Opacity" Value="0.8" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
</Border>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="Installation Location"
|
||||
TextAlignment="Center" />
|
||||
<local:FilePicker
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DoExistsCheck="False"
|
||||
FontSize="14"
|
||||
PathType="Folder"
|
||||
PromptTitle="Select Installation directory"
|
||||
TargetPath="{Binding Location}" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="Download Location"
|
||||
TextAlignment="Center" />
|
||||
<local:FilePicker
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Height="30"
|
||||
VerticalAlignment="Center"
|
||||
DoExistsCheck="False"
|
||||
FontSize="14"
|
||||
PathType="Folder"
|
||||
PromptTitle="Select a location for MO2 downloads"
|
||||
TargetPath="{Binding DownloadLocation}" />
|
||||
<Button
|
||||
x:Name="BeginButton"
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="4"
|
||||
Width="55"
|
||||
Height="55"
|
||||
Margin="0,0,25,0"
|
||||
HorizontalAlignment="Right"
|
||||
Background="#222222"
|
||||
BorderBrush="{StaticResource SecondaryBrush}"
|
||||
Command="{Binding BeginCommand}"
|
||||
Style="{StaticResource CircleButtonStyle}">
|
||||
<icon:PackIconMaterial
|
||||
Width="25"
|
||||
Height="25"
|
||||
Margin="5,0,0,0"
|
||||
Kind="Play">
|
||||
<icon:PackIconMaterial.Style>
|
||||
<Style TargetType="icon:PackIconMaterial">
|
||||
<Setter Property="Foreground" Value="{StaticResource SecondaryBrush}" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsMouseOver, ElementName=BeginButton}" Value="True">
|
||||
<Setter Property="Foreground" Value="#00ffe7" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</icon:PackIconMaterial.Style>
|
||||
</icon:PackIconMaterial>
|
||||
<Button.Effect>
|
||||
<DropShadowEffect
|
||||
BlurRadius="15"
|
||||
ShadowDepth="0"
|
||||
Color="{StaticResource Secondary}" />
|
||||
</Button.Effect>
|
||||
</Button>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
<Rectangle
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Height="1"
|
||||
Margin="25,0"
|
||||
VerticalAlignment="Top"
|
||||
Fill="{StaticResource DarkBackgroundBrush}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
Grid.Row="3"
|
||||
Margin="5,0,5,5"
|
||||
Visibility="{Binding InstallingMode, Converter={StaticResource bool2VisibilityConverter}}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="4" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ListBox
|
||||
Grid.Column="0"
|
||||
local:AutoScrollBehavior.ScrollOnNewItem="True"
|
||||
ItemsSource="{Binding MWVM.Log}" />
|
||||
<ListBox
|
||||
x:Name="CpuListBox"
|
||||
Grid.Column="2"
|
||||
ItemsSource="{Binding MWVM.StatusList}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid HorizontalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ProgressBar
|
||||
Grid.Column="0"
|
||||
Width="100"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Value="{Binding Progress, Mode=OneTime}">
|
||||
<ProgressBar.Style>
|
||||
<Style TargetType="ProgressBar">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Progress, Mode=OneTime}" Value="0">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ProgressBar.Style>
|
||||
</ProgressBar>
|
||||
<TextBlock Grid.Column="1" Text=" CPU " />
|
||||
<TextBlock Grid.Column="2" Text="{Binding ID, Mode=OneTime}" />
|
||||
<TextBlock Grid.Column="3" Text=" - " />
|
||||
<TextBlock Grid.Column="4" Text="{Binding Msg, Mode=OneTime}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
28
Wabbajack/Views/InstallationView.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 InstallationView.xaml
|
||||
/// </summary>
|
||||
public partial class InstallationView : UserControl
|
||||
{
|
||||
public InstallationView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
29
Wabbajack/Views/MainWindow.xaml
Normal file
@ -0,0 +1,29 @@
|
||||
<Window
|
||||
x:Class="Wabbajack.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Wabbajack"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="Wabbajack"
|
||||
Width="1280"
|
||||
Height="960"
|
||||
MinWidth="850"
|
||||
MinHeight="650"
|
||||
Closing="Window_Closing"
|
||||
Icon="../Resources/Icons/wabbajack.ico"
|
||||
ResizeMode="CanResize"
|
||||
Style="{StaticResource {x:Type Window}}"
|
||||
WindowStyle="ToolWindow"
|
||||
mc:Ignorable="d">
|
||||
<ContentPresenter Content="{Binding ActivePane}">
|
||||
<ContentPresenter.Resources>
|
||||
<DataTemplate DataType="{x:Type local:CompilerVM}">
|
||||
<local:CompilerView />
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type local:InstallerVM}">
|
||||
<local:InstallationView />
|
||||
</DataTemplate>
|
||||
</ContentPresenter.Resources>
|
||||
</ContentPresenter>
|
||||
</Window>
|
51
Wabbajack/Views/MainWindow.xaml.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using Wabbajack.Common;
|
||||
using Application = System.Windows.Application;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private MainWindowVM _mwvm;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
|
||||
if (args.Length != 3) return;
|
||||
var modlistPath = args[2];
|
||||
Initialize(RunMode.Install, modlistPath);
|
||||
}
|
||||
|
||||
public MainWindow(RunMode mode, string source)
|
||||
{
|
||||
Initialize(mode, source);
|
||||
}
|
||||
|
||||
private void Initialize(RunMode mode, string source)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_mwvm = new MainWindowVM(mode, source, this);
|
||||
Utils.Log($"Wabbajack Build - {ThisAssembly.Git.Sha}");
|
||||
this.DataContext = _mwvm;
|
||||
}
|
||||
|
||||
internal bool ExitWhenClosing = true;
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
_mwvm.Dispose();
|
||||
if (ExitWhenClosing)
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
139
Wabbajack/Views/ModeSelectionWindow.xaml
Normal file
@ -0,0 +1,139 @@
|
||||
<Window
|
||||
x:Class="Wabbajack.ModeSelectionWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Wabbajack"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="Wabbajack"
|
||||
Width="1024"
|
||||
Height="800"
|
||||
Closing="Close_Window"
|
||||
Icon="../Resources/Icons/wabbajack.ico"
|
||||
ResizeMode="CanResize"
|
||||
Style="{StaticResource {x:Type Window}}"
|
||||
WindowStyle="ToolWindow"
|
||||
mc:Ignorable="d">
|
||||
<Grid Margin="20">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="30" />
|
||||
<ColumnDefinition Width="30" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30" />
|
||||
<RowDefinition Height="150" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="70" />
|
||||
<RowDefinition Height="70" />
|
||||
<RowDefinition Height="70" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Name="GitHub"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="5,0,0,0"
|
||||
HorizontalAlignment="Right"
|
||||
MouseLeftButtonDown="GitHub_MouseLeftButtonDown" />
|
||||
<Image
|
||||
Name="Patreon"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="5,0,0,0"
|
||||
MouseLeftButtonDown="Patreon_MouseLeftButtonDown" />
|
||||
<Image
|
||||
Name="Discord"
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Margin="5,0,0,0"
|
||||
MouseLeftButtonDown="Discord_MouseLeftButtonDown" />
|
||||
<Image
|
||||
Name="Banner"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="2,0,2,0"
|
||||
Stretch="Uniform" />
|
||||
<ListBox
|
||||
Grid.Row="2"
|
||||
Grid.ColumnSpan="3"
|
||||
ItemsSource="{Binding ModLists}"
|
||||
ScrollViewer.CanContentScroll="False"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
SelectedItem="{Binding Path=SelectedModList, Mode=TwoWay}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="200" />
|
||||
<ColumnDefinition Width="200" />
|
||||
<ColumnDefinition Width="200" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="20" />
|
||||
<RowDefinition Height="15" />
|
||||
<RowDefinition Height="150" />
|
||||
<RowDefinition Height="20" />
|
||||
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="4"
|
||||
Grid.Column="0"
|
||||
Source="{Binding Links.ImageUri}" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
FontSize="20"
|
||||
Text="{Binding Title}" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Text="{Binding Author}" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="4"
|
||||
HorizontalAlignment="Right"
|
||||
Text="{Binding Game}"
|
||||
TextAlignment="Right" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Grid.ColumnSpan="3"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Text="{Binding Description}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button Grid.Row="3" Grid.Column="2">More Info</Button>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Button
|
||||
Name="InstallModlist"
|
||||
Grid.Row="3"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="2"
|
||||
Click="InstallModlist_Click"
|
||||
IsEnabled="{Binding CanInstall}">
|
||||
<TextBlock FontSize="40">Download and Install</TextBlock>
|
||||
</Button>
|
||||
<Button
|
||||
Name="InstallFromList"
|
||||
Grid.Row="4"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="2"
|
||||
Click="InstallFromList_Click">
|
||||
<TextBlock FontSize="40">Install from Disk</TextBlock>
|
||||
</Button>
|
||||
<Button
|
||||
Name="CreateModlist"
|
||||
Grid.Row="5"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="2"
|
||||
Click="CreateModlist_Click">
|
||||
<TextBlock FontSize="40">Create a ModList</TextBlock>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Window>
|
@ -21,16 +21,16 @@ namespace Wabbajack
|
||||
public ModeSelectionWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
var bannerImage = UIUtils.BitmapImageFromResource("Wabbajack.UI.banner_small_dark.png");
|
||||
var bannerImage = UIUtils.BitmapImageFromResource("Wabbajack.Resources.banner_small_dark.png");
|
||||
Banner.Source = bannerImage;
|
||||
var patreonIcon = UIUtils.BitmapImageFromResource("Wabbajack.UI.Icons.patreon_light.png");
|
||||
var patreonIcon = UIUtils.BitmapImageFromResource("Wabbajack.Resources.Icons.patreon_light.png");
|
||||
Patreon.Source = patreonIcon;
|
||||
var githubIcon = UIUtils.BitmapImageFromResource("Wabbajack.UI.Icons.github_light.png");
|
||||
var githubIcon = UIUtils.BitmapImageFromResource("Wabbajack.Resources.Icons.github_light.png");
|
||||
GitHub.Source = githubIcon;
|
||||
var discordIcon = UIUtils.BitmapImageFromResource("Wabbajack.UI.Icons.discord.png");
|
||||
var discordIcon = UIUtils.BitmapImageFromResource("Wabbajack.Resources.Icons.discord.png");
|
||||
Discord.Source = discordIcon;
|
||||
|
||||
DataContext = new ModeSelectionWindowViewModel();
|
||||
DataContext = new ModeSelectionWindowVM();
|
||||
}
|
||||
|
||||
private void CreateModlist_Click(object sender, RoutedEventArgs e)
|
||||
@ -46,7 +46,7 @@ namespace Wabbajack
|
||||
// RunMode.Install,
|
||||
// UIUtils.OpenFileDialog($"Wabbajack Modlist (*{Consts.ModlistExtension})|*{Consts.ModlistExtension}"));
|
||||
|
||||
var result = ((ModeSelectionWindowViewModel)DataContext).Download();
|
||||
var result = ((ModeSelectionWindowVM)DataContext).Download();
|
||||
if (result != null)
|
||||
{
|
||||
OpenMainWindow(RunMode.Install, result);
|
21
Wabbajack/Views/TextViewer.xaml
Normal file
@ -0,0 +1,21 @@
|
||||
<Window
|
||||
x:Class="Wabbajack.TextViewer"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Wabbajack"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="TextViewer"
|
||||
Width="800"
|
||||
Height="450"
|
||||
Icon="../Resources/Icons/wabbajack.ico"
|
||||
Style="{StaticResource {x:Type Window}}"
|
||||
WindowStyle="ToolWindow"
|
||||
mc:Ignorable="d">
|
||||
<Grid>
|
||||
<TextBlock
|
||||
Name="TextBlock"
|
||||
FontSize="20"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</Window>
|
@ -1,6 +1,6 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace Wabbajack.UI
|
||||
namespace Wabbajack
|
||||
{
|
||||
public partial class TextViewer : Window
|
||||
{
|
48
Wabbajack/Views/UserControlRx.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using ReactiveUI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
public class UserControlRx : UserControl, IDisposable, IReactiveObject
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
public event PropertyChangingEventHandler PropertyChanging;
|
||||
|
||||
public void RaisePropertyChanging(PropertyChangingEventArgs args)
|
||||
{
|
||||
PropertyChanging?.Invoke(this, args);
|
||||
}
|
||||
|
||||
public void RaisePropertyChanged(PropertyChangedEventArgs args)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, args);
|
||||
}
|
||||
|
||||
private readonly Lazy<CompositeDisposable> _CompositeDisposable = new Lazy<CompositeDisposable>();
|
||||
public CompositeDisposable CompositeDisposable => _CompositeDisposable.Value;
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (_CompositeDisposable.IsValueCreated)
|
||||
{
|
||||
_CompositeDisposable.Value.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected static void WireNotifyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (!(d is UserControlRx control)) return;
|
||||
if (object.Equals(e.OldValue, e.NewValue)) return;
|
||||
control.RaisePropertyChanged(e.Property.Name);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\Costura.Fody.4.0.0\build\Costura.Fody.props" Condition="Exists('..\packages\Costura.Fody.4.0.0\build\Costura.Fody.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@ -32,6 +31,7 @@
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<XamlDebuggingInformation>True</XamlDebuggingInformation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
@ -54,7 +54,7 @@
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>UI\Icons\wabbajack.ico</ApplicationIcon>
|
||||
<ApplicationIcon>Resources\Icons\wabbajack.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug %28no commandargs%29|AnyCPU'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@ -96,107 +96,18 @@
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="AlphaFS, Version=2.2.0.0, Culture=neutral, PublicKeyToken=4d31a58f7d7ad5c9, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AlphaFS.2.2.6\lib\net452\AlphaFS.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="CommonMark, Version=0.1.0.0, Culture=neutral, PublicKeyToken=001ef8810438905d, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\CommonMark.NET.0.15.1\lib\net45\CommonMark.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Costura, Version=4.0.0.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Costura.Fody.4.0.0\lib\net40\Costura.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DynamicData, Version=6.13.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DynamicData.6.13.17\lib\net461\DynamicData.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=1.2.0.246, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SharpZipLib.1.2.0\lib\net45\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="K4os.Compression.LZ4, Version=1.1.11.0, Culture=neutral, PublicKeyToken=2186fa9121ef231d, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\K4os.Compression.LZ4.1.1.11\lib\net46\K4os.Compression.LZ4.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="K4os.Compression.LZ4.Streams, Version=1.1.11.0, Culture=neutral, PublicKeyToken=2186fa9121ef231d, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\K4os.Compression.LZ4.Streams.1.1.11\lib\net46\K4os.Compression.LZ4.Streams.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="K4os.Hash.xxHash, Version=1.0.6.0, Culture=neutral, PublicKeyToken=32cd54395057cec3, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\K4os.Hash.xxHash.1.0.6\lib\net46\K4os.Hash.xxHash.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MegaApiClient, Version=1.7.1.495, Culture=neutral, PublicKeyToken=0480d311efbeb4e2, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MegaApiClient.1.7.1\lib\net46\MegaApiClient.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAPICodePack, Version=1.1.3.3, Culture=neutral, PublicKeyToken=8985beaab7ea3f04, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft-WindowsAPICodePack-Core.1.1.3.3\lib\net452\Microsoft.WindowsAPICodePack.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.WindowsAPICodePack.Shell, Version=1.1.3.3, Culture=neutral, PublicKeyToken=8985beaab7ea3f04, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft-WindowsAPICodePack-Shell.1.1.3.3\lib\net452\Microsoft.WindowsAPICodePack.Shell.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json.Bson, Version=1.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.Bson.1.0.2\lib\net45\Newtonsoft.Json.Bson.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Pharmacist.Common, Version=1.2.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Pharmacist.Common.1.2.2\lib\netstandard2.0\Pharmacist.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationFramework.Aero" />
|
||||
<Reference Include="ReactiveUI, Version=10.4.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ReactiveUI.10.4.1\lib\net461\ReactiveUI.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ReactiveUI.Events.WPF, Version=10.4.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ReactiveUI.Events.WPF.10.4.1\lib\net461\ReactiveUI.Events.WPF.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ReactiveUI.WPF, Version=10.4.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ReactiveUI.WPF.10.4.1\lib\net461\ReactiveUI.WPF.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SharpCompress, Version=0.23.0.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SharpCompress.0.23.0\lib\net45\SharpCompress.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Syroot.KnownFolders, Version=1.2.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Syroot.Windows.IO.KnownFolders.1.2.1\lib\net452\Syroot.KnownFolders.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Splat, Version=9.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Splat.9.1.1\lib\net461\Splat.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Splat.Drawing, Version=9.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Splat.Drawing.9.1.1\lib\net461\Splat.Drawing.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Design" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Drawing.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Drawing.Primitives.4.3.0\lib\net45\System.Drawing.Primitives.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reactive, Version=4.2.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reactive.4.2.0\lib\net46\System.Reactive.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Security" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Transactions" />
|
||||
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Windows" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
@ -209,53 +120,63 @@
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="websocket-sharp, Version=1.0.4.0, Culture=neutral, PublicKeyToken=5660b08a1845a91e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\WebSocketSharpFork.1.0.4.0\lib\net35\websocket-sharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="YamlDotNet, Version=8.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\YamlDotNet.8.0.0\lib\net45\YamlDotNet.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="Converters\BoolToVisibilityConverter.cs" />
|
||||
<Compile Include="Views\CompilerView.xaml.cs">
|
||||
<DependentUpon>CompilerView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Converters\IsNotNullVisibilityConverter.cs" />
|
||||
<Compile Include="Enums\RunMode.cs" />
|
||||
<Compile Include="Extensions\ReactiveUIExt.cs" />
|
||||
<Compile Include="UI\DownloadWindow.xaml.cs">
|
||||
<Compile Include="Views\DownloadWindow.xaml.cs">
|
||||
<DependentUpon>DownloadWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UI\ModeSelectionWindowViewModel.cs" />
|
||||
<Compile Include="UI\ModListDefinition.cs" />
|
||||
<Compile Include="UI\SlideshowView.xaml.cs">
|
||||
<DependentUpon>SlideshowView.xaml</DependentUpon>
|
||||
<Compile Include="View Models\ModeSelectionWindowVM.cs" />
|
||||
<Compile Include="View Models\ModListDefinition.cs" />
|
||||
<Compile Include="Views\FilePicker.xaml.cs">
|
||||
<DependentUpon>FilePicker.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UI\ModlistPropertiesWindow.xaml.cs">
|
||||
<DependentUpon>ModlistPropertiesWindow.xaml</DependentUpon>
|
||||
<Compile Include="Views\InstallationView.xaml.cs">
|
||||
<DependentUpon>InstallationView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="UI\ModeSelectionWindow.xaml.cs">
|
||||
<Compile Include="Util\CPUStatus.cs" />
|
||||
<Compile Include="View Models\CompilerVM.cs" />
|
||||
<Compile Include="View Models\MainWindowVM.cs" />
|
||||
<Compile Include="Views\ModeSelectionWindow.xaml.cs">
|
||||
<DependentUpon>ModeSelectionWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Themes\LeftMarginMultiplierConverter.cs" />
|
||||
<Compile Include="Themes\TreeViewItemExtensions.cs" />
|
||||
<Compile Include="UI\SlideShow.cs" />
|
||||
<Compile Include="UI\TextViewer.xaml.cs">
|
||||
<Compile Include="Converters\LeftMarginMultiplierConverter.cs" />
|
||||
<Compile Include="Util\TreeViewItemExtensions.cs" />
|
||||
<Compile Include="View Models\SlideShow.cs" />
|
||||
<Compile Include="Views\TextViewer.xaml.cs">
|
||||
<DependentUpon>TextViewer.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Page Include="UI\DownloadWindow.xaml">
|
||||
<Compile Include="Views\UserControlRx.cs" />
|
||||
<Page Include="Views\CompilerView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="UI\SlideshowView.xaml">
|
||||
<Page Include="Views\DownloadWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="UI\MainWindow.xaml">
|
||||
<Page Include="Views\FilePicker.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Views\InstallationView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Views\MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
@ -263,17 +184,13 @@
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="AppState.cs" />
|
||||
<Compile Include="AutoScrollBehavior.cs" />
|
||||
<Compile Include="UI\MainWindow.xaml.cs">
|
||||
<Compile Include="View Models\InstallerVM.cs" />
|
||||
<Compile Include="Util\AutoScrollBehavior.cs" />
|
||||
<Compile Include="Views\MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Page Include="UI\ModeSelectionWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="UI\ModlistPropertiesWindow.xaml">
|
||||
<Page Include="Views\ModeSelectionWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
@ -281,9 +198,9 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="UI\TextViewer.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Page Include="Views\TextViewer.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -304,7 +221,6 @@
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
@ -344,44 +260,112 @@
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="UI\banner.png" />
|
||||
<Resource Include="Resources\Icons\wabbajack.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="UI\banner_small.png" />
|
||||
<EmbeddedResource Include="Resources\banner.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="UI\Icons\discord.png" />
|
||||
<EmbeddedResource Include="UI\Icons\github.png" />
|
||||
<EmbeddedResource Include="UI\Icons\patreon.png" />
|
||||
<EmbeddedResource Include="Resources\banner_small.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="UI\Icons\next.png" />
|
||||
<EmbeddedResource Include="Resources\Icons\discord.png" />
|
||||
<EmbeddedResource Include="Resources\Icons\github.png" />
|
||||
<EmbeddedResource Include="Resources\Icons\patreon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="UI\none.jpg" />
|
||||
<EmbeddedResource Include="Resources\Icons\next.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="UI\Icons\github_light.png" />
|
||||
<EmbeddedResource Include="UI\Icons\patreon_light.png" />
|
||||
<EmbeddedResource Include="Resources\none.jpg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="UI\Banner_Dark.png" />
|
||||
<EmbeddedResource Include="Resources\Icons\github_light.png" />
|
||||
<EmbeddedResource Include="Resources\Icons\patreon_light.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="UI\banner_small_dark.png" />
|
||||
<EmbeddedResource Include="Resources\Banner_Dark.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="UI\Icons\wabbajack.ico" />
|
||||
<EmbeddedResource Include="Resources\banner_small_dark.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AlphaFS">
|
||||
<Version>2.2.6</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="CommonMark.NET">
|
||||
<Version>0.15.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Costura.Fody">
|
||||
<Version>4.0.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="DynamicData">
|
||||
<Version>6.13.17</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Fody">
|
||||
<Version>5.1.1</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="GitInfo">
|
||||
<Version>2.0.20</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="K4os.Compression.LZ4.Streams">
|
||||
<Version>1.1.11</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MahApps.Metro">
|
||||
<Version>1.6.5</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MahApps.Metro.IconPacks">
|
||||
<Version>2.3.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MegaApiClient">
|
||||
<Version>1.7.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft-WindowsAPICodePack-Shell">
|
||||
<Version>1.1.3.3</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json">
|
||||
<Version>12.0.2</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json.Bson">
|
||||
<Version>1.0.2</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="protobuf-net">
|
||||
<Version>2.4.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ReactiveUI.Events.WPF">
|
||||
<Version>10.4.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ReactiveUI.WPF">
|
||||
<Version>10.4.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SharpCompress">
|
||||
<Version>0.23.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SharpZipLib">
|
||||
<Version>1.2.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Syroot.Windows.IO.KnownFolders">
|
||||
<Version>1.2.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Reactive">
|
||||
<Version>4.2.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="WebSocketSharpFork">
|
||||
<Version>1.0.4</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="WPFThemes.DarkBlend">
|
||||
<Version>1.0.8</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="YamlDotNet">
|
||||
<Version>7.0.0</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Wabba_Mouth.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\packages\Fody.5.1.1\build\Fody.targets" Condition="Exists('..\packages\Fody.5.1.1\build\Fody.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Fody.5.1.1\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.5.1.1\build\Fody.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Costura.Fody.4.0.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.4.0.0\build\Costura.Fody.props'))" />
|
||||
<Error Condition="!Exists('..\packages\GitInfo.2.0.20\build\GitInfo.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\GitInfo.2.0.20\build\GitInfo.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\GitInfo.2.0.20\build\GitInfo.targets" Condition="Exists('..\packages\GitInfo.2.0.20\build\GitInfo.targets')" />
|
||||
</Project>
|
@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="AlphaFS" version="2.2.6" targetFramework="net472" />
|
||||
<package id="CommonMark.NET" version="0.15.1" targetFramework="net472" />
|
||||
<package id="Costura.Fody" version="4.0.0" targetFramework="net472" />
|
||||
<package id="DynamicData" version="6.13.17" targetFramework="net472" />
|
||||
<package id="Fody" version="5.1.1" targetFramework="net472" developmentDependency="true" />
|
||||
<package id="GitInfo" version="2.0.20" targetFramework="net472" developmentDependency="true" />
|
||||
<package id="K4os.Compression.LZ4" version="1.1.11" targetFramework="net472" />
|
||||
<package id="K4os.Compression.LZ4.Streams" version="1.1.11" targetFramework="net472" />
|
||||
<package id="K4os.Hash.xxHash" version="1.0.6" targetFramework="net472" />
|
||||
<package id="MegaApiClient" version="1.7.1" targetFramework="net472" />
|
||||
<package id="Microsoft-WindowsAPICodePack-Core" version="1.1.3.3" targetFramework="net472" />
|
||||
<package id="Microsoft-WindowsAPICodePack-Shell" version="1.1.3.3" targetFramework="net472" />
|
||||
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net472" />
|
||||
<package id="Newtonsoft.Json.Bson" version="1.0.2" targetFramework="net472" />
|
||||
<package id="Pharmacist.Common" version="1.2.2" targetFramework="net472" />
|
||||
<package id="protobuf-net" version="2.4.0" targetFramework="net472" />
|
||||
<package id="ReactiveUI" version="10.4.1" targetFramework="net472" />
|
||||
<package id="ReactiveUI.Events.WPF" version="10.4.1" targetFramework="net472" />
|
||||
<package id="ReactiveUI.WPF" version="10.4.1" targetFramework="net472" />
|
||||
<package id="SharpCompress" version="0.23.0" targetFramework="net472" />
|
||||
<package id="SharpZipLib" version="1.2.0" targetFramework="net472" />
|
||||
<package id="Splat" version="9.1.1" targetFramework="net472" />
|
||||
<package id="Splat.Drawing" version="9.1.1" targetFramework="net472" />
|
||||
<package id="Syroot.Windows.IO.KnownFolders" version="1.2.1" targetFramework="net472" />
|
||||
<package id="System.Buffers" version="4.4.0" targetFramework="net472" />
|
||||
<package id="System.Drawing.Primitives" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Memory" version="4.5.3" targetFramework="net472" />
|
||||
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net472" />
|
||||
<package id="System.Reactive" version="4.2.0" targetFramework="net472" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net472" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.5.3" targetFramework="net472" />
|
||||
<package id="System.ValueTuple" version="4.5.0" targetFramework="net472" />
|
||||
<package id="WebSocketSharpFork" version="1.0.4.0" targetFramework="net472" />
|
||||
<package id="WPFThemes.DarkBlend" version="1.0.8" targetFramework="net472" />
|
||||
<package id="YamlDotNet" version="8.0.0" targetFramework="net472" />
|
||||
</packages>
|