diff --git a/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadDesignViewModel.cs b/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadDesignViewModel.cs index 1545adf44a..e7229900c6 100644 --- a/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadDesignViewModel.cs +++ b/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadDesignViewModel.cs @@ -11,8 +11,7 @@ namespace NexusMods.App.UI.Pages.CollectionDownload; public class CollectionDownloadDesignViewModel : APageViewModel, ICollectionDownloadViewModel { - public CollectionDownloadTreeDataGridAdapter RequiredDownloadsAdapter { get; } = null!; - public CollectionDownloadTreeDataGridAdapter OptionalDownloadsAdapter { get; } = null!; + public CollectionDownloadTreeDataGridAdapter TreeDataGridAdapter { get; } = null!; public CollectionDownloadDesignViewModel() : base(new DesignWindowManager()) { } diff --git a/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadView.axaml b/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadView.axaml index 6f3fc347e2..5fe8c45653 100644 --- a/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadView.axaml +++ b/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadView.axaml @@ -48,28 +48,29 @@ - - + + - + - + - + - - + + - + COLLECTION DOWNLOAD - - + + @@ -80,7 +81,7 @@ - + @@ -106,7 +107,8 @@ - + @@ -116,18 +118,19 @@ - + - + - - + + - + Required @@ -136,10 +139,9 @@ - - + Optional @@ -151,7 +153,6 @@ - - + diff --git a/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadView.axaml.cs b/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadView.axaml.cs index 6689461da3..3c2a907b11 100644 --- a/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadView.axaml.cs +++ b/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadView.axaml.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.Reactive.Disposables; using System.Reactive.Linq; using Avalonia.Media; @@ -15,18 +16,18 @@ public CollectionDownloadView() { InitializeComponent(); - TreeDataGridViewHelper.SetupTreeDataGridAdapter(this, RequiredDownloadsTree, vm => vm.RequiredDownloadsAdapter); - TreeDataGridViewHelper.SetupTreeDataGridAdapter(this, OptionalDownloadsTree, vm => vm.OptionalDownloadsAdapter); + TreeDataGridViewHelper.SetupTreeDataGridAdapter(this, RequiredDownloadsTree, vm => vm.TreeDataGridAdapter); + TreeDataGridViewHelper.SetupTreeDataGridAdapter(this, OptionalDownloadsTree, vm => vm.TreeDataGridAdapter); this.WhenActivated(d => { this.BindCommand(ViewModel, vm => vm.DownloadAllCommand, view => view.DownloadAllButton) .DisposeWith(d); - this.OneWayBind(ViewModel, vm => vm.RequiredDownloadsAdapter.Source.Value, view => view.RequiredDownloadsTree.Source) + this.OneWayBind(ViewModel, vm => vm.TreeDataGridAdapter.Source.Value, view => view.RequiredDownloadsTree.Source) .DisposeWith(d); - this.OneWayBind(ViewModel, vm => vm.OptionalDownloadsAdapter.Source.Value, view => view.OptionalDownloadsTree.Source) + this.OneWayBind(ViewModel, vm => vm.TreeDataGridAdapter.Source.Value, view => view.OptionalDownloadsTree.Source) .DisposeWith(d); this.WhenAnyValue(view => view.ViewModel!.BackgroundImage) @@ -78,14 +79,28 @@ public CollectionDownloadView() this.OneWayBind(ViewModel, vm => vm.RevisionNumber, view => view.Revision.Text, revision => $"Revision {revision}") .DisposeWith(d); + this.WhenAnyValue(view => view.TabControl.SelectedItem) + .Select(selectedItem => + { + if (ReferenceEquals(selectedItem, RequiredTab)) return CollectionDownloadsFilter.OnlyRequired; + if (ReferenceEquals(selectedItem, OptionalTab)) return CollectionDownloadsFilter.OnlyOptional; + throw new UnreachableException(); + }) + .Subscribe(filter => + { + ViewModel!.TreeDataGridAdapter.Filter.Value = filter; + }) + .DisposeWith(d); + this.WhenAnyValue(view => view.ViewModel) .WhereNotNull() - .Subscribe(vm => + .Select(static vm => vm.OptionalDownloadsCount > 0) + .Subscribe(hasOptionalDownloads => { - if (vm.OptionalDownloadsCount == 0) - { - // TabControl.IsVisible = false; - } + if (hasOptionalDownloads) TabControl.Classes.Remove("SingleTab"); + else TabControl.Classes.Add("SingleTab"); + + if (!hasOptionalDownloads) TabControl.SelectedItem = RequiredTab; }).DisposeWith(d); this.WhenAnyValue(view => view.ViewModel!.OverallRating) diff --git a/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadViewModel.cs b/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadViewModel.cs index e8583c34ca..9c3cb7ed1b 100644 --- a/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadViewModel.cs +++ b/src/NexusMods.App.UI/Pages/CollectionDownload/CollectionDownloadViewModel.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Reactive.Linq; using Avalonia.Controls.Models.TreeDataGrid; using Avalonia.Media.Imaging; using DynamicData; @@ -20,7 +21,6 @@ using R3; using ReactiveUI; using ReactiveUI.Fody.Helpers; -using ReactiveCommand = R3.ReactiveCommand; namespace NexusMods.App.UI.Pages.CollectionDownload; @@ -34,9 +34,7 @@ public class CollectionDownloadViewModel : APageViewModel(canExecuteSource: Observable.Return(false), initialCanExecute: false); + InstallCollectionCommand = new ReactiveCommand(canExecuteSource: R3.Observable.Return(false), initialCanExecute: false); this.WhenActivated(disposables => { - RequiredDownloadsAdapter.Activate(); - OptionalDownloadsAdapter.Activate(); - Disposable.Create(RequiredDownloadsAdapter, static adapter => adapter.Deactivate()); - Disposable.Create(OptionalDownloadsAdapter, static adapter => adapter.Deactivate()); + TreeDataGridAdapter.Activate(); + Disposable.Create(TreeDataGridAdapter, static adapter => adapter.Deactivate()); ImagePipelines.CreateObservable(_collection.Id, tileImagePipeline) .ObserveOnUIThreadDispatcher() @@ -110,7 +104,7 @@ public CollectionDownloadViewModel( .Subscribe(this, static (bitmap, self) => self.AuthorAvatar = bitmap) .AddTo(disposables); - RequiredDownloadsAdapter.MessageSubject.Merge(OptionalDownloadsAdapter.MessageSubject).SubscribeAwait( + TreeDataGridAdapter.MessageSubject.SubscribeAwait( onNextAsync: (message, cancellationToken) => { return message.Item.Match( @@ -158,11 +152,14 @@ public class CollectionDownloadTreeDataGridAdapter : TreeDataGridAdapter MessageSubject { get; } = new(); + public R3.ReactiveProperty Filter { get; } = new(value: CollectionDownloadsFilter.OnlyRequired); private readonly Dictionary _commandDisposables = new(); private readonly IDisposable _activationDisposable; - public CollectionDownloadTreeDataGridAdapter(NexusModsDataProvider nexusModsDataProvider, CollectionRevisionMetadata.ReadOnly revisionMetadata) + public CollectionDownloadTreeDataGridAdapter( + NexusModsDataProvider nexusModsDataProvider, + CollectionRevisionMetadata.ReadOnly revisionMetadata) { _nexusModsDataProvider = nexusModsDataProvider; _revisionMetadata = revisionMetadata; @@ -213,7 +210,7 @@ protected override void BeforeModelDeactivationHook(ILibraryItemModel model) protected override IObservable> GetRootsObservable(bool viewHierarchical) { - return _nexusModsDataProvider.ObserveCollectionItems(_revisionMetadata); + return _nexusModsDataProvider.ObserveCollectionItems(_revisionMetadata, Filter.AsSystemObservable()); } protected override IColumn[] CreateColumns(bool viewHierarchical) diff --git a/src/NexusMods.App.UI/Pages/CollectionDownload/ICollectionDownloadViewModel.cs b/src/NexusMods.App.UI/Pages/CollectionDownload/ICollectionDownloadViewModel.cs index 10310b0d52..65d8291741 100644 --- a/src/NexusMods.App.UI/Pages/CollectionDownload/ICollectionDownloadViewModel.cs +++ b/src/NexusMods.App.UI/Pages/CollectionDownload/ICollectionDownloadViewModel.cs @@ -9,8 +9,7 @@ namespace NexusMods.App.UI.Pages.CollectionDownload; public interface ICollectionDownloadViewModel : IPageViewModelInterface { - CollectionDownloadTreeDataGridAdapter RequiredDownloadsAdapter { get; } - CollectionDownloadTreeDataGridAdapter OptionalDownloadsAdapter { get; } + CollectionDownloadTreeDataGridAdapter TreeDataGridAdapter { get; } /// string Name { get; } diff --git a/src/NexusMods.App.UI/Pages/LibraryPage/ILibraryItemWithAction.cs b/src/NexusMods.App.UI/Pages/LibraryPage/ILibraryItemWithAction.cs index 2ac76d28de..a4f5719e3a 100644 --- a/src/NexusMods.App.UI/Pages/LibraryPage/ILibraryItemWithAction.cs +++ b/src/NexusMods.App.UI/Pages/LibraryPage/ILibraryItemWithAction.cs @@ -18,6 +18,8 @@ int IComparable.CompareTo(ILibraryItemWithAction? other) { (ILibraryItemWithInstallAction, ILibraryItemWithDownloadAction) => -1, (ILibraryItemWithDownloadAction, ILibraryItemWithInstallAction) => 1, + (ILibraryItemWithDownloadAction a, ILibraryItemWithDownloadAction b) => ((int)a.DownloadState.Value).CompareTo((int)b.DownloadState.Value), + (ILibraryItemWithInstallAction a, ILibraryItemWithInstallAction b) => a.IsInstalled.Value.CompareTo(b.IsInstalled.Value), _ => 0, }; } diff --git a/src/NexusMods.App.UI/Pages/NexusModsDataProvider.cs b/src/NexusMods.App.UI/Pages/NexusModsDataProvider.cs index 4686b09501..15093887b7 100644 --- a/src/NexusMods.App.UI/Pages/NexusModsDataProvider.cs +++ b/src/NexusMods.App.UI/Pages/NexusModsDataProvider.cs @@ -25,6 +25,12 @@ namespace NexusMods.App.UI.Pages; using CollectionDownloadEntity = Abstractions.NexusModsLibrary.Models.CollectionDownload; +public enum CollectionDownloadsFilter +{ + OnlyRequired, + OnlyOptional, +} + [UsedImplicitly] public class NexusModsDataProvider : ILibraryDataProvider, ILoadoutDataProvider { @@ -38,13 +44,19 @@ public NexusModsDataProvider(IServiceProvider serviceProvider) } public IObservable> ObserveCollectionItems( - CollectionRevisionMetadata.ReadOnly revisionMetadata) + CollectionRevisionMetadata.ReadOnly revisionMetadata, + IObservable filterObservable) { return _connection .ObserveDatoms(CollectionDownloadEntity.CollectionRevision, revisionMetadata) .AsEntityIds() .Transform(datom => CollectionDownloadEntity.Load(_connection.Db, datom.E)) - .Filter(static downloadEntity => downloadEntity.IsCollectionDownloadNexusMods() || downloadEntity.IsCollectionDownloadExternal()) + .FilterOnObservable(downloadEntity => filterObservable.Select(filter => filter switch + { + CollectionDownloadsFilter.OnlyRequired => !downloadEntity.IsOptional, + CollectionDownloadsFilter.OnlyOptional => downloadEntity.IsOptional, + })) + .FilterImmutable(static downloadEntity => downloadEntity.IsCollectionDownloadNexusMods() || downloadEntity.IsCollectionDownloadExternal()) .Transform(ILibraryItemModel (downloadEntity) => { if (downloadEntity.TryGetAsCollectionDownloadNexusMods(out var nexusModsDownload)) diff --git a/src/Themes/NexusMods.Themes.NexusFluentDark/Styles/UserControls/CollectionDownloadPage/CollectionDownloadPageStyles.axaml b/src/Themes/NexusMods.Themes.NexusFluentDark/Styles/UserControls/CollectionDownloadPage/CollectionDownloadPageStyles.axaml index 60d41fbf2e..6be6b3e25c 100644 --- a/src/Themes/NexusMods.Themes.NexusFluentDark/Styles/UserControls/CollectionDownloadPage/CollectionDownloadPageStyles.axaml +++ b/src/Themes/NexusMods.Themes.NexusFluentDark/Styles/UserControls/CollectionDownloadPage/CollectionDownloadPageStyles.axaml @@ -3,8 +3,9 @@ xmlns:panels="clr-namespace:Avalonia.Labs.Panels;assembly=Avalonia.Labs.Panels" xmlns:collections="clr-namespace:NexusMods.App.UI.Pages.CollectionDownload;assembly=NexusMods.App.UI" xmlns:icons="clr-namespace:NexusMods.Icons;assembly=NexusMods.Icons"> + - + @@ -21,27 +22,19 @@ - + @@ -227,6 +220,13 @@ + + + +