using DynamicData; using DynamicData.Binding; using ReactiveUI; using System; using System.Collections.Generic; using System.ComponentModel; 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 { /// /// 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. /// public class MainWindowVM : ViewModel { public AppState AppState { get; } private ViewModel _ActivePane; public ViewModel ActivePane { get => _ActivePane; set => this.RaiseAndSetIfChanged(ref _ActivePane, value); } private int _QueueProgress; public int QueueProgress { get => _QueueProgress; set => this.RaiseAndSetIfChanged(ref _QueueProgress, value); } private readonly Subject _statusSubject = new Subject(); public IObservable StatusObservable => _statusSubject; public ObservableCollectionExtended StatusList { get; } = new ObservableCollectionExtended(); private Subject _logSubj = new Subject(); public ObservableCollectionExtended Log { get; } = new ObservableCollectionExtended(); public MainWindowVM(RunMode mode) { // 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)); this.AppState = new AppState(this, mode); // 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.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 => { }); } } }