Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move toolbar into tabs #2364

Merged
merged 4 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
erri120 marked this conversation as resolved.
Show resolved Hide resolved
.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>();
Al12rs marked this conversation as resolved.
Show resolved Hide resolved

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 numDownloadedOptionalItemsObservable = Observable
.Return(_revision)
.OffUi()
.SelectMany(revision => collectionDownloader.DownloadedItemCountObservable(revision, itemType: CollectionDownloader.ItemType.Optional));

var isPremiumObservable = loginManager.IsPremiumObservable;
var isCollectionInstalledObservable = collectionDownloader.IsCollectionInstalled(_revision);

numDownloadedObservable.CombineLatest(isPremiumObservable, isCollectionInstalledObservable)
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);
erri120 marked this conversation as resolved.
Show resolved Hide resolved

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
Loading