Implement basic total modlist size filter

This commit is contained in:
trawzified 2023-12-30 21:34:36 +01:00
parent a908c49f26
commit 95ff0dac6d
8 changed files with 79 additions and 11 deletions

View File

@ -14,7 +14,7 @@ namespace Wabbajack.Models;
public class ResourceMonitor : IDisposable public class ResourceMonitor : IDisposable
{ {
private readonly TimeSpan _pollInterval = TimeSpan.FromMilliseconds(250); private readonly TimeSpan _pollInterval = TimeSpan.FromMilliseconds(1000);
private readonly IResource[] _resources; private readonly IResource[] _resources;

View File

@ -87,7 +87,7 @@
<SolidColorBrush <SolidColorBrush
x:Key="MahApps.Brushes.AccentBase" x:Key="MahApps.Brushes.AccentBase"
options:Freeze="True" options:Freeze="True"
Color="{StaticResource MahApps.Colors.AccentBase}" /> Color="{StaticResource Primary}" />
<SolidColorBrush <SolidColorBrush
x:Key="MahApps.Brushes.Accent" x:Key="MahApps.Brushes.Accent"
options:Freeze="True" options:Freeze="True"

View File

@ -46,6 +46,11 @@ namespace Wabbajack
[Reactive] public bool ShowUnofficialLists { get; set; } [Reactive] public bool ShowUnofficialLists { get; set; }
[Reactive] public string GameType { get; set; } [Reactive] public string GameType { get; set; }
[Reactive] public double MinSizeFilter { get; set; }
[Reactive] public double MaxSizeFilter { get; set; }
[Reactive] public ModListMetadataVM MinSizeModlist { get; set; }
[Reactive] public ModListMetadataVM MaxSizeModlist { get; set; }
public class GameTypeEntry public class GameTypeEntry
{ {
@ -67,6 +72,8 @@ namespace Wabbajack
[Reactive] public List<GameTypeEntry> GameTypeEntries { get; set; } [Reactive] public List<GameTypeEntry> GameTypeEntries { get; set; }
private bool _filteringOnGame; private bool _filteringOnGame;
private bool _filteringOnMinSize;
private bool _filteringOnMaxSize;
private GameTypeEntry _selectedGameTypeEntry = null; private GameTypeEntry _selectedGameTypeEntry = null;
public GameTypeEntry SelectedGameTypeEntry public GameTypeEntry SelectedGameTypeEntry
@ -170,12 +177,29 @@ namespace Wabbajack
}) })
.StartWith(_ => true); .StartWith(_ => true);
var minSizeFilter = this.ObservableForProperty(vm => vm.MinSizeFilter)
.Select(v => v.Value)
.Select<double, Func<ModListMetadataVM, bool>>(minSize =>
{
_filteringOnMinSize = true;
return item => item.Metadata.DownloadMetadata.TotalSize > (minSize * Math.Pow(1024, 3));
});
var maxSizeFilter = this.ObservableForProperty(vm => vm.MaxSizeFilter)
.Select(v => v.Value)
.Select<double, Func<ModListMetadataVM, bool>>(maxSize =>
{
_filteringOnMaxSize = true;
return item => item.Metadata.DownloadMetadata.TotalSize < (maxSize * Math.Pow(1024, 3));
});
var searchSorter = this.WhenValueChanged(vm => vm.Search) var searchSorter = this.WhenValueChanged(vm => vm.Search)
.Where(s => !string.IsNullOrWhiteSpace(s))
.Throttle(searchThrottle, RxApp.MainThreadScheduler) .Throttle(searchThrottle, RxApp.MainThreadScheduler)
.Select(s => SortExpressionComparer<ModListMetadataVM> .Select(s => SortExpressionComparer<ModListMetadataVM>
.Descending(m => m.Metadata.Title.StartsWith(s, StringComparison.InvariantCultureIgnoreCase)) .Descending(m => m.Metadata.Title.StartsWith(s, StringComparison.InvariantCultureIgnoreCase))
.ThenByDescending(m => m.Metadata.Title.Contains(s, StringComparison.InvariantCultureIgnoreCase))); .ThenByDescending(m => m.Metadata.Title.Contains(s, StringComparison.InvariantCultureIgnoreCase))
.ThenByDescending(m => !m.IsBroken));
_modLists.Connect() _modLists.Connect()
.ObserveOn(RxApp.MainThreadScheduler) .ObserveOn(RxApp.MainThreadScheduler)
.Filter(searchTextPredicates) .Filter(searchTextPredicates)
@ -183,6 +207,8 @@ namespace Wabbajack
.Filter(showUnofficial) .Filter(showUnofficial)
.Filter(showNSFWFilter) .Filter(showNSFWFilter)
.Filter(gameFilter) .Filter(gameFilter)
.Filter(minSizeFilter)
.Filter(maxSizeFilter)
.Sort(searchSorter) .Sort(searchSorter)
.TreatMovesAsRemoveAdd() .TreatMovesAsRemoveAdd()
.Bind(out _filteredModLists) .Bind(out _filteredModLists)
@ -196,7 +222,16 @@ namespace Wabbajack
var nextEntry = GameTypeEntries.FirstOrDefault(gte => previousGameType == gte.GameIdentifier); var nextEntry = GameTypeEntries.FirstOrDefault(gte => previousGameType == gte.GameIdentifier);
SelectedGameTypeEntry = nextEntry != default ? nextEntry : GameTypeEntries.FirstOrDefault(gte => GameType == ALL_GAME_IDENTIFIER); SelectedGameTypeEntry = nextEntry != default ? nextEntry : GameTypeEntries.FirstOrDefault(gte => GameType == ALL_GAME_IDENTIFIER);
} }
/*
if (!_filteringOnMinSize)
MinSizeModlist = ModLists.MinBy(ml => ml.Metadata.DownloadMetadata.TotalSize);
if(!_filteringOnMaxSize)
MaxSizeModlist = ModLists.MaxBy(ml => ml.Metadata.DownloadMetadata.TotalSize);
*/
_filteringOnGame = false; _filteringOnGame = false;
_filteringOnMinSize = false;
_filteringOnMaxSize = false;
}) })
.DisposeWith(disposables); .DisposeWith(disposables);
}); });
@ -255,6 +290,8 @@ namespace Wabbajack
e.AddOrUpdate(modLists.Select(m => e.AddOrUpdate(modLists.Select(m =>
new ModListMetadataVM(_logger, this, m, _maintainer, _wjClient, _cancellationToken))); new ModListMetadataVM(_logger, this, m, _maintainer, _wjClient, _cancellationToken)));
}); });
MinSizeModlist = _modLists.Items.Any() ? _modLists.Items.MinBy(ml => ml.Metadata.DownloadMetadata.TotalSize) : null;
MaxSizeModlist = _modLists.Items.Any() ? _modLists.Items.MaxBy(ml => ml.Metadata.DownloadMetadata.TotalSize) : null;
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -132,9 +132,7 @@ namespace Wabbajack
DownloadSizeText = "Download size : " + UIUtils.FormatBytes(Metadata.DownloadMetadata.SizeOfArchives); DownloadSizeText = "Download size : " + UIUtils.FormatBytes(Metadata.DownloadMetadata.SizeOfArchives);
InstallSizeText = "Installation size : " + UIUtils.FormatBytes(Metadata.DownloadMetadata.SizeOfInstalledFiles); InstallSizeText = "Installation size : " + UIUtils.FormatBytes(Metadata.DownloadMetadata.SizeOfInstalledFiles);
TotalSizeRequirementText = "Total size requirement: " + UIUtils.FormatBytes( TotalSizeRequirementText = "Total size requirement: " + UIUtils.FormatBytes( Metadata.DownloadMetadata.TotalSize );
Metadata.DownloadMetadata.SizeOfArchives + Metadata.DownloadMetadata.SizeOfInstalledFiles
);
VersionText = "Modlist version : " + Metadata.Version; VersionText = "Modlist version : " + Metadata.Version;
ImageContainsTitle = Metadata.ImageContainsTitle; ImageContainsTitle = Metadata.ImageContainsTitle;
DisplayVersionOnlyInInstallerView = Metadata.DisplayVersionOnlyInInstallerView; DisplayVersionOnlyInInstallerView = Metadata.DisplayVersionOnlyInInstallerView;
@ -181,8 +179,9 @@ namespace Wabbajack
}) })
.ToGuiProperty(this, nameof(Exists)); .ToGuiProperty(this, nameof(Exists));
var imageObs = Observable.Return(Metadata.ValidationSummary.SmallImage.ToString()) var modlistImageSource = Metadata.ValidationSummary?.SmallImage?.ToString() ?? Metadata.Links.ImageUri;
.DownloadBitmapImage((ex) => _logger.LogError("Error downloading modlist image {Title} from {ImageUri}: {Exception}", Metadata.Title, Metadata.ValidationSummary.SmallImage, ex.Message), LoadingImageLock); var imageObs = Observable.Return(modlistImageSource)
.DownloadBitmapImage((ex) => _logger.LogError("Error downloading modlist image {Title} from {ImageUri}: {Exception}", Metadata.Title, modlistImageSource, ex.Message), LoadingImageLock);
_Image = imageObs _Image = imageObs
.ToGuiProperty(this, nameof(Image)); .ToGuiProperty(this, nameof(Image));

View File

@ -114,7 +114,7 @@ namespace Wabbajack
_resourceMonitor.Updates _resourceMonitor.Updates
.Select(r => string.Join(", ", r.Where(r => r.Throughput > 0) .Select(r => string.Join(", ", r.Where(r => r.Throughput > 0)
.Select(s => $"{s.Name} - {s.Throughput.ToFileSizeString()}/sec"))) .Select(s => $"{s.Name} - {s.Throughput.ToFileSizeString()}/s")))
.BindToStrict(this, view => view.ResourceStatus); .BindToStrict(this, view => view.ResourceStatus);

View File

@ -86,6 +86,7 @@
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
@ -136,7 +137,7 @@
</ComboBox.ItemTemplate> </ComboBox.ItemTemplate>
</ComboBox> </ComboBox>
<Grid Grid.Row="2" Margin="0, 10, 0, 0"> <Grid Grid.Row="2" Margin="0, 25, 0, 0">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
@ -188,6 +189,16 @@
<TextBlock Grid.Column="1" Margin="3, 0, 0, 0" Text="Show only modlists for installed games" FontSize="14" VerticalAlignment="Center" /> <TextBlock Grid.Column="1" Margin="3, 0, 0, 0" Text="Show only modlists for installed games" FontSize="14" VerticalAlignment="Center" />
</Grid> </Grid>
<Grid Grid.Row="5" Margin="0, 25, 0, 0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock FontSize="14" Text="Modlist size"/>
<mahapps:RangeSlider Margin="0, 10, 0, 0" x:Name="SizeSliderFilter" Grid.Row="1" AutoToolTipPlacement="TopLeft" AutoToolTipPrecision="1" />
</Grid>
<Button <Button
x:Name="ClearFiltersButton" x:Name="ClearFiltersButton"
Grid.Row="6" Grid.Row="6"

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Windows; using System.Windows;
@ -23,6 +24,19 @@ namespace Wabbajack
.BindToStrict(this, x => x.ModListGalleryControl.ItemsSource) .BindToStrict(this, x => x.ModListGalleryControl.ItemsSource)
.DisposeWith(dispose); .DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.MinSizeModlist)
.Where(x => x != null)
.Select(modlist => Math.Round(modlist.Metadata.DownloadMetadata.TotalSize / Math.Pow(1024, 3), 1))
.BindToStrict(this, x => x.SizeSliderFilter.Minimum)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.MaxSizeModlist)
.Where(x => x != null)
.Select(modlist => Math.Round(modlist.Metadata.DownloadMetadata.TotalSize / Math.Pow(1024, 3), 1))
.BindToStrict(this, x => x.SizeSliderFilter.Maximum)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.LoadingLock.IsLoading) this.WhenAny(x => x.ViewModel.LoadingLock.IsLoading)
.Select(x => x ? Visibility.Visible : Visibility.Collapsed) .Select(x => x ? Visibility.Visible : Visibility.Collapsed)
.StartWith(Visibility.Collapsed) .StartWith(Visibility.Collapsed)
@ -61,6 +75,10 @@ namespace Wabbajack
.DisposeWith(dispose); .DisposeWith(dispose);
this.BindStrict(ViewModel, vm => vm.ShowUnofficialLists, x => x.ShowUnofficialLists.IsChecked) this.BindStrict(ViewModel, vm => vm.ShowUnofficialLists, x => x.ShowUnofficialLists.IsChecked)
.DisposeWith(dispose); .DisposeWith(dispose);
this.BindStrict(ViewModel, vm => vm.MinSizeFilter, x => x.SizeSliderFilter.LowerValue)
.DisposeWith(dispose);
this.BindStrict(ViewModel, vm => vm.MaxSizeFilter, x => x.SizeSliderFilter.UpperValue)
.DisposeWith(dispose);
this.WhenAny(x => x.ViewModel.ClearFiltersCommand) this.WhenAny(x => x.ViewModel.ClearFiltersCommand)
.BindToStrict(this, x => x.ClearFiltersButton.Command) .BindToStrict(this, x => x.ClearFiltersButton.Command)

View File

@ -1,3 +1,4 @@
using System;
using Wabbajack.Hashing.xxHash64; using Wabbajack.Hashing.xxHash64;
namespace Wabbajack.DTOs; namespace Wabbajack.DTOs;
@ -10,4 +11,6 @@ public class DownloadMetadata
public long SizeOfArchives { get; set; } public long SizeOfArchives { get; set; }
public long NumberOfInstalledFiles { get; set; } public long NumberOfInstalledFiles { get; set; }
public long SizeOfInstalledFiles { get; set; } public long SizeOfInstalledFiles { get; set; }
public long TotalSize => SizeOfArchives + SizeOfInstalledFiles;
} }