From cafba5ff81f699cf11c5de4ea42035e80a23848e Mon Sep 17 00:00:00 2001 From: Justin Swanson Date: Sun, 17 Nov 2019 01:04:53 -0600 Subject: [PATCH] FilePickerVM ExistCheckOption /w IfNotEmpty features Some paths aren't an error condition when the path is completely empty --- Wabbajack.Common/Extensions/RxExt.cs | 26 +++++++ .../View Models/Compilers/MO2CompilerVM.cs | 4 +- .../Compilers/ModlistSettingsEditorVM.cs | 4 +- .../View Models/Compilers/VortexCompilerVM.cs | 6 +- Wabbajack/View Models/FilePickerVM.cs | 75 ++++++++++++++----- Wabbajack/View Models/InstallerVM.cs | 4 +- 6 files changed, 92 insertions(+), 27 deletions(-) diff --git a/Wabbajack.Common/Extensions/RxExt.cs b/Wabbajack.Common/Extensions/RxExt.cs index 25ac87b2..0018d3a8 100644 --- a/Wabbajack.Common/Extensions/RxExt.cs +++ b/Wabbajack.Common/Extensions/RxExt.cs @@ -60,6 +60,32 @@ namespace Wabbajack .Switch(); } + /// + /// 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. + /// + /// Source observable to subscribe to if on + /// On/Off signal of whether to subscribe to source observable + /// Value to fire when switching off + /// Observable that publishes data from source, if the switch is on. + public static IObservable FilterSwitch(this IObservable source, IObservable filterSwitch, T valueWhenOff) + { + return filterSwitch + .DistinctUntilChanged() + .Select(on => + { + if (on) + { + return source; + } + else + { + return Observable.Return(valueWhenOff); + } + }) + .Switch(); + } /// Inspiration: /// http://reactivex.io/documentation/operators/debounce.html diff --git a/Wabbajack/View Models/Compilers/MO2CompilerVM.cs b/Wabbajack/View Models/Compilers/MO2CompilerVM.cs index 6555d608..5cc20243 100644 --- a/Wabbajack/View Models/Compilers/MO2CompilerVM.cs +++ b/Wabbajack/View Models/Compilers/MO2CompilerVM.cs @@ -40,13 +40,13 @@ namespace Wabbajack { this.ModlistLocation = new FilePickerVM() { - DoExistsCheck = true, + ExistCheckOption = FilePickerVM.ExistCheckOptions.On, PathType = FilePickerVM.PathTypeOptions.File, PromptTitle = "Select Modlist" }; this.DownloadLocation = new FilePickerVM() { - DoExistsCheck = true, + ExistCheckOption = FilePickerVM.ExistCheckOptions.On, PathType = FilePickerVM.PathTypeOptions.Folder, PromptTitle = "Select Download Location", }; diff --git a/Wabbajack/View Models/Compilers/ModlistSettingsEditorVM.cs b/Wabbajack/View Models/Compilers/ModlistSettingsEditorVM.cs index 42066044..a6bc955d 100644 --- a/Wabbajack/View Models/Compilers/ModlistSettingsEditorVM.cs +++ b/Wabbajack/View Models/Compilers/ModlistSettingsEditorVM.cs @@ -36,7 +36,7 @@ namespace Wabbajack this.settings = settings; this.ImagePath = new FilePickerVM() { - DoExistsCheck = false, + ExistCheckOption = FilePickerVM.ExistCheckOptions.IfNotEmpty, PathType = FilePickerVM.PathTypeOptions.File, Filters = { @@ -46,7 +46,7 @@ namespace Wabbajack this.ReadMeText = new FilePickerVM() { PathType = FilePickerVM.PathTypeOptions.File, - DoExistsCheck = false, + ExistCheckOption = FilePickerVM.ExistCheckOptions.IfNotEmpty, }; } diff --git a/Wabbajack/View Models/Compilers/VortexCompilerVM.cs b/Wabbajack/View Models/Compilers/VortexCompilerVM.cs index d31dd17f..44f9bff0 100644 --- a/Wabbajack/View Models/Compilers/VortexCompilerVM.cs +++ b/Wabbajack/View Models/Compilers/VortexCompilerVM.cs @@ -53,19 +53,19 @@ namespace Wabbajack { this.GameLocation = new FilePickerVM() { - DoExistsCheck = true, + ExistCheckOption = FilePickerVM.ExistCheckOptions.On, PathType = FilePickerVM.PathTypeOptions.Folder, PromptTitle = "Select Game Folder Location" }; this.DownloadsLocation = new FilePickerVM() { - DoExistsCheck = true, + ExistCheckOption = FilePickerVM.ExistCheckOptions.On, PathType = FilePickerVM.PathTypeOptions.Folder, PromptTitle = "Select Downloads Folder" }; this.StagingLocation = new FilePickerVM() { - DoExistsCheck = true, + ExistCheckOption = FilePickerVM.ExistCheckOptions.On, PathType = FilePickerVM.PathTypeOptions.Folder, PromptTitle = "Select Staging Folder" }; diff --git a/Wabbajack/View Models/FilePickerVM.cs b/Wabbajack/View Models/FilePickerVM.cs index c216cdb7..3e2fa7aa 100644 --- a/Wabbajack/View Models/FilePickerVM.cs +++ b/Wabbajack/View Models/FilePickerVM.cs @@ -23,6 +23,13 @@ namespace Wabbajack Folder } + public enum ExistCheckOptions + { + Off, + IfNotEmpty, + On + } + public object Parent { get; } [Reactive] @@ -38,7 +45,7 @@ namespace Wabbajack public PathTypeOptions PathType { get; set; } [Reactive] - public bool DoExistsCheck { get; set; } + public ExistCheckOptions ExistCheckOption { get; set; } [Reactive] public IObservable AdditionalError { get; set; } @@ -63,28 +70,60 @@ namespace Wabbajack this.SetTargetPathCommand = ConstructTypicalPickerCommand(); // Check that file exists - this._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) + + var existsCheckTuple = Observable.CombineLatest( + this.WhenAny(x => x.ExistCheckOption), + this.WhenAny(x => x.PathType), + this.WhenAny(x => x.TargetPath) // Dont want to debounce the initial value, because we know it's null .Skip(1) - .Debounce(TimeSpan.FromMilliseconds(200)), - resultSelector: (_, DoExists, Type, Path) => (DoExists, Type, Path)) + .Debounce(TimeSpan.FromMilliseconds(200)) + .StartWith(default(string)), + resultSelector: (ExistsOption, Type, Path) => (ExistsOption, Type, Path)) + .Publish() + .RefCount(); + + this._Exists = Observable.Interval(TimeSpan.FromSeconds(3)) + // Only check exists on timer if desired + .FilterSwitch(existsCheckTuple + .Select(t => + { + // Don't do exists type if we don't know what path type we're tracking + if (t.Type == PathTypeOptions.Off) return false; + switch (t.ExistsOption) + { + case ExistCheckOptions.Off: + return false; + case ExistCheckOptions.IfNotEmpty: + return !string.IsNullOrWhiteSpace(t.Path); + case ExistCheckOptions.On: + return true; + default: + throw new NotImplementedException(); + } + })) + .Unit() + // Also check though, when fields change + .Merge(this.WhenAny(x => x.PathType).Unit()) + .Merge(this.WhenAny(x => x.ExistCheckOption).Unit()) + .Merge(this.WhenAny(x => x.TargetPath).Unit()) + // Signaled to check, get latest params for actual use + .CombineLatest(existsCheckTuple, + resultSelector: (_, tuple) => tuple) // Refresh exists .Select(t => { - if (!t.DoExists) return true; + switch (t.ExistsOption) + { + case ExistCheckOptions.IfNotEmpty: + if (string.IsNullOrWhiteSpace(t.Path)) return true; + break; + case ExistCheckOptions.On: + break; + case ExistCheckOptions.Off: + default: + return true; + } switch (t.Type) { case PathTypeOptions.Either: diff --git a/Wabbajack/View Models/InstallerVM.cs b/Wabbajack/View Models/InstallerVM.cs index 1f62ded0..1bc4e49a 100644 --- a/Wabbajack/View Models/InstallerVM.cs +++ b/Wabbajack/View Models/InstallerVM.cs @@ -99,7 +99,7 @@ namespace Wabbajack this.Location = new FilePickerVM() { - DoExistsCheck = false, + ExistCheckOption = FilePickerVM.ExistCheckOptions.Off, PathType = FilePickerVM.PathTypeOptions.Folder, PromptTitle = "Select Installation Directory", }; @@ -107,7 +107,7 @@ namespace Wabbajack .Select(x => Utils.IsDirectoryPathValid(x)); this.DownloadLocation = new FilePickerVM() { - DoExistsCheck = false, + ExistCheckOption = FilePickerVM.ExistCheckOptions.Off, PathType = FilePickerVM.PathTypeOptions.Folder, PromptTitle = "Select a location for MO2 downloads", };