Skip to content

Commit

Permalink
Initial UI design for the collection install page (#2080)
Browse files Browse the repository at this point in the history
* WIP

* Most of the design is wired up, just need to pretty it up and add the backend implementation

* Add commented out background image
  • Loading branch information
halgari authored Sep 25, 2024
1 parent a6f75e0 commit 58cefe9
Show file tree
Hide file tree
Showing 8 changed files with 406 additions and 0 deletions.
Binary file not shown.
6 changes: 6 additions & 0 deletions src/NexusMods.App.UI/NexusMods.App.UI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,12 @@
<Compile Update="Pages\LibraryPage\Collections\CollectionsDesignViewModel.cs">
<DependentUpon>ICollectionsViewModel.cs</DependentUpon>
</Compile>
<Compile Update="Pages\CollectionDownload\CollectionDownloadDesignViewModel.cs">
<DependentUpon>ICollectionDownloadViewModel.cs</DependentUpon>
</Compile>
<Compile Update="Pages\LibraryPage\Collections\CollectionCardViewModel.cs">
<DependentUpon>ICollectionCardViewModel.cs</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using NexusMods.Abstractions.Jobs;
using NexusMods.Abstractions.NexusWebApi.Types;
using NexusMods.Paths;

namespace NexusMods.App.UI.Pages.CollectionDownload;

public class CollectionDownloadDesignViewModel : AViewModel<ICollectionDownloadViewModel>, ICollectionDownloadViewModel
{
public string Name => "Vanilla+ [Quality of Life]";
public CollectionSlug Slug { get; } = CollectionSlug.From("tckf0m");
public RevisionNumber RevisionNumber { get; } = RevisionNumber.From(6);
public string AuthorName => "Lowtonotolerance";

public string Summary =>
"Aims to improves vanilla gameplay while adding minimal additional content. Aims to improves vanilla gameplay while adding minimal additional content. Aims to improves vanilla gameplay while adding minimal additional content. Aims to improves vanilla gameplay while adding minimal additional content.";

public int ModCount => 9;
public int RequiredModCount => 7;
public int OptionalModCount => 2;
public int EndorsementCount => 248;
public int DownloadCount => 35_123;
public Size TotalSize { get; } = Size.From(76_123_456);
public Percent OverallRating { get; } = Percent.CreateClamped(0.82);
public Bitmap TileImage { get; } = new(AssetLoader.Open(new Uri("avares://NexusMods.App.UI/Assets/DesignTime/collection_tile_image.png")));

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";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<reactiveUi:ReactiveUserControl
x:TypeArguments="collectionDownload:ICollectionDownloadViewModel"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveUi="http://reactiveui.net"
xmlns:collectionDownload="clr-namespace:NexusMods.App.UI.Pages.CollectionDownload"
xmlns:panels="clr-namespace:Avalonia.Labs.Panels;assembly=Avalonia.Labs.Panels"
xmlns:icons="clr-namespace:NexusMods.Icons;assembly=NexusMods.Icons"
mc:Ignorable="d" d:DesignWidth="1620" d:DesignHeight="600"
x:Class="NexusMods.App.UI.Pages.CollectionDownload.CollectionDownloadView">
<Design.DataContext>
<collectionDownload:CollectionDownloadDesignViewModel />
</Design.DataContext>

<reactiveUi:ReactiveUserControl.Resources>
<MenuFlyout x:Key="CollectionMenuFlyout">
<MenuItem>
<MenuItem.Header>
<panels:FlexPanel>
<TextBlock>View on Nexus Mods</TextBlock>
</panels:FlexPanel>
</MenuItem.Header>
</MenuItem>
<MenuItem>
<MenuItem.Header>
<panels:FlexPanel>
<TextBlock>View in Library</TextBlock>
</panels:FlexPanel>
</MenuItem.Header>
</MenuItem>
<MenuItem>
<MenuItem.Header>
<panels:FlexPanel>
<TextBlock>Delete all downloads</TextBlock>
</panels:FlexPanel>
</MenuItem.Header>
</MenuItem>
<MenuItem>
<MenuItem.Header>
<panels:FlexPanel>
<TextBlock>Delete Collection</TextBlock>
</panels:FlexPanel>
</MenuItem.Header>
</MenuItem>
</MenuFlyout>
</reactiveUi:ReactiveUserControl.Resources>

<panels:FlexPanel x:Name="Body">
<panels:FlexPanel x:Name="Frame758">
<panels:FlexPanel x:Name="Frame1452">
<Border x:Name="ContainerBorder">
<panels:FlexPanel x:Name="Container">
<Border x:Name="Image38Border">
<Image x:Name="Image38" />
</Border>
<panels:FlexPanel x:Name="ContainerInner">
<TextBlock Classes="TitleSMSemi">COLLECTION DOWNLOAD</TextBlock>
<TextBlock x:Name="Title" Classes="HeadingSMSemi"/>
<panels:FlexPanel x:Name="TagsPanel">
<TextBlock x:Name="Revision" />
<Border x:Name="AuthorAvatarBorder">
<Image x:Name="AuthorAvatar" />
</Border>
</panels:FlexPanel>
<TextBlock x:Name="AuthorName" />
<TextBlock x:Name="Summary"></TextBlock>
</panels:FlexPanel>
</panels:FlexPanel>
</Border>
</panels:FlexPanel>
<panels:FlexPanel x:Name="Frame1449">
<panels:FlexPanel x:Name="Stats" IsVisible="True">
<panels:FlexPanel x:Name="ModsPanel">
<icons:UnifiedIcon Value="{x:Static icons:IconValues.Mods}" />
<TextBlock x:Name="ModCount" />
</panels:FlexPanel>
<panels:FlexPanel x:Name="EndorsementsPanel">
<icons:UnifiedIcon Value="{x:Static icons:IconValues.ThumbUp}" />
<TextBlock x:Name="Endorsements" />
</panels:FlexPanel>
<panels:FlexPanel x:Name="DownloadsPanel">
<icons:UnifiedIcon Value="{x:Static icons:IconValues.Download}" />
<TextBlock x:Name="Downloads" />
</panels:FlexPanel>
<panels:FlexPanel x:Name="TotalSizePanel">
<icons:UnifiedIcon Value="{x:Static icons:IconValues.Size}" />
<TextBlock x:Name="TotalSize" />
</panels:FlexPanel>
<panels:FlexPanel x:Name="OverallRatingPanel">
<icons:UnifiedIcon Value="{x:Static icons:IconValues.CheckCircle}" />
<TextBlock x:Name="OverallRating" />
</panels:FlexPanel>
</panels:FlexPanel>
</panels:FlexPanel>
</panels:FlexPanel>
<panels:FlexPanel x:Name="ListHeaderRow">
<TextBlock x:Name="CollectionStatusText"></TextBlock>
<Button x:Name="InstallButton">Install</Button>
<Button x:Name="DownloadAllButton">DownloadAll</Button>
<Button x:Name="FlyoutMenuButton" Flyout="{StaticResource CollectionMenuFlyout}">...</Button>
</panels:FlexPanel>
<Expander>
<Expander.Header>
<panels:FlexPanel>
<TextBlock>Required</TextBlock>
<TextBlock x:Name="RequiredModsCount" />
</panels:FlexPanel>
</Expander.Header>
<TextBlock>TODO: Grid of mods will appear here</TextBlock>
</Expander>
<Expander>
<Expander.Header>
<panels:FlexPanel>
<TextBlock>Optional</TextBlock>
<TextBlock x:Name="OptionalModsCount" />
</panels:FlexPanel>
</Expander.Header>
<TextBlock>TODO: Grid of mods will appear here</TextBlock>
</Expander>
</panels:FlexPanel>

</reactiveUi:ReactiveUserControl>

Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Reactive.Disposables;
using Avalonia.Media;
using Avalonia.ReactiveUI;
using ReactiveUI;

namespace NexusMods.App.UI.Pages.CollectionDownload;

public partial class CollectionDownloadView : ReactiveUserControl<ICollectionDownloadViewModel>
{
public CollectionDownloadView()
{
InitializeComponent();

this.WhenActivated(d =>
{

// Uncomment this to enable the background image
/*
this.WhenAnyValue(view => view.ViewModel!.BackgroundImage)
.WhereNotNull()
.SubscribeWithErrorLogging(image => Body.Background = new ImageBrush { Source = image })
.DisposeWith(d);
*/

this.WhenAnyValue(view => view.ViewModel!.TileImage)
.WhereNotNull()
.SubscribeWithErrorLogging(image => Image38.Source = image)
.DisposeWith(d);

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

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

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

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

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

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

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

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

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

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

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

}
);
}


}

Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using Avalonia.Media.Imaging;
using NexusMods.Abstractions.Jobs;
using NexusMods.Abstractions.NexusWebApi.Types;
using NexusMods.Paths;

namespace NexusMods.App.UI.Pages.CollectionDownload;

public interface ICollectionDownloadViewModel : IViewModelInterface
{
/// <summary>
/// Name of the collection
/// </summary>
public string Name { get; }

/// <summary>
/// The collection's slug
/// </summary>
public CollectionSlug Slug { get; }

/// <summary>
/// The collection's revision number
/// </summary>
public RevisionNumber RevisionNumber { get; }

/// <summary>
/// Name of the author of the collection
/// </summary>
public string AuthorName { get; }

/// <summary>
/// The summary (short description) of the collection
/// </summary>
public string Summary { get; }

/// <summary>
/// Total number of mods in the collection
/// </summary>
public int ModCount { get; }

/// <summary>
/// The number of required mods in the collection
/// </summary>
public int RequiredModCount { get; }

/// <summary>
/// The number of optional mods in the collection
/// </summary>
public int OptionalModCount { get; }

/// <summary>
/// The number of endorsements the collection has
/// </summary>
public int EndorsementCount { get; }

/// <summary>
/// The number of downloads the collection has
/// </summary>
public int DownloadCount { get; }

/// <summary>
/// The size of the collection including all downloads and the collection file iteself
/// </summary>
public Size TotalSize { get; }

/// <summary>
/// The overall approval rating of the collection
/// </summary>
public Percent OverallRating { get; }

/// <summary>
/// The small tileable image of the collection
/// </summary>
public Bitmap TileImage { get; }

/// <summary>
/// The background banner image of the collection
/// </summary>
public Bitmap BackgroundImage { get; }

/// <summary>
/// A text representation of the collection's status, such as "Downloading", "Installing", "Ready to Play", etc.
/// </summary>
public string CollectionStatusText { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<StyleInclude Source="/Styles/Controls/FlexPanel/FlexPanelStyles.axaml"/>

<StyleInclude Source="/Styles/UserControls/Banners/InfoBannerStyles.axaml"/>
<StyleInclude Source="/Styles/UserControls/CollectionDownloadPage/CollectionDownloadPage.axaml"/>
<StyleInclude Source="/Styles/UserControls/CollectionCards/CollectionCardStyles.axaml"/>
<StyleInclude Source="/Styles/UserControls/Diagnostics/DiagnosticEntryStyles.axaml"/>
<StyleInclude Source="/Styles/UserControls/EmptyState/EmptyStateStyles.axaml"/>
Expand Down
Loading

0 comments on commit 58cefe9

Please sign in to comment.