2019-11-01 00:00:18 +00:00
|
|
|
using DynamicData;
|
2019-10-22 03:03:01 +00:00
|
|
|
using DynamicData.Binding;
|
|
|
|
using ReactiveUI;
|
2019-11-02 23:23:11 +00:00
|
|
|
using ReactiveUI.Fody.Helpers;
|
2019-10-22 02:12:55 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
2019-10-23 04:15:42 +00:00
|
|
|
using System.ComponentModel;
|
2019-10-25 04:26:29 +00:00
|
|
|
using System.IO;
|
2019-10-22 02:12:55 +00:00
|
|
|
using System.Linq;
|
2019-10-22 03:03:01 +00:00
|
|
|
using System.Reactive.Disposables;
|
|
|
|
using System.Reactive.Linq;
|
|
|
|
using System.Reactive.Subjects;
|
2019-10-22 02:12:55 +00:00
|
|
|
using System.Text;
|
|
|
|
using System.Threading.Tasks;
|
2019-10-23 04:15:42 +00:00
|
|
|
using System.Windows;
|
2019-10-22 03:03:01 +00:00
|
|
|
using Wabbajack.Common;
|
2019-10-22 02:12:55 +00:00
|
|
|
using Wabbajack.Lib;
|
|
|
|
|
|
|
|
namespace Wabbajack
|
|
|
|
{
|
2019-10-23 04:15:42 +00:00
|
|
|
/// <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>
|
2019-10-22 02:12:55 +00:00
|
|
|
public class MainWindowVM : ViewModel
|
|
|
|
{
|
2019-10-25 04:26:29 +00:00
|
|
|
public MainWindow MainWindow { get; }
|
2019-10-22 02:12:55 +00:00
|
|
|
|
2019-10-25 04:26:29 +00:00
|
|
|
private readonly ObservableAsPropertyHelper<ViewModel> _ActivePane;
|
|
|
|
public ViewModel ActivePane => _ActivePane.Value;
|
2019-10-22 02:12:55 +00:00
|
|
|
|
2019-11-02 23:23:11 +00:00
|
|
|
[Reactive]
|
|
|
|
public int QueueProgress { get; set; }
|
2019-10-22 03:03:01 +00:00
|
|
|
|
|
|
|
private readonly Subject<CPUStatus> _statusSubject = new Subject<CPUStatus>();
|
|
|
|
public IObservable<CPUStatus> StatusObservable => _statusSubject;
|
|
|
|
public ObservableCollectionExtended<CPUStatus> StatusList { get; } = new ObservableCollectionExtended<CPUStatus>();
|
|
|
|
|
2019-10-23 04:15:42 +00:00
|
|
|
private Subject<string> _logSubj = new Subject<string>();
|
|
|
|
public ObservableCollectionExtended<string> Log { get; } = new ObservableCollectionExtended<string>();
|
|
|
|
|
2019-11-02 23:23:11 +00:00
|
|
|
[Reactive]
|
|
|
|
public RunMode Mode { get; set; }
|
2019-10-25 04:26:29 +00:00
|
|
|
|
2019-11-02 22:21:05 +00:00
|
|
|
private readonly Lazy<CompilerVM> _Compiler;
|
|
|
|
private readonly Lazy<InstallerVM> _Installer;
|
|
|
|
|
2019-10-25 04:26:29 +00:00
|
|
|
public MainWindowVM(RunMode mode, string source, MainWindow mainWindow)
|
2019-10-22 02:12:55 +00:00
|
|
|
{
|
2019-10-25 04:26:29 +00:00
|
|
|
this.Mode = mode;
|
|
|
|
this.MainWindow = mainWindow;
|
2019-11-02 22:21:05 +00:00
|
|
|
this._Installer = new Lazy<InstallerVM>(() => new InstallerVM(this));
|
|
|
|
this._Compiler = new Lazy<CompilerVM>(() => new CompilerVM(this, source));
|
2019-10-25 04:26:29 +00:00
|
|
|
|
2019-10-23 04:15:42 +00:00
|
|
|
// 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));
|
|
|
|
|
2019-11-02 22:21:05 +00:00
|
|
|
// Wire mode to drive the active pane.
|
|
|
|
// Note: This is currently made into a derivative property driven by mode,
|
|
|
|
// but it can be easily changed into a normal property that can be set from anywhere if needed
|
2019-10-25 04:26:29 +00:00
|
|
|
this._ActivePane = this.WhenAny(x => x.Mode)
|
|
|
|
.Select<RunMode, ViewModel>(m =>
|
|
|
|
{
|
|
|
|
switch (m)
|
|
|
|
{
|
|
|
|
case RunMode.Compile:
|
2019-11-02 22:21:05 +00:00
|
|
|
return this._Compiler.Value;
|
2019-10-25 04:26:29 +00:00
|
|
|
case RunMode.Install:
|
2019-11-02 22:21:05 +00:00
|
|
|
return this._Installer.Value;
|
2019-10-25 04:26:29 +00:00
|
|
|
default:
|
|
|
|
return default;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.ToProperty(this, nameof(this.ActivePane));
|
|
|
|
this.WhenAny(x => x.ActivePane)
|
|
|
|
.ObserveOn(RxApp.TaskpoolScheduler)
|
|
|
|
.WhereCastable<ViewModel, InstallerVM>()
|
2019-10-30 19:45:42 +00:00
|
|
|
.Subscribe(vm => vm.ModListPath = source)
|
2019-10-25 04:26:29 +00:00
|
|
|
.DisposeWith(this.CompositeDisposable);
|
|
|
|
|
2019-10-30 19:45:42 +00:00
|
|
|
// 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);
|
2019-10-22 03:03:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void SetQueueSize(int max, int current)
|
|
|
|
{
|
|
|
|
if (max == 0)
|
|
|
|
max = 1;
|
|
|
|
QueueProgress = current * 100 / max;
|
2019-10-22 02:12:55 +00:00
|
|
|
}
|
2019-10-23 04:15:42 +00:00
|
|
|
|
|
|
|
public override void Dispose()
|
|
|
|
{
|
|
|
|
base.Dispose();
|
|
|
|
Utils.SetLoggerFn(s => { });
|
|
|
|
}
|
2019-10-22 02:12:55 +00:00
|
|
|
}
|
|
|
|
}
|