diff --git a/Wabbajack.Lib/ACompiler.cs b/Wabbajack.Lib/ACompiler.cs index f3fe207a..a018e359 100644 --- a/Wabbajack.Lib/ACompiler.cs +++ b/Wabbajack.Lib/ACompiler.cs @@ -18,6 +18,7 @@ namespace Wabbajack.Lib public string? ModListName, ModListAuthor, ModListDescription, ModListWebsite, ModlistReadme; public Version? ModlistVersion; public AbsolutePath ModListImage; + public bool ModlistIsNSFW; protected Version? WabbajackVersion; public abstract AbsolutePath VFSCacheName { get; } diff --git a/Wabbajack.Lib/Data.cs b/Wabbajack.Lib/Data.cs index 1f6b6807..450bfe43 100644 --- a/Wabbajack.Lib/Data.cs +++ b/Wabbajack.Lib/Data.cs @@ -108,6 +108,11 @@ namespace Wabbajack.Lib /// public Version Version = new Version(1, 0, 0, 0); + /// + /// Whether the Modlist is NSFW or not + /// + public bool IsNSFW; + /// /// The size of all the archives once they're downloaded /// diff --git a/Wabbajack.Lib/MO2Compiler.cs b/Wabbajack.Lib/MO2Compiler.cs index 04f204fb..5a7d313a 100644 --- a/Wabbajack.Lib/MO2Compiler.cs +++ b/Wabbajack.Lib/MO2Compiler.cs @@ -303,7 +303,8 @@ namespace Wabbajack.Lib Description = ModListDescription ?? "", Readme = ModlistReadme ?? "", Image = ModListImage != default ? ModListImage.FileName : default, - Website = ModListWebsite != null ? new Uri(ModListWebsite) : null + Website = !string.IsNullOrWhiteSpace(ModListWebsite) ? new Uri(ModListWebsite) : null, + IsNSFW = ModlistIsNSFW }; UpdateTracker.NextStep("Running Validation"); diff --git a/Wabbajack.Lib/ModListRegistry/ModListMetadata.cs b/Wabbajack.Lib/ModListRegistry/ModListMetadata.cs index df19992b..e0fe28cf 100644 --- a/Wabbajack.Lib/ModListRegistry/ModListMetadata.cs +++ b/Wabbajack.Lib/ModListRegistry/ModListMetadata.cs @@ -29,6 +29,9 @@ namespace Wabbajack.Lib.ModListRegistry [JsonProperty("official")] public bool Official { get; set; } + [JsonProperty("nsfw")] + public bool NSFW { get; set; } + [JsonProperty("links")] public LinksObject Links { get; set; } = new LinksObject(); diff --git a/Wabbajack/Settings.cs b/Wabbajack/Settings.cs index f641f75d..091f7f12 100644 --- a/Wabbajack/Settings.cs +++ b/Wabbajack/Settings.cs @@ -130,6 +130,7 @@ namespace Wabbajack public string Description { get; set; } public string Website { get; set; } public string Readme { get; set; } + public bool IsNSFW { get; set; } public AbsolutePath SplashScreen { get; set; } } diff --git a/Wabbajack/View Models/Compilers/ModlistSettingsEditorVM.cs b/Wabbajack/View Models/Compilers/ModlistSettingsEditorVM.cs index 623bed28..5d7256cf 100644 --- a/Wabbajack/View Models/Compilers/ModlistSettingsEditorVM.cs +++ b/Wabbajack/View Models/Compilers/ModlistSettingsEditorVM.cs @@ -20,7 +20,7 @@ namespace Wabbajack [Reactive] public string VersionText { get; set; } - private ObservableAsPropertyHelper _version; + private readonly ObservableAsPropertyHelper _version; public Version Version => _version.Value; [Reactive] @@ -37,6 +37,9 @@ namespace Wabbajack [Reactive] public string Website { get; set; } + [Reactive] + public bool IsNSFW { get; set; } + public IObservable InError { get; } public ModlistSettingsEditorVM(CompilationModlistSettings settings) @@ -81,6 +84,7 @@ namespace Wabbajack ImagePath.TargetPath = _settings.SplashScreen; Website = _settings.Website; VersionText = _settings.Version; + IsNSFW = _settings.IsNSFW; } public void Save() @@ -92,6 +96,7 @@ namespace Wabbajack _settings.Readme = Readme; _settings.SplashScreen = ImagePath.TargetPath; _settings.Website = Website; + _settings.IsNSFW = IsNSFW; } } } diff --git a/Wabbajack/View Models/Gallery/ModListGalleryVM.cs b/Wabbajack/View Models/Gallery/ModListGalleryVM.cs index 5b3d4148..3d20d69e 100644 --- a/Wabbajack/View Models/Gallery/ModListGalleryVM.cs +++ b/Wabbajack/View Models/Gallery/ModListGalleryVM.cs @@ -34,6 +34,9 @@ namespace Wabbajack [Reactive] public bool OnlyInstalled { get; set; } + + [Reactive] + public bool ShowNSFW { get; set; } private readonly ObservableAsPropertyHelper _Loaded; public bool Loaded => _Loaded.Value; @@ -49,6 +52,7 @@ namespace Wabbajack () => { OnlyInstalled = false; + ShowNSFW = false; Search = string.Empty; }); @@ -91,7 +95,7 @@ namespace Wabbajack .Transform(m => new ModListMetadataVM(this, m)) .DisposeMany() // Filter only installed - .Filter(predicateChanged: this.WhenAny(x => x.OnlyInstalled) + .Filter(this.WhenAny(x => x.OnlyInstalled) .Select>(onlyInstalled => (vm) => { if (!onlyInstalled) return true; @@ -99,13 +103,19 @@ namespace Wabbajack return gameMeta.IsInstalled; })) // Filter on search box - .Filter(predicateChanged: this.WhenAny(x => x.Search) + .Filter(this.WhenAny(x => x.Search) .Debounce(TimeSpan.FromMilliseconds(150), RxApp.MainThreadScheduler) .Select>(search => (vm) => { if (string.IsNullOrWhiteSpace(search)) return true; return vm.Metadata.Title.ContainsCaseInsensitive(search); })) + .Filter(this.WhenAny(x => x.ShowNSFW) + .Select>(showNSFW => vm => + { + if (!vm.Metadata.NSFW) return true; + return vm.Metadata.NSFW && showNSFW; + })) // Put broken lists at bottom .Sort(Comparer.Create((a, b) => a.IsBroken.CompareTo(b.IsBroken))) .Bind(ModLists) diff --git a/Wabbajack/View Models/ModListVM.cs b/Wabbajack/View Models/ModListVM.cs index accf12bb..44368ab0 100644 --- a/Wabbajack/View Models/ModListVM.cs +++ b/Wabbajack/View Models/ModListVM.cs @@ -22,6 +22,7 @@ namespace Wabbajack public Uri Website => SourceModList?.Website; public ModManager ModManager => SourceModList?.ModManager ?? ModManager.MO2; public Version Version => SourceModList?.Version; + public bool IsNSFW => SourceModList?.IsNSFW ?? false; // Image isn't exposed as a direct property, but as an observable. // This acts as a caching mechanism, as interested parties will trigger it to be created, diff --git a/Wabbajack/Views/Compilers/CompilerView.xaml b/Wabbajack/Views/Compilers/CompilerView.xaml index 5fa4a148..cd0247b0 100644 --- a/Wabbajack/Views/Compilers/CompilerView.xaml +++ b/Wabbajack/Views/Compilers/CompilerView.xaml @@ -147,6 +147,9 @@ Text="Readme" ToolTip="Link to the Readme." /> + !x) .BindToStrict(this, x => x.SettingsScrollViewer.IsEnabled) .DisposeWith(dispose); - this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.ModListName, x => x.ModListNameSetting.Text) + this.BindStrict(ViewModel, x => x.CurrentModlistSettings.ModListName, x => x.ModListNameSetting.Text) .DisposeWith(dispose); this.BindStrict(ViewModel, x => x.CurrentModlistSettings.VersionText, x => x.VersionSetting.Text) .DisposeWith(dispose); - this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.AuthorText, x => x.AuthorNameSetting.Text) + this.BindStrict(ViewModel, x => x.CurrentModlistSettings.AuthorText, x => x.AuthorNameSetting.Text) .DisposeWith(dispose); - this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.Description, x => x.DescriptionSetting.Text) + this.BindStrict(ViewModel, x => x.CurrentModlistSettings.Description, x => x.DescriptionSetting.Text) .DisposeWith(dispose); this.WhenAny(x => x.ViewModel.CurrentModlistSettings.ImagePath) .BindToStrict(this, x => x.ImageFilePicker.PickerVM) .DisposeWith(dispose); - this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.Website, x => x.WebsiteSetting.Text) + this.BindStrict(ViewModel, x => x.CurrentModlistSettings.Website, x => x.WebsiteSetting.Text) .DisposeWith(dispose); - this.BindStrict(this.ViewModel, x => x.CurrentModlistSettings.Readme, x => x.ReadmeSetting.Text) + this.BindStrict(ViewModel, x => x.CurrentModlistSettings.Readme, x => x.ReadmeSetting.Text) + .DisposeWith(dispose); + this.BindStrict(ViewModel, x => x.CurrentModlistSettings.IsNSFW, x => x.NSFWSetting.IsChecked) .DisposeWith(dispose); // Bottom Compiler Settings diff --git a/Wabbajack/Views/ModListGalleryView.xaml b/Wabbajack/Views/ModListGalleryView.xaml index 364e4ec4..018b6eff 100644 --- a/Wabbajack/Views/ModListGalleryView.xaml +++ b/Wabbajack/Views/ModListGalleryView.xaml @@ -106,6 +106,12 @@ x:Name="SearchBox" Width="160" VerticalContentAlignment="Center" /> + x.ErrorIcon.Visibility) .DisposeWith(dispose); - this.BindStrict(this.ViewModel, vm => vm.Search, x => x.SearchBox.Text) + this.BindStrict(ViewModel, vm => vm.Search, x => x.SearchBox.Text) .DisposeWith(dispose); - this.BindStrict(this.ViewModel, vm => vm.OnlyInstalled, x => x.OnlyInstalledCheckbox.IsChecked) + this.BindStrict(ViewModel, vm => vm.OnlyInstalled, x => x.OnlyInstalledCheckbox.IsChecked) + .DisposeWith(dispose); + this.BindStrict(ViewModel, vm => vm.ShowNSFW, x => x.ShowNSFW.IsChecked) .DisposeWith(dispose); this.WhenAny(x => x.ViewModel.ClearFiltersCommand)