mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Slideshow update thread removed in favor of Rx
Will want to replace the throttle /w a debounce call. Also will want to remove unnecessary subject once command IsExecuting callbacks are researched
This commit is contained in:
parent
c808f9a4ed
commit
ff2010134c
@ -22,18 +22,17 @@ using Wabbajack.NexusApi;
|
|||||||
using Wabbajack.UI;
|
using Wabbajack.UI;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using DynamicData.Binding;
|
using DynamicData.Binding;
|
||||||
|
using System.Reactive;
|
||||||
|
|
||||||
namespace Wabbajack
|
namespace Wabbajack
|
||||||
{
|
{
|
||||||
public enum TaskMode { INSTALLING, BUILDING }
|
public enum TaskMode { INSTALLING, BUILDING }
|
||||||
internal class AppState : ViewModel, IDataErrorInfo
|
public class AppState : ViewModel, IDataErrorInfo
|
||||||
{
|
{
|
||||||
public const bool GcCollect = true;
|
public const bool GcCollect = true;
|
||||||
|
|
||||||
private SlideShow _slideShow;
|
private SlideShow _slideShow;
|
||||||
|
|
||||||
public bool installing = false;
|
|
||||||
|
|
||||||
private string _mo2Folder;
|
private string _mo2Folder;
|
||||||
|
|
||||||
private readonly BitmapImage _wabbajackLogo = UIUtils.BitmapImageFromResource("Wabbajack.UI.banner.png");
|
private readonly BitmapImage _wabbajackLogo = UIUtils.BitmapImageFromResource("Wabbajack.UI.banner.png");
|
||||||
@ -69,6 +68,9 @@ namespace Wabbajack
|
|||||||
private string _HTMLReport;
|
private string _HTMLReport;
|
||||||
public string HTMLReport { get => _HTMLReport; set => this.RaiseAndSetIfChanged(ref _HTMLReport, value); }
|
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
|
// Command properties
|
||||||
public IReactiveCommand ChangePathCommand => ReactiveCommand.Create(ExecuteChangePath);
|
public IReactiveCommand ChangePathCommand => ReactiveCommand.Create(ExecuteChangePath);
|
||||||
public IReactiveCommand ChangeDownloadPathCommand => ReactiveCommand.Create(ExecuteChangeDownloadPath);
|
public IReactiveCommand ChangeDownloadPathCommand => ReactiveCommand.Create(ExecuteChangeDownloadPath);
|
||||||
@ -77,7 +79,10 @@ namespace Wabbajack
|
|||||||
public IReactiveCommand VisitNexusSiteCommand => ReactiveCommand.Create(VisitNexusSite);
|
public IReactiveCommand VisitNexusSiteCommand => ReactiveCommand.Create(VisitNexusSite);
|
||||||
public IReactiveCommand OpenReadmeCommand { get; }
|
public IReactiveCommand OpenReadmeCommand { get; }
|
||||||
public IReactiveCommand OpenModListPropertiesCommand => ReactiveCommand.Create(OpenModListProperties);
|
public IReactiveCommand OpenModListPropertiesCommand => ReactiveCommand.Create(OpenModListProperties);
|
||||||
public IReactiveCommand SlideShowNextItemCommand { get; }
|
// ToDo
|
||||||
|
// This subject is not desirable. Need to research why command's IsExecuting observable not firing, as we'd prefer to hook onto that instead
|
||||||
|
private Subject<Unit> _slideshowCommandTriggeredSubject = new Subject<Unit>();
|
||||||
|
public ReactiveCommand<Unit, Unit> SlideShowNextItemCommand => ReactiveCommand.Create(() => _slideshowCommandTriggeredSubject.OnNext(Unit.Default));
|
||||||
|
|
||||||
public AppState()
|
public AppState()
|
||||||
{
|
{
|
||||||
@ -121,7 +126,6 @@ namespace Wabbajack
|
|||||||
.DisposeWith(this.CompositeDisposable);
|
.DisposeWith(this.CompositeDisposable);
|
||||||
|
|
||||||
_slideShow = new SlideShow(this, true);
|
_slideShow = new SlideShow(this, true);
|
||||||
this.SlideShowNextItemCommand = ReactiveCommand.Create(_slideShow.UpdateSlideShowItem);
|
|
||||||
|
|
||||||
// Update splashscreen when modlist changes
|
// Update splashscreen when modlist changes
|
||||||
Observable.CombineLatest(
|
Observable.CombineLatest(
|
||||||
@ -170,10 +174,24 @@ namespace Wabbajack
|
|||||||
.Subscribe(bitmap => this.SplashScreenImage = bitmap)
|
.Subscribe(bitmap => this.SplashScreenImage = bitmap)
|
||||||
.DisposeWith(this.CompositeDisposable);
|
.DisposeWith(this.CompositeDisposable);
|
||||||
|
|
||||||
// Trigger a slideshow update if enabled
|
/// Wire slideshow updates
|
||||||
this.WhenAny(x => x.EnableSlideShow)
|
// Merge all the sources that trigger a slideshow update
|
||||||
.Skip(1) // Don't fire initially
|
Observable.Merge(
|
||||||
.WhenAny(enable => enable)
|
// If the natural timer fires
|
||||||
|
Observable.Interval(TimeSpan.FromSeconds(10)).Unit(),
|
||||||
|
// If user requests one manually
|
||||||
|
_slideshowCommandTriggeredSubject)
|
||||||
|
// When enabled, fire an initial signal
|
||||||
|
.StartWith(Unit.Default)
|
||||||
|
// Only subscribe to slideshow triggers if enabled and installing
|
||||||
|
.FilterSwitch(
|
||||||
|
Observable.CombineLatest(
|
||||||
|
this.WhenAny(x => x.EnableSlideShow),
|
||||||
|
this.WhenAny(x => x.Installing),
|
||||||
|
resultSelector: (enabled, installing) => enabled && 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(_ => _slideShow.UpdateSlideShowItem())
|
.Subscribe(_ => _slideShow.UpdateSlideShowItem())
|
||||||
.DisposeWith(this.CompositeDisposable);
|
.DisposeWith(this.CompositeDisposable);
|
||||||
|
|
||||||
@ -192,17 +210,8 @@ namespace Wabbajack
|
|||||||
.Bind(this.Status)
|
.Bind(this.Status)
|
||||||
.Subscribe()
|
.Subscribe()
|
||||||
.DisposeWith(this.CompositeDisposable);
|
.DisposeWith(this.CompositeDisposable);
|
||||||
|
|
||||||
slideshowThread = new Thread(UpdateLoop)
|
|
||||||
{
|
|
||||||
Priority = ThreadPriority.BelowNormal,
|
|
||||||
IsBackground = true
|
|
||||||
};
|
|
||||||
slideshowThread.Start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime lastSlideShowUpdate = new DateTime();
|
|
||||||
|
|
||||||
public ObservableCollection<string> Log { get; } = new ObservableCollection<string>();
|
public ObservableCollection<string> Log { get; } = new ObservableCollection<string>();
|
||||||
|
|
||||||
private string _Location;
|
private string _Location;
|
||||||
@ -317,7 +326,6 @@ namespace Wabbajack
|
|||||||
public string SplashScreenSummary { get => _SplashScreenSummary; set => this.RaiseAndSetIfChanged(ref _SplashScreenSummary, value); }
|
public string SplashScreenSummary { get => _SplashScreenSummary; set => this.RaiseAndSetIfChanged(ref _SplashScreenSummary, value); }
|
||||||
private bool _splashShowNSFW = false;
|
private bool _splashShowNSFW = false;
|
||||||
public bool SplashShowNSFW { get => _splashShowNSFW; set => this.RaiseAndSetIfChanged(ref _splashShowNSFW, value); }
|
public bool SplashShowNSFW { get => _splashShowNSFW; set => this.RaiseAndSetIfChanged(ref _splashShowNSFW, value); }
|
||||||
private readonly Thread slideshowThread = null;
|
|
||||||
|
|
||||||
public string Error => "Error";
|
public string Error => "Error";
|
||||||
|
|
||||||
@ -355,23 +363,6 @@ namespace Wabbajack
|
|||||||
return validationMessage;
|
return validationMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateLoop()
|
|
||||||
{
|
|
||||||
while (Running)
|
|
||||||
{
|
|
||||||
if (_slideShow.SlidesQueue.Any())
|
|
||||||
{
|
|
||||||
if (DateTime.Now - lastSlideShowUpdate > TimeSpan.FromSeconds(10))
|
|
||||||
{
|
|
||||||
_slideShow.UpdateSlideShowItem();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Thread.Sleep(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Running { get; set; } = true;
|
|
||||||
|
|
||||||
public void LogMsg(string msg)
|
public void LogMsg(string msg)
|
||||||
{
|
{
|
||||||
Application.Current.Dispatcher.Invoke(() => Log.Add(msg));
|
Application.Current.Dispatcher.Invoke(() => Log.Add(msg));
|
||||||
@ -425,7 +416,7 @@ namespace Wabbajack
|
|||||||
UIReady = false;
|
UIReady = false;
|
||||||
if (Mode == TaskMode.INSTALLING)
|
if (Mode == TaskMode.INSTALLING)
|
||||||
{
|
{
|
||||||
installing = true;
|
this.Installing = true;
|
||||||
var installer = new Installer(this.ModListPath, this.ModList, Location)
|
var installer = new Installer(this.ModListPath, this.ModList, Location)
|
||||||
{
|
{
|
||||||
DownloadFolder = DownloadLocation
|
DownloadFolder = DownloadLocation
|
||||||
@ -447,9 +438,7 @@ namespace Wabbajack
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
UIReady = true;
|
UIReady = true;
|
||||||
Running = false;
|
this.Installing = false;
|
||||||
installing = false;
|
|
||||||
slideshowThread.Abort();
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
using System.Reactive;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using DynamicData.Kernel;
|
using DynamicData.Kernel;
|
||||||
@ -29,6 +30,38 @@ namespace Wabbajack
|
|||||||
return source.ObserveOn(RxApp.MainThreadScheduler);
|
return source.ObserveOn(RxApp.MainThreadScheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IObservable<Unit> Unit<T>(this IObservable<T> source)
|
||||||
|
{
|
||||||
|
return source.Select(_ => System.Reactive.Unit.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convenience operator to subscribe to the source observable, only when a second "switch" observable is on.
|
||||||
|
/// When the switch is on, the source will be subscribed to, and its updates passed through.
|
||||||
|
/// When the switch is off, the subscription to the source observable will be stopped, and no signal will be published.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="source">Source observable to subscribe to if on</param>
|
||||||
|
/// <param name="filterSwitch">On/Off signal of whether to subscribe to source observable</param>
|
||||||
|
/// <returns>Observable that publishes data from source, if the switch is on.</returns>
|
||||||
|
public static IObservable<T> FilterSwitch<T>(this IObservable<T> source, IObservable<bool> filterSwitch)
|
||||||
|
{
|
||||||
|
return filterSwitch
|
||||||
|
.DistinctUntilChanged()
|
||||||
|
.Select(on =>
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
{
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Observable.Empty<T>();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.Switch();
|
||||||
|
}
|
||||||
|
|
||||||
/// These snippets were provided by RolandPheasant (author of DynamicData)
|
/// 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.
|
/// They'll be going into the official library at some point, but are here for now.
|
||||||
#region Dynamic Data EnsureUniqueChanges
|
#region Dynamic Data EnsureUniqueChanges
|
||||||
|
@ -149,7 +149,7 @@
|
|||||||
Height="30"
|
Height="30"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Command="{Binding SlideShowNextItemCommand}"
|
Command="{Binding SlideShowNextItemCommand}"
|
||||||
ToolTip="Spamming this button will result in problems">
|
ToolTip="Skip to next slide">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<Image Source="{Binding NextIcon}" Stretch="Fill" />
|
<Image Source="{Binding NextIcon}" Stretch="Fill" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
@ -68,7 +68,6 @@ namespace Wabbajack
|
|||||||
MessageBoxImage.Error);
|
MessageBoxImage.Error);
|
||||||
Dispatcher.Invoke(() =>
|
Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
context.Running = false;
|
|
||||||
ExitWhenClosing = false;
|
ExitWhenClosing = false;
|
||||||
var window = new ModeSelectionWindow
|
var window = new ModeSelectionWindow
|
||||||
{
|
{
|
||||||
|
@ -74,7 +74,7 @@ namespace Wabbajack.UI
|
|||||||
|
|
||||||
public void UpdateSlideShowItem()
|
public void UpdateSlideShowItem()
|
||||||
{
|
{
|
||||||
if (!_appState.EnableSlideShow || !_appState.installing || SlidesQueue.Count==0) return;
|
if (SlidesQueue.Count == 0) return;
|
||||||
var slide = SlidesQueue.Peek();
|
var slide = SlidesQueue.Peek();
|
||||||
|
|
||||||
while (CachedSlides.Count >= MaxCacheSize)
|
while (CachedSlides.Count >= MaxCacheSize)
|
||||||
@ -97,12 +97,9 @@ namespace Wabbajack.UI
|
|||||||
{
|
{
|
||||||
_appState.SplashScreenImage = _appState._noneImage;
|
_appState.SplashScreenImage = _appState._noneImage;
|
||||||
if (slide.ImageURL != null && slide.Image != null)
|
if (slide.ImageURL != null && slide.Image != null)
|
||||||
{
|
|
||||||
System.Windows.Application.Current.Dispatcher.Invoke(() =>
|
|
||||||
{
|
{
|
||||||
if (!CachedSlides.ContainsKey(slide.ModID)) return;
|
if (!CachedSlides.ContainsKey(slide.ModID)) return;
|
||||||
_appState.SplashScreenImage = slide.Image;
|
_appState.SplashScreenImage = slide.Image;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_appState.SplashScreenModName = slide.ModName;
|
_appState.SplashScreenModName = slide.ModName;
|
||||||
@ -111,8 +108,6 @@ namespace Wabbajack.UI
|
|||||||
_appState._nexusSiteURL = slide.ModURL;
|
_appState._nexusSiteURL = slide.ModURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_appState.lastSlideShowUpdate = DateTime.Now;
|
|
||||||
|
|
||||||
SlidesQueue.Dequeue();
|
SlidesQueue.Dequeue();
|
||||||
QueueRandomSlide(false, true);
|
QueueRandomSlide(false, true);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user