Skip to content

Commit

Permalink
Merge pull request #2364 from erri120/feat/2254-8
Browse files Browse the repository at this point in the history
Move toolbar into tabs
  • Loading branch information
Al12rs authored Dec 11, 2024
2 parents bd7deb5 + 38b4538 commit fcc46e3
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@ public partial class CollectionDownload : IModelDefinition
/// Index into the source array.
/// </summary>
public static readonly Int32Attribute ArrayIndex = new(Namespace, nameof(ArrayIndex)) { IsIndexed = true };

public partial struct ReadOnly
{
public bool IsRequired => !IsOptional;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ private async Task<IEnumerable<Diagnostic>> DiagnoseOutdatedDependencies(
{
var uniqueIdToVersion = loadoutItemIdToManifest
.Select(kv => (kv.Value.UniqueID, kv.Value.Version))
.DistinctBy(kv => kv.UniqueID)
.ToImmutableDictionary(kv => kv.UniqueID, kv => kv.Version);

var collect = loadoutItemIdToManifest.SelectMany(kv =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,15 @@ public CollectionDownloadDesignViewModel() : base(new DesignWindowManager()) { }
public Bitmap BackgroundImage { get; } = new(AssetLoader.Open(new Uri("avares://NexusMods.App.UI/Assets/DesignTime/header-background.webp")));
public string CollectionStatusText { get; } = "0 of 9 mods downloaded";

public ReactiveCommand<Unit> DownloadAllCommand { get; } = new ReactiveCommand();
public ReactiveCommand<Unit> InstallCollectionCommand { get; } = new ReactiveCommand();
public ReactiveCommand<Unit> CommandDeleteCollection { get; } = new ReactiveCommand();
public ReactiveCommand<Unit> CommandDeleteAllDownloads { get; } = new ReactiveCommand();
public int CountDownloadedOptionalItems { get; } = 0;
public int CountDownloadedRequiredItems { get; } = 1;
public ReactiveCommand<Unit> CommandDownloadOptionalItems { get; } = new ReactiveCommand();
public ReactiveCommand<Unit> CommandDownloadRequiredItems { get; } = new ReactiveCommand();
public ReactiveCommand<Unit> CommandInstallOptionalItems { get; } = new ReactiveCommand();
public ReactiveCommand<Unit> CommandInstallRequiredItems { get; } = new ReactiveCommand();

public ReactiveCommand<Unit> CommandViewOnNexusMods { get; } = new ReactiveCommand();
public ReactiveCommand<Unit> CommandViewInLibrary { get; } = new ReactiveCommand();
public ReactiveCommand<Unit> CommandDeleteAllDownloads { get; } = new ReactiveCommand();
public ReactiveCommand<Unit> CommandDeleteCollection { get; } = new ReactiveCommand();
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@
</MenuItem.Header>
</MenuItem>
</MenuFlyout>

<DockPanel x:Key="TabItemContent" >
<Border x:Name="ListHeaderRowBorder" DockPanel.Dock="Top">
<panels:FlexPanel x:Name="ListHeaderRow">
<TextBlock x:Name="TextCollectionStatus"/>
<controls:StandardButton x:Name="ButtonDownloadRequiredItems" Text="Download all required mods" />
<controls:StandardButton x:Name="ButtonInstallRequiredItems" Text="Install Collection" />

<controls:StandardButton x:Name="ButtonDownloadOptionalItems" Text="Download all optional mods" />
<controls:StandardButton x:Name="ButtonInstallOptionalItems" Text="Install downloaded optional mods" />
<controls:StandardButton Flyout="{StaticResource CollectionMenuFlyout}" Text="..." />
</panels:FlexPanel>
</Border>

<TreeDataGrid x:Name="DownloadsTree" DockPanel.Dock="Bottom"/>
</DockPanel>
</reactiveUi:ReactiveUserControl.Resources>

<DockPanel x:Name="Body">
Expand Down Expand Up @@ -117,20 +133,9 @@
</Border>
</Border>

<!-- second row (buttons) -->
<Border x:Name="ListHeaderRowBorder" DockPanel.Dock="Top">
<panels:FlexPanel x:Name="ListHeaderRow">
<TextBlock x:Name="CollectionStatusText" />
<controls:StandardButton x:Name="InstallButton" Text="Install" />
<controls:StandardButton x:Name="DownloadAllButton" Text="Download All" />
<controls:StandardButton x:Name="FlyoutMenuButton" Flyout="{StaticResource CollectionMenuFlyout}"
Text="..." />
</panels:FlexPanel>
</Border>

<!-- third row (tab control and datagrid) -->
<!-- second row (tab control and datagrid) -->
<TabControl x:Name="TabControl">
<TabItem x:Name="RequiredTab">
<TabItem x:Name="RequiredTab" Content="{StaticResource TabItemContent}">
<TabItem.Header>
<StackPanel x:Name="RequiredModsPanel" Orientation="Horizontal">
<TextBlock>Required</TextBlock>
Expand All @@ -139,9 +144,8 @@
</Border>
</StackPanel>
</TabItem.Header>
<TreeDataGrid x:Name="RequiredDownloadsTree" />
</TabItem>
<TabItem x:Name="OptionalTab">
<TabItem x:Name="OptionalTab" Content="{StaticResource TabItemContent}">
<TabItem.Header>
<StackPanel x:Name="OptionalModsPanel" Orientation="Horizontal">
<TextBlock>Optional</TextBlock>
Expand All @@ -150,7 +154,6 @@
</Border>
</StackPanel>
</TabItem.Header>
<TreeDataGrid x:Name="OptionalDownloadsTree" />
</TabItem>
</TabControl>
</DockPanel>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using NexusMods.App.UI.Controls;
using NexusMods.App.UI.Pages.LibraryPage;
using NexusMods.MnemonicDB.Abstractions;
using R3;
using ReactiveUI;

namespace NexusMods.App.UI.Pages.CollectionDownload;
Expand All @@ -16,33 +17,36 @@ public CollectionDownloadView()
{
InitializeComponent();

TreeDataGridViewHelper.SetupTreeDataGridAdapter<CollectionDownloadView, ICollectionDownloadViewModel, ILibraryItemModel, EntityId>(this, RequiredDownloadsTree, vm => vm.TreeDataGridAdapter);
TreeDataGridViewHelper.SetupTreeDataGridAdapter<CollectionDownloadView, ICollectionDownloadViewModel, ILibraryItemModel, EntityId>(this, OptionalDownloadsTree, vm => vm.TreeDataGridAdapter);
TreeDataGridViewHelper.SetupTreeDataGridAdapter<CollectionDownloadView, ICollectionDownloadViewModel, ILibraryItemModel, EntityId>(this, DownloadsTree, vm => vm.TreeDataGridAdapter);

this.WhenActivated(d =>
{
this.BindCommand(ViewModel, vm => vm.InstallCollectionCommand, view => view.InstallButton)
this.BindCommand(ViewModel, vm => vm.CommandViewOnNexusMods, view => view.MenuItemViewOnNexusMods)
.DisposeWith(d);

this.BindCommand(ViewModel, vm => vm.DownloadAllCommand, view => view.DownloadAllButton)
this.BindCommand(ViewModel, vm => vm.CommandViewInLibrary, view => view.MenuItemViewInLibrary)
.DisposeWith(d);

this.BindCommand(ViewModel, vm => vm.CommandDeleteCollection, view => view.MenuItemDeleteCollection)
this.BindCommand(ViewModel, vm => vm.CommandDeleteAllDownloads, view => view.MenuItemDeleteAllDownloads)
.DisposeWith(d);

this.BindCommand(ViewModel, vm => vm.CommandDeleteAllDownloads, view => view.MenuItemDeleteAllDownloads)
this.BindCommand(ViewModel, vm => vm.CommandDeleteCollection, view => view.MenuItemDeleteCollection)
.DisposeWith(d);

this.BindCommand(ViewModel, vm => vm.CommandViewOnNexusMods, view => view.MenuItemViewOnNexusMods)
this.OneWayBind(ViewModel, vm => vm.CollectionStatusText, view => view.TextCollectionStatus.Text)
.DisposeWith(d);

// TODO:
MenuItemViewInLibrary.IsEnabled = false;
this.BindCommand(ViewModel, vm => vm.CommandDownloadRequiredItems, view => view.ButtonDownloadRequiredItems)
.DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.CommandInstallRequiredItems, view => view.ButtonInstallRequiredItems)
.DisposeWith(d);

this.OneWayBind(ViewModel, vm => vm.TreeDataGridAdapter.Source.Value, view => view.RequiredDownloadsTree.Source)
this.BindCommand(ViewModel, vm => vm.CommandDownloadOptionalItems, view => view.ButtonDownloadOptionalItems)
.DisposeWith(d);
this.BindCommand(ViewModel, vm => vm.CommandInstallOptionalItems, view => view.ButtonInstallOptionalItems)
.DisposeWith(d);

this.OneWayBind(ViewModel, vm => vm.TreeDataGridAdapter.Source.Value, view => view.OptionalDownloadsTree.Source)
this.OneWayBind(ViewModel, vm => vm.TreeDataGridAdapter.Source.Value, view => view.DownloadsTree.Source)
.DisposeWith(d);

this.WhenAnyValue(view => view.ViewModel!.BackgroundImage)
Expand Down Expand Up @@ -88,9 +92,6 @@ public CollectionDownloadView()
this.OneWayBind(ViewModel, vm => vm.OptionalDownloadsCount, view => view.OptionalDownloadsCount.Text)
.DisposeWith(d);

this.OneWayBind(ViewModel, vm => vm.CollectionStatusText, view => view.CollectionStatusText.Text)
.DisposeWith(d);

this.OneWayBind(ViewModel, vm => vm.RevisionNumber, view => view.Revision.Text, revision => $"Revision {revision}")
.DisposeWith(d);

Expand All @@ -107,6 +108,24 @@ public CollectionDownloadView()
})
.DisposeWith(d);

this.WhenAnyValue(
view => view.ViewModel!.CountDownloadedRequiredItems,
view => view.ViewModel!.CountDownloadedOptionalItems)
.CombineLatest(ViewModel!.TreeDataGridAdapter.Filter.AsSystemObservable(), (a, b) => (a.Item1, a.Item2, b))
.Subscribe(tuple =>
{
var (countDownloadedRequiredItems, countDownloadedOptionalItems, filter) = tuple;
var hasDownloadedAllRequiredItems = countDownloadedRequiredItems == ViewModel!.RequiredDownloadsCount;
var hasDownloadedAllOptionalItems = countDownloadedOptionalItems == ViewModel!.OptionalDownloadsCount;

ButtonDownloadRequiredItems.IsVisible = !hasDownloadedAllRequiredItems;
ButtonInstallRequiredItems.IsVisible = hasDownloadedAllRequiredItems;

ButtonDownloadOptionalItems.IsVisible = filter == CollectionDownloadsFilter.OnlyOptional && !hasDownloadedAllOptionalItems;
ButtonInstallOptionalItems.IsVisible = false; // TODO: implement this button
// ButtonInstallOptionalItems.IsVisible = filter == CollectionDownloadsFilter.OnlyOptional;
}).DisposeWith(d);

this.WhenAnyValue(view => view.ViewModel)
.WhereNotNull()
.Select(static vm => vm.OptionalDownloadsCount > 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,22 @@ public CollectionDownloadViewModel(
RequiredDownloadsCount = requiredDownloadCount;
OptionalDownloadsCount = optionalDownloadCount;

DownloadAllCommand = _canDownload.ToReactiveCommand<Unit>(
executeAsync: (_, cancellationToken) => collectionDownloader.DownloadAll(_revision, onlyRequired: true, db: connection.Db, cancellationToken: cancellationToken),
CommandDownloadRequiredItems = _canDownloadRequiredItems.ToReactiveCommand<Unit>(
executeAsync: (_, cancellationToken) => collectionDownloader.DownloadItems(_revision, itemType: CollectionDownloader.ItemType.Required, db: connection.Db, cancellationToken: cancellationToken),
awaitOperation: AwaitOperation.Drop,
configureAwait: false
);

InstallCollectionCommand = _canInstall.ToReactiveCommand<Unit>(
CommandDownloadOptionalItems = _canDownloadOptionalItems.ToReactiveCommand<Unit>(
executeAsync: (_, cancellationToken) => collectionDownloader.DownloadItems(_revision, itemType: CollectionDownloader.ItemType.Optional, db: connection.Db, cancellationToken: cancellationToken),
awaitOperation: AwaitOperation.Drop,
configureAwait: false
);

// TODO: implement this button
CommandInstallOptionalItems = _canInstallOptionalItems.ToReactiveCommand<Unit>();

CommandInstallRequiredItems = _canInstallRequiredItems.ToReactiveCommand<Unit>(
executeAsync: async (_, _) => { await InstallCollectionJob.Create(serviceProvider, targetLoadout, revisionMetadata); },
awaitOperation: AwaitOperation.Drop,
configureAwait: false
Expand Down Expand Up @@ -130,39 +139,59 @@ public CollectionDownloadViewModel(
configureAwait: false
);

CommandViewInLibrary = new ReactiveCommand(canExecuteSource: R3.Observable.Return(false), initialCanExecute: false);

this.WhenActivated(disposables =>
{
TreeDataGridAdapter.Activate();
Disposable.Create(TreeDataGridAdapter, static adapter => adapter.Deactivate()).AddTo(disposables);

var numDownloadedObservable = Observable
var numDownloadedRequiredItemsObservable = Observable
.Return(_revision)
.OffUi()
.SelectMany(revision => collectionDownloader.RequiredDownloadedCountObservable(revision));
.SelectMany(revision => collectionDownloader.DownloadedItemCountObservable(revision, itemType: CollectionDownloader.ItemType.Required));

var isPremiumObservable = loginManager.IsPremiumObservable;
var isCollectionInstalledObservable = collectionDownloader.IsCollectionInstalled(_revision);
var numDownloadedOptionalItemsObservable = Observable
.Return(_revision)
.OffUi()
.SelectMany(revision => collectionDownloader.DownloadedItemCountObservable(revision, itemType: CollectionDownloader.ItemType.Optional));

numDownloadedObservable.CombineLatest(isPremiumObservable, isCollectionInstalledObservable)
var isPremiumObservable = loginManager.IsPremiumObservable.Prepend(false);
var isCollectionInstalledObservable = collectionDownloader.IsCollectionInstalled(_revision).Prepend(false);

numDownloadedRequiredItemsObservable.CombineLatest(isPremiumObservable, isCollectionInstalledObservable)
.OnUI()
.Subscribe(tuple =>
{
var (numDownloaded, isPremium, isCollectionInstalled) = tuple;
var hasDownloaded = numDownloaded == RequiredDownloadsCount;
var (numDownloadedRequiredItems, isPremium, isCollectionInstalled) = tuple;
var hasDownloadedAllRequiredItems = numDownloadedRequiredItems == RequiredDownloadsCount;

_canInstall.OnNext(!isCollectionInstalled && hasDownloaded);
_canDownload.OnNext(!hasDownloaded && isPremium);
CountDownloadedRequiredItems = numDownloadedRequiredItems;
_canInstallRequiredItems.OnNext(!isCollectionInstalled && hasDownloadedAllRequiredItems);
_canDownloadRequiredItems.OnNext(!hasDownloadedAllRequiredItems && isPremium);

if (hasDownloaded)
if (hasDownloadedAllRequiredItems)
{
CollectionStatusText = Language.CollectionDownloadViewModel_Ready_to_install;
}
else
{
CollectionStatusText = string.Format(Language.CollectionDownloadViewModel_Num_required_mods_downloaded, numDownloaded, RequiredDownloadsCount);
CollectionStatusText = string.Format(Language.CollectionDownloadViewModel_Num_required_mods_downloaded, numDownloadedRequiredItems, RequiredDownloadsCount);
}
}).AddTo(disposables);

numDownloadedOptionalItemsObservable.CombineLatest(isPremiumObservable)
.OnUI()
.Subscribe(tuple =>
{
var (numDownloadedOptionalItems, isPremium) = tuple;
var hasDownloadedAllOptionalItems = numDownloadedOptionalItems == OptionalDownloadsCount;

CountDownloadedOptionalItems = numDownloadedOptionalItems;
_canInstallOptionalItems.OnNext(numDownloadedOptionalItems > 0);
_canDownloadOptionalItems.OnNext(!hasDownloadedAllOptionalItems && isPremium);
}).AddTo(disposables);

ImagePipelines.CreateObservable(_collection.Id, tileImagePipeline)
.ObserveOnUIThreadDispatcher()
.Subscribe(this, static (bitmap, self) => self.TileImage = bitmap)
Expand Down Expand Up @@ -192,8 +221,10 @@ public CollectionDownloadViewModel(
});
}

private readonly BehaviorSubject<bool> _canDownload = new(initialValue: false);
private readonly BehaviorSubject<bool> _canInstall = new(initialValue: false);
private readonly BehaviorSubject<bool> _canDownloadRequiredItems = new(initialValue: false);
private readonly BehaviorSubject<bool> _canDownloadOptionalItems = new(initialValue: false);
private readonly BehaviorSubject<bool> _canInstallRequiredItems = new(initialValue: false);
private readonly BehaviorSubject<bool> _canInstallOptionalItems = new(initialValue: false);

public string Name => _collection.Name;
public string Summary => _collection.Summary;
Expand All @@ -210,17 +241,23 @@ public CollectionDownloadViewModel(

public int RequiredDownloadsCount { get; }
public int OptionalDownloadsCount { get; }
[Reactive] public int CountDownloadedOptionalItems { get; private set; }
[Reactive] public int CountDownloadedRequiredItems { get; private set; }

[Reactive] public Bitmap? TileImage { get; private set; }
[Reactive] public Bitmap? BackgroundImage { get; private set; }
[Reactive] public Bitmap? AuthorAvatar { get; private set; }
[Reactive] public string CollectionStatusText { get; private set; } = "";

public ReactiveCommand<Unit> DownloadAllCommand { get; }
public ReactiveCommand<Unit> InstallCollectionCommand { get; }
public ReactiveCommand<Unit> CommandDeleteCollection { get; }
public ReactiveCommand<Unit> CommandDeleteAllDownloads { get; }
public ReactiveCommand<Unit> CommandDownloadRequiredItems { get; }
public ReactiveCommand<Unit> CommandInstallRequiredItems { get; }
public ReactiveCommand<Unit> CommandDownloadOptionalItems { get; }
public ReactiveCommand<Unit> CommandInstallOptionalItems { get; }

public ReactiveCommand<Unit> CommandViewOnNexusMods { get; }
public ReactiveCommand<Unit> CommandViewInLibrary { get; }
public ReactiveCommand<Unit> CommandDeleteAllDownloads { get; }
public ReactiveCommand<Unit> CommandDeleteCollection { get; }
}

public record DownloadMessage(DownloadableItem Item);
Expand Down
Loading

0 comments on commit fcc46e3

Please sign in to comment.