Skip to content

Commit e06c537

Browse files
authored
Merge pull request #1736 from Nexus-Mods/feat/multiple-loadouts-part1
Multiple loadouts UI part1
2 parents e9c6f85 + 104895f commit e06c537

File tree

44 files changed

+619
-73
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+619
-73
lines changed

Directory.Packages.props

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Project>
22
<ItemGroup>
33
<PackageVersion Include="Avalonia.AvaloniaEdit" Version="11.0.6" />
4+
<PackageVersion Include="Avalonia.Labs.Panels" Version="11.0.10.1" />
45
<PackageVersion Include="AvaloniaEdit.TextMate" Version="11.0.6" />
56
<PackageVersion Include="FlatSharp.Compiler" Version="7.6.0" />
67
<PackageVersion Include="FlatSharp.Runtime" Version="7.6.0" />

src/Games/NexusMods.Games.AdvancedInstaller.UI/Content/Right/SelectLocation/SelectLocationView.axaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
</Border>
5858

5959
<!-- 'Suggested' -->
60-
<Border Classes="Top Rounded-lg Padding16 SuggestedAreaBorder">
60+
<Border Classes="High Rounded-lg Padding16 SuggestedAreaBorder">
6161
<StackPanel Orientation="Vertical">
6262
<StackPanel Classes="SuggestedHeaderStackPanel" Orientation="Vertical">
6363
<!-- Header: 'SUGGESTED' -->

src/Games/NexusMods.Games.AdvancedInstaller.UI/Pages/AdvancedInstallerPages/AdvancedInstallerPageView.axaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131

3232
</Grid.Styles>
3333

34-
<Border Grid.Row="0" Classes="Top RoundedTop" HorizontalAlignment="Stretch">
35-
<Border Classes="Top RoundedTop TopPart" x:Name="TopContentBorder">
34+
<Border Grid.Row="0" Classes="High RoundedTop" HorizontalAlignment="Stretch">
35+
<Border Classes="High RoundedTop TopPart" x:Name="TopContentBorder">
3636
<Grid RowDefinitions="Auto, *">
3737

3838
<Border Grid.Row="0" Classes="OverlayHeaderSection" x:Name="OverlayHeaderBorder">

src/Games/NexusMods.Games.AdvancedInstaller.UI/Pages/ModUnsupportedPage/UnsupportedModPageView.axaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555

5656
</Grid.Styles>
5757

58-
<Border Grid.Row="0" Classes="RoundedTop Top" HorizontalAlignment="Stretch">
58+
<Border Grid.Row="0" Classes="Rounded-t-lg High" HorizontalAlignment="Stretch">
5959
<Border Classes="TopPart" x:Name="TopContentBorder">
6060
<Grid RowDefinitions="Auto, *">
6161

src/Games/NexusMods.Games.FOMOD.UI/Step/GuidedInstallerStepView.axaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858

5959
<Grid Grid.Column="1" x:Name="PreviewStackPanel" RowDefinitions="Auto,*">
6060
<Border Grid.Row="0" x:Name="PreviewTitleBorder"
61-
Classes="RoundedTop OutlineStrong">
61+
Classes="Rounded-t-lg OutlineStrong">
6262
<Grid ColumnDefinitions="*, Auto, Auto">
6363

6464
<TextBlock Grid.Column="0" x:Name="PreviewTitleTextBox" Classes="BodyXLBold"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace NexusMods.App.UI.Controls.LoadoutBadge;
2+
3+
public interface ILoadoutBadgeViewModel : IViewModelInterface
4+
{
5+
string LoadoutShortName { get; }
6+
7+
bool IsLoadoutSelected { get; }
8+
9+
bool IsLoadoutApplied { get; }
10+
11+
bool IsLoadoutInProgress { get; }
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<reactiveUi:ReactiveUserControl x:TypeArguments="loadoutBadge:ILoadoutBadgeViewModel"
2+
xmlns="https://github.com/avaloniaui"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6+
xmlns:icons="clr-namespace:NexusMods.Icons;assembly=NexusMods.Icons"
7+
xmlns:spinner="clr-namespace:NexusMods.App.UI.Controls.Spinner"
8+
xmlns:reactiveUi="http://reactiveui.net"
9+
xmlns:loadoutBadge="clr-namespace:NexusMods.App.UI.Controls.LoadoutBadge"
10+
mc:Ignorable="d" d:DesignWidth="120" d:DesignHeight="120"
11+
x:Class="NexusMods.App.UI.Controls.LoadoutBadge.LoadoutBadge"
12+
HorizontalAlignment="Right"
13+
VerticalAlignment="Top">
14+
<Design.DataContext>
15+
<loadoutBadge:LoadoutBadgeDesignViewModel />
16+
</Design.DataContext>
17+
18+
<Border x:Name="OuterBorder">
19+
<StackPanel x:Name="ContentsStackPanel"
20+
Orientation="Horizontal">
21+
<spinner:Spinner x:Name="Spinner" />
22+
<icons:UnifiedIcon x:Name="Icon"
23+
Classes="Check" />
24+
<TextBlock x:Name="ShortName"
25+
Classes="BodyLGBold"/>
26+
</StackPanel>
27+
</Border>
28+
</reactiveUi:ReactiveUserControl>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System.Reactive.Disposables;
2+
using Avalonia.Controls;
3+
using Avalonia.Controls.Metadata;
4+
using Avalonia.ReactiveUI;
5+
using ReactiveUI;
6+
7+
namespace NexusMods.App.UI.Controls.LoadoutBadge;
8+
9+
[PseudoClasses(":selected", ":in-progress", ":applied")]
10+
public partial class LoadoutBadge : ReactiveUserControl<ILoadoutBadgeViewModel>
11+
{
12+
public LoadoutBadge()
13+
{
14+
InitializeComponent();
15+
16+
this.WhenActivated(d =>
17+
{
18+
this.WhenAnyValue(x => x.ViewModel!.IsLoadoutSelected)
19+
.OnUI()
20+
.Subscribe(SetSelected)
21+
.DisposeWith(d);
22+
23+
this.WhenAnyValue(x => x.ViewModel!.IsLoadoutApplied)
24+
.OnUI()
25+
.Subscribe(SetApplied)
26+
.DisposeWith(d);
27+
28+
this.WhenAnyValue(x => x.ViewModel!.IsLoadoutInProgress)
29+
.OnUI()
30+
.Subscribe(SetInProgress)
31+
.DisposeWith(d);
32+
33+
this.OneWayBind(ViewModel, vm => vm.LoadoutShortName, v => v.ShortName.Text)
34+
.DisposeWith(d);
35+
}
36+
);
37+
}
38+
39+
private void SetSelected(bool selected)
40+
{
41+
PseudoClasses.Set(":selected", selected);
42+
}
43+
44+
private void SetApplied(bool applied)
45+
{
46+
PseudoClasses.Set(":applied", applied);
47+
}
48+
49+
private void SetInProgress(bool inProgress)
50+
{
51+
PseudoClasses.Set(":in-progress", inProgress);
52+
}
53+
}
54+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System.Reactive.Disposables;
2+
using System.Reactive.Linq;
3+
using ReactiveUI;
4+
using ReactiveUI.Fody.Helpers;
5+
6+
namespace NexusMods.App.UI.Controls.LoadoutBadge;
7+
8+
public class LoadoutBadgeDesignViewModel : AViewModel<ILoadoutBadgeViewModel>, ILoadoutBadgeViewModel
9+
{
10+
private enum LoadoutAppliedState
11+
{
12+
NotApplied,
13+
Applying,
14+
Applied,
15+
}
16+
private LoadoutAppliedState _loadoutAppliedState = LoadoutAppliedState.NotApplied;
17+
18+
public LoadoutBadgeDesignViewModel()
19+
{
20+
this.WhenActivated(d =>
21+
{
22+
// Cycle thorough all the states for preview purposes
23+
24+
Observable.Interval(TimeSpan.FromSeconds(0.5))
25+
.Subscribe(_ =>
26+
{
27+
IsLoadoutSelected = !IsLoadoutSelected;
28+
})
29+
.DisposeWith(d);
30+
31+
Observable.Interval(TimeSpan.FromSeconds(1))
32+
.Subscribe(_ =>
33+
{
34+
switch (_loadoutAppliedState)
35+
{
36+
case LoadoutAppliedState.NotApplied:
37+
IsLoadoutApplied = false;
38+
IsLoadoutInProgress = false;
39+
_loadoutAppliedState = LoadoutAppliedState.Applying;
40+
break;
41+
case LoadoutAppliedState.Applying:
42+
IsLoadoutApplied = false;
43+
IsLoadoutInProgress = true;
44+
_loadoutAppliedState = LoadoutAppliedState.Applied;
45+
break;
46+
case LoadoutAppliedState.Applied:
47+
IsLoadoutApplied = true;
48+
IsLoadoutInProgress = false;
49+
_loadoutAppliedState = LoadoutAppliedState.NotApplied;
50+
break;
51+
default:
52+
throw new ArgumentOutOfRangeException();
53+
}
54+
})
55+
.DisposeWith(d);
56+
}
57+
);
58+
}
59+
60+
public string LoadoutShortName { get; } = "A";
61+
[Reactive] public bool IsLoadoutSelected { get; private set; } = false;
62+
[Reactive] public bool IsLoadoutApplied { get; private set; } = false;
63+
[Reactive] public bool IsLoadoutInProgress { get; private set; } = false;
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace NexusMods.App.UI.Controls.LoadoutCard;
2+
3+
public interface ILoadoutCardViewModel : IViewModelInterface
4+
{
5+
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<reactiveUi:ReactiveUserControl x:TypeArguments="loadoutCard:ILoadoutCardViewModel" xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:reactiveUi="http://reactiveui.net"
6+
xmlns:loadoutCard="clr-namespace:NexusMods.App.UI.Controls.LoadoutCard"
7+
xmlns:panels="clr-namespace:Avalonia.Labs.Panels;assembly=Avalonia.Labs.Panels"
8+
xmlns:icons="clr-namespace:NexusMods.Icons;assembly=NexusMods.Icons"
9+
xmlns:loadoutBadge="clr-namespace:NexusMods.App.UI.Controls.LoadoutBadge"
10+
mc:Ignorable="d" d:DesignWidth="250" d:DesignHeight="400"
11+
x:Class="NexusMods.App.UI.Controls.LoadoutCard.LoadoutCardView">
12+
<Button x:Name="CardOuterButton">
13+
14+
<panels:FlexPanel x:Name="CardOuterFlexPanel">
15+
16+
<Border x:Name="ImageSectionBorder">
17+
<Grid>
18+
<Image x:Name="GameImage"
19+
Source="avares://NexusMods.App.UI/Assets/DesignTime/cyberpunk_game.png" />
20+
<Rectangle x:Name="GradientLayerRectangle" />
21+
<loadoutBadge:LoadoutBadge x:Name="LoadoutBadge" />
22+
</Grid>
23+
</Border>
24+
25+
<Border x:Name="DetailsSectionBorder">
26+
27+
<panels:FlexPanel x:Name="DetailsSectionFlexPanel">
28+
29+
<TextBlock x:Name="LoadoutNameTextBlock"
30+
Classes="BodyLGBold"
31+
Text="Loadout A" />
32+
33+
<panels:FlexPanel x:Name="BodyAndActionsGroupFlexPanel">
34+
35+
<panels:FlexPanel x:Name="DetailsBodyFlexPanel">
36+
37+
<panels:FlexPanel x:Name="CurrentlyAppliedFlexPanel">
38+
39+
<TextBlock x:Name="CurrentlyAppliedTextBlock"
40+
Classes="BodySMBold"
41+
Text="Currently Applied" />
42+
<icons:UnifiedIcon x:Name="AppliedCheckBoxIcon"
43+
Classes="CheckBox" />
44+
45+
</panels:FlexPanel>
46+
47+
<TextBlock x:Name="LastAppliedTimeTextBlock"
48+
Classes="BodySMNormal ForegroundSubdued"
49+
Text="Last applied 2 months ago"
50+
IsVisible="False" />
51+
52+
<TextBlock x:Name="CreatedTimeTextBlock"
53+
Classes="BodySMNormal ForegroundSubdued"
54+
Text="Created 10 months ago" />
55+
56+
<TextBlock x:Name="NumberOfModsTextBlock"
57+
Classes="BodySMNormal ForegroundSubdued"
58+
Text="Mods 276" />
59+
60+
</panels:FlexPanel>
61+
62+
<panels:FlexPanel x:Name="ActionsFlexPanel">
63+
64+
<Button x:Name="CreateCopyButton"
65+
Classes="Rounded Primary">
66+
<StackPanel HorizontalAlignment="Center">
67+
<TextBlock Classes="BodySMBold" Text="Create Copy" />
68+
</StackPanel>
69+
</Button>
70+
71+
72+
<Button x:Name="DeleteButton"
73+
Classes="Rounded Primary">
74+
<icons:UnifiedIcon Classes="TrashCanOutline" />
75+
</Button>
76+
</panels:FlexPanel>
77+
78+
</panels:FlexPanel>
79+
80+
</panels:FlexPanel>
81+
</Border>
82+
83+
</panels:FlexPanel>
84+
</Button>
85+
</reactiveUi:ReactiveUserControl>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using Avalonia.ReactiveUI;
2+
3+
namespace NexusMods.App.UI.Controls.LoadoutCard;
4+
5+
public partial class LoadoutCardView : ReactiveUserControl<ILoadoutCardViewModel>
6+
{
7+
public LoadoutCardView()
8+
{
9+
InitializeComponent();
10+
}
11+
}
12+

src/NexusMods.App.UI/Controls/MarkdownRenderer/MarkdownRendererView.axaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
<Setter Property="FontSize" Value="13" />
106106
<!-- <Setter Property="LineHeight" Value="19.5" /> -->
107107
<Setter Property="Foreground" Value="{StaticResource NeutralModerateBrush}" />
108-
<Setter Property="Background" Value="{StaticResource SurfaceTopBrush}" />
108+
<Setter Property="Background" Value="{StaticResource SurfaceHighBrush}" />
109109
</Style>
110110

111111
<Style Selector="ctxt|CHyperlink">

src/NexusMods.App.UI/Controls/ModInfo/Loading/LoadingView.axaml

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
1212
xmlns:loading="clr-namespace:NexusMods.App.UI.Controls.ModInfo.Loading"
1313
xmlns:spinner="clr-namespace:NexusMods.App.UI.Controls.Spinner">
14-
<spinner:Spinner Classes="SmallerSpinner" HorizontalAlignment="Center" VerticalAlignment="Center" />
14+
<spinner:Spinner HorizontalAlignment="Center"
15+
VerticalAlignment="Center"
16+
Height="48"
17+
Width="48"/>
1518
</reactiveUi:ReactiveUserControl>
1619

src/NexusMods.App.UI/Controls/Spinner/Spinner.axaml

+21-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1-
<UserControl
2-
d:DesignHeight="60"
3-
d:DesignWidth="60"
4-
mc:Ignorable="d"
5-
x:Class="NexusMods.App.UI.Controls.Spinner.Spinner"
6-
xmlns="https://github.com/avaloniaui"
7-
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
8-
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9-
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
10-
<Arc Height="{Binding $parent.Width}"
11-
Width="{Binding $parent.Height}" />
1+
<UserControl mc:Ignorable="d"
2+
d:DesignHeight="60"
3+
d:DesignWidth="60"
4+
x:Class="NexusMods.App.UI.Controls.Spinner.Spinner"
5+
xmlns="https://github.com/avaloniaui"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
8+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
9+
xmlns:spinner="clr-namespace:NexusMods.App.UI.Controls.Spinner">
10+
11+
<!-- Source: https://www.figma.com/design/8pjtQeNggvVi7RWoLNGV80/%F0%9F%A7%B0-Nexus-Mods-Design-System?node-id=137-1575&m=dev -->
12+
<Path
13+
Data="M60.5 30C60.5 24.0666 58.7405 18.2664 55.4441 13.3329C52.1476 8.39942 47.4623 4.55424 41.9805 2.28361C36.4987 0.012985 30.4667 -0.581115 24.6473 0.576442C18.8279 1.734 13.4824 4.59122 9.2868 8.7868C5.09122 12.9824 2.234 18.3279 1.07644 24.1473C-0.0811151 29.9667 0.512985 35.9987 2.78361 41.4805C5.05424 46.9623 8.89942 51.6476 13.8329 54.9441C18.7664 58.2405 24.5666 60 30.5 60V52.8071C25.9892 52.8071 21.5796 51.4695 17.829 48.9634C14.0784 46.4574 11.1552 42.8954 9.42895 38.7279C7.70274 34.5605 7.25108 29.9747 8.1311 25.5505C9.01111 21.1264 11.1833 17.0626 14.3729 13.8729C17.5626 10.6833 21.6264 8.51112 26.0505 7.6311C30.4747 6.75108 35.0605 7.20273 39.2279 8.92895C43.3954 10.6552 46.9574 13.5784 49.4634 17.329C51.9695 21.0796 53.3071 25.4892 53.3071 30H60.5Z"
14+
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type spinner:Spinner}}}"
15+
HorizontalAlignment="Center"
16+
VerticalAlignment="Center"
17+
Stretch="Uniform">
18+
<Path.RenderTransform>
19+
<RotateTransform />
20+
</Path.RenderTransform>
21+
</Path>
1222
</UserControl>
13-

src/NexusMods.App.UI/NexusMods.App.UI.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
<PackageReference Include="Avalonia.Controls.DataGrid" />
6262
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
6363
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" />
64+
<PackageReference Include="Avalonia.Labs.Panels" />
6465
<PackageReference Include="Avalonia.ReactiveUI" />
6566
<PackageReference Include="Avalonia.Svg.Skia" />
6667
<PackageReference Include="Avalonia.Themes.Fluent" />

src/NexusMods.Icons/IconValues.cs

+3
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,9 @@ public static class IconValues
303303
#endregion
304304

305305
#region Toggle
306+
307+
// https://pictogrammers.com/library/mdi/icon/checkbox-marked/
308+
public static readonly IconValue CheckBox = new ProjektankerIcon("mdi-checkbox-marked");
306309

307310
// https://pictogrammers.com/library/mdi/icon/star/
308311
public static readonly IconValue Star = new ProjektankerIcon("mdi-star");

0 commit comments

Comments
 (0)