Skip to content

Commit 55ecac9

Browse files
authored
Merge pull request #1760 from Nexus-Mods/feat/multiple-loadouts-part2
Multiple loadouts part2
2 parents e06c537 + 181cdd8 commit 55ecac9

File tree

8 files changed

+337
-103
lines changed

8 files changed

+337
-103
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<reactiveUi:ReactiveUserControl x:TypeArguments="loadoutBadge:ILoadoutBadgeViewModel"
1+
<reactiveUi:ReactiveUserControl x:TypeArguments="loadoutBadge:ILoadoutBadgeViewModel"
22
xmlns="https://github.com/avaloniaui"
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@@ -7,22 +7,21 @@
77
xmlns:spinner="clr-namespace:NexusMods.App.UI.Controls.Spinner"
88
xmlns:reactiveUi="http://reactiveui.net"
99
xmlns:loadoutBadge="clr-namespace:NexusMods.App.UI.Controls.LoadoutBadge"
10+
xmlns:panels="clr-namespace:Avalonia.Labs.Panels;assembly=Avalonia.Labs.Panels"
1011
mc:Ignorable="d" d:DesignWidth="120" d:DesignHeight="120"
1112
x:Class="NexusMods.App.UI.Controls.LoadoutBadge.LoadoutBadge"
1213
HorizontalAlignment="Right"
1314
VerticalAlignment="Top">
1415
<Design.DataContext>
1516
<loadoutBadge:LoadoutBadgeDesignViewModel />
1617
</Design.DataContext>
17-
18-
<Border x:Name="OuterBorder">
19-
<StackPanel x:Name="ContentsStackPanel"
20-
Orientation="Horizontal">
18+
19+
<panels:FlexPanel x:Name="ContentsFlexPanel">
20+
<Border>
2121
<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>
22+
</Border>
23+
<icons:UnifiedIcon x:Name="Icon"
24+
Classes="Check" />
25+
<TextBlock x:Name="ShortName"/>
26+
</panels:FlexPanel>
2827
</reactiveUi:ReactiveUserControl>
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,31 @@
1+
using System.Reactive;
2+
using Avalonia.Media;
3+
using NexusMods.App.UI.Controls.LoadoutBadge;
4+
using ReactiveUI;
5+
16
namespace NexusMods.App.UI.Controls.LoadoutCard;
27

38
public interface ILoadoutCardViewModel : IViewModelInterface
49
{
10+
ILoadoutBadgeViewModel LoadoutBadgeViewModel { get; }
11+
12+
string LoadoutName { get; }
13+
14+
IImage LoadoutImage { get; }
15+
16+
bool IsLoadoutApplied { get; }
17+
18+
string HumanizedLoadoutLastApplyTime { get; }
19+
20+
string HumanizedLoadoutCreationTime { get; }
21+
22+
string LoadoutModCount { get; }
23+
24+
bool IsDeleting { get; }
25+
26+
ReactiveCommand<Unit, Unit> VisitLoadoutCommand { get; }
27+
28+
ReactiveCommand<Unit, Unit> CloneLoadoutCommand { get; }
529

30+
ReactiveCommand<Unit, Unit> DeleteLoadoutCommand { get; }
631
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System.Reactive;
2+
using System.Reactive.Disposables;
3+
using System.Reactive.Linq;
4+
using Avalonia.Media;
5+
using Avalonia.Media.Imaging;
6+
using Avalonia.Platform;
7+
using NexusMods.App.UI.Controls.LoadoutBadge;
8+
using ReactiveUI;
9+
using ReactiveUI.Fody.Helpers;
10+
11+
namespace NexusMods.App.UI.Controls.LoadoutCard;
12+
13+
public class LoadoutCardDesignViewModel : AViewModel<ILoadoutCardViewModel>, ILoadoutCardViewModel
14+
{
15+
public LoadoutCardDesignViewModel()
16+
{
17+
this.WhenActivated(d =>
18+
{
19+
// Cycle thorough all the states for preview purposes
20+
Observable.Interval(TimeSpan.FromSeconds(2.5))
21+
.Subscribe(_ =>
22+
{
23+
IsDeleting = !IsDeleting;
24+
})
25+
.DisposeWith(d);
26+
}
27+
);
28+
}
29+
30+
public ILoadoutBadgeViewModel LoadoutBadgeViewModel { get; } = new LoadoutBadgeDesignViewModel();
31+
public string LoadoutName { get; } = "Loadout B";
32+
public IImage LoadoutImage { get; } = new Bitmap(AssetLoader.Open(new Uri("avares://NexusMods.App.UI/Assets/DesignTime/cyberpunk_game.png")));
33+
34+
public bool IsLoadoutApplied { get; } = true;
35+
public string HumanizedLoadoutLastApplyTime { get; } = "Last applied 2 months ago";
36+
public string HumanizedLoadoutCreationTime { get; } = "Created 10 months ago";
37+
public string LoadoutModCount { get; } = "Mods 276";
38+
[Reactive] public bool IsDeleting { get; private set; } = true;
39+
public ReactiveCommand<Unit, Unit> VisitLoadoutCommand { get; } = ReactiveCommand.Create(() => { });
40+
public ReactiveCommand<Unit, Unit> CloneLoadoutCommand { get; } = ReactiveCommand.Create(() => { });
41+
public ReactiveCommand<Unit, Unit> DeleteLoadoutCommand { get; } = ReactiveCommand.Create(() => { });
42+
}

src/NexusMods.App.UI/Controls/LoadoutCard/LoadoutCardView.axaml

+68-51
Original file line numberDiff line numberDiff line change
@@ -7,79 +7,96 @@
77
xmlns:panels="clr-namespace:Avalonia.Labs.Panels;assembly=Avalonia.Labs.Panels"
88
xmlns:icons="clr-namespace:NexusMods.Icons;assembly=NexusMods.Icons"
99
xmlns:loadoutBadge="clr-namespace:NexusMods.App.UI.Controls.LoadoutBadge"
10+
xmlns:spinner="clr-namespace:NexusMods.App.UI.Controls.Spinner"
1011
mc:Ignorable="d" d:DesignWidth="250" d:DesignHeight="400"
1112
x:Class="NexusMods.App.UI.Controls.LoadoutCard.LoadoutCardView">
12-
<Button x:Name="CardOuterButton">
13+
<Design.DataContext>
14+
<loadoutCard:LoadoutCardDesignViewModel />
15+
</Design.DataContext>
16+
17+
<Border x:Name="ContainerBorder">
18+
<Grid>
19+
<Button x:Name="CardOuterButton">
1320

14-
<panels:FlexPanel x:Name="CardOuterFlexPanel">
21+
<panels:FlexPanel x:Name="CardOuterFlexPanel">
1522

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>
23+
<Border x:Name="ImageSectionBorder">
24+
<Grid>
25+
<Image x:Name="GameImage" />
26+
<Rectangle x:Name="GradientLayerRectangle" />
27+
<loadoutBadge:LoadoutBadge x:Name="LoadoutBadge" Classes="CardSize" />
28+
</Grid>
29+
</Border>
2430

25-
<Border x:Name="DetailsSectionBorder">
31+
<Border x:Name="DetailsSectionBorder">
2632

27-
<panels:FlexPanel x:Name="DetailsSectionFlexPanel">
33+
<panels:FlexPanel x:Name="DetailsSectionFlexPanel">
2834

29-
<TextBlock x:Name="LoadoutNameTextBlock"
30-
Classes="BodyLGBold"
31-
Text="Loadout A" />
35+
<TextBlock x:Name="LoadoutNameTextBlock"
36+
Classes="BodyLGBold" />
3237

33-
<panels:FlexPanel x:Name="BodyAndActionsGroupFlexPanel">
38+
<panels:FlexPanel x:Name="BodyAndActionsGroupFlexPanel">
3439

35-
<panels:FlexPanel x:Name="DetailsBodyFlexPanel">
40+
<panels:FlexPanel x:Name="DetailsBodyFlexPanel">
3641

37-
<panels:FlexPanel x:Name="CurrentlyAppliedFlexPanel">
42+
<panels:FlexPanel x:Name="CurrentlyAppliedFlexPanel">
3843

39-
<TextBlock x:Name="CurrentlyAppliedTextBlock"
40-
Classes="BodySMBold"
41-
Text="Currently Applied" />
42-
<icons:UnifiedIcon x:Name="AppliedCheckBoxIcon"
43-
Classes="CheckBox" />
44+
<TextBlock x:Name="CurrentlyAppliedTextBlock"
45+
Classes="BodySMBold"
46+
Text="Currently Applied" />
47+
<icons:UnifiedIcon x:Name="AppliedCheckBoxIcon"
48+
Classes="CheckBox" />
4449

45-
</panels:FlexPanel>
50+
</panels:FlexPanel>
4651

47-
<TextBlock x:Name="LastAppliedTimeTextBlock"
48-
Classes="BodySMNormal ForegroundSubdued"
49-
Text="Last applied 2 months ago"
50-
IsVisible="False" />
52+
<TextBlock x:Name="LastAppliedTimeTextBlock"
53+
Classes="BodySMNormal ForegroundSubdued"
54+
IsVisible="False" />
5155

52-
<TextBlock x:Name="CreatedTimeTextBlock"
53-
Classes="BodySMNormal ForegroundSubdued"
54-
Text="Created 10 months ago" />
56+
<TextBlock x:Name="CreatedTimeTextBlock"
57+
Classes="BodySMNormal ForegroundSubdued"/>
5558

56-
<TextBlock x:Name="NumberOfModsTextBlock"
57-
Classes="BodySMNormal ForegroundSubdued"
58-
Text="Mods 276" />
59+
<TextBlock x:Name="NumberOfModsTextBlock"
60+
Classes="BodySMNormal ForegroundSubdued"/>
5961

60-
</panels:FlexPanel>
62+
</panels:FlexPanel>
6163

62-
<panels:FlexPanel x:Name="ActionsFlexPanel">
64+
<panels:FlexPanel x:Name="ActionsFlexPanel">
6365

64-
<Button x:Name="CreateCopyButton"
65-
Classes="Rounded Primary">
66-
<StackPanel HorizontalAlignment="Center">
67-
<TextBlock Classes="BodySMBold" Text="Create Copy" />
68-
</StackPanel>
69-
</Button>
66+
<Button x:Name="CreateCopyButton"
67+
Classes="Rounded Primary">
68+
<StackPanel HorizontalAlignment="Center">
69+
<TextBlock Classes="BodySMBold" Text="Create Copy" />
70+
</StackPanel>
71+
</Button>
7072

7173

72-
<Button x:Name="DeleteButton"
73-
Classes="Rounded Primary">
74-
<icons:UnifiedIcon Classes="TrashCanOutline" />
75-
</Button>
76-
</panels:FlexPanel>
74+
<Button x:Name="DeleteButton"
75+
Classes="Rounded Primary">
76+
<icons:UnifiedIcon Classes="TrashCanOutline" />
77+
</Button>
78+
</panels:FlexPanel>
79+
80+
</panels:FlexPanel>
7781

78-
</panels:FlexPanel>
82+
</panels:FlexPanel>
83+
</Border>
7984

8085
</panels:FlexPanel>
81-
</Border>
86+
</Button>
87+
88+
<!-- Needs to be on top of the card button to avoid the disabled opacity -->
89+
<panels:FlexPanel x:Name="OverlayFlexPanel" IsVisible="False">
90+
<panels:FlexPanel x:Name="DeletingSpinnerFlexPanel">
91+
<spinner:Spinner x:Name="DeletingSpinner" />
92+
<TextBlock x:Name="DeletingTextBlock"
93+
Classes="BodyXLNormal ForegroundSubdued"
94+
Text="Deleting..." />
95+
</panels:FlexPanel>
96+
<Border />
97+
</panels:FlexPanel>
98+
</Grid>
99+
</Border>
100+
82101

83-
</panels:FlexPanel>
84-
</Button>
85102
</reactiveUi:ReactiveUserControl>

src/NexusMods.App.UI/Controls/LoadoutCard/LoadoutCardView.axaml.cs

+86
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
using System.Reactive.Disposables;
2+
using System.Reactive.Linq;
13
using Avalonia.ReactiveUI;
4+
using ReactiveUI;
25

36
namespace NexusMods.App.UI.Controls.LoadoutCard;
47

@@ -7,6 +10,89 @@ public partial class LoadoutCardView : ReactiveUserControl<ILoadoutCardViewModel
710
public LoadoutCardView()
811
{
912
InitializeComponent();
13+
14+
this.WhenActivated(d =>
15+
{
16+
// LoadoutBadge
17+
this.OneWayBind(ViewModel,
18+
vm => vm.LoadoutBadgeViewModel,
19+
view => view.LoadoutBadge.ViewModel)
20+
.DisposeWith(d);
21+
22+
// Game Image
23+
this.OneWayBind(ViewModel,
24+
vm => vm.LoadoutImage,
25+
view => view.GameImage.Source)
26+
.DisposeWith(d);
27+
28+
// Loadout Name
29+
this.OneWayBind(ViewModel,
30+
vm => vm.LoadoutName,
31+
view => view.LoadoutNameTextBlock.Text)
32+
.DisposeWith(d);
33+
34+
// Currently applied visibility
35+
this.OneWayBind(ViewModel,
36+
vm => vm.IsLoadoutApplied,
37+
view => view.CurrentlyAppliedFlexPanel.IsVisible)
38+
.DisposeWith(d);
39+
40+
// Last applied visibility
41+
this.WhenAnyValue(view => view.ViewModel!.IsLoadoutApplied)
42+
.Select(isApplied => !isApplied)
43+
.OnUI()
44+
.BindToView(this, view => view.LastAppliedTimeTextBlock.IsVisible)
45+
.DisposeWith(d);
46+
47+
// Last applied time
48+
this.OneWayBind(ViewModel,
49+
vm => vm.HumanizedLoadoutLastApplyTime,
50+
view => view.LastAppliedTimeTextBlock.Text)
51+
.DisposeWith(d);
52+
53+
// Created time
54+
this.OneWayBind(ViewModel,
55+
vm => vm.HumanizedLoadoutCreationTime,
56+
view => view.CreatedTimeTextBlock.Text)
57+
.DisposeWith(d);
58+
59+
// Mod count
60+
this.OneWayBind(ViewModel,
61+
vm => vm.LoadoutModCount,
62+
view => view.NumberOfModsTextBlock.Text)
63+
.DisposeWith(d);
64+
65+
// Deleting state
66+
this.WhenAnyValue(view => view.ViewModel!.IsDeleting)
67+
.OnUI()
68+
.Subscribe(isDeleting =>
69+
{
70+
IsEnabled = !isDeleting;
71+
OverlayFlexPanel.IsVisible = isDeleting;
72+
CreateCopyButton.IsVisible = !isDeleting;
73+
DeleteButton.IsVisible = !isDeleting;
74+
})
75+
.DisposeWith(d);
76+
77+
// Clone loadout command
78+
this.BindCommand(ViewModel,
79+
vm => vm.CloneLoadoutCommand,
80+
view => view.CreateCopyButton)
81+
.DisposeWith(d);
82+
83+
// Delete loadout command
84+
this.BindCommand(ViewModel,
85+
vm => vm.DeleteLoadoutCommand,
86+
view => view.DeleteButton)
87+
.DisposeWith(d);
88+
89+
// Visit loadout command
90+
this.BindCommand(ViewModel,
91+
vm => vm.DeleteLoadoutCommand,
92+
view => view.DeleteButton)
93+
.DisposeWith(d);
94+
}
95+
);
1096
}
1197
}
1298

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

+6
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,12 @@
561561
<Compile Update="Controls\Settings\Section\SettingSectionViewModel.cs">
562562
<DependentUpon>ISettingSectionViewModel.cs</DependentUpon>
563563
</Compile>
564+
<Compile Update="Controls\LoadoutBadge\LoadoutBadgeDesignViewModel.cs">
565+
<DependentUpon>ILoadoutBadgeViewModel.cs</DependentUpon>
566+
</Compile>
567+
<Compile Update="Controls\LoadoutCard\LoadoutCardDesignViewModel.cs">
568+
<DependentUpon>ILoadoutCardViewModel.cs</DependentUpon>
569+
</Compile>
564570
</ItemGroup>
565571

566572
<ItemGroup>

0 commit comments

Comments
 (0)