Skip to content

Commit

Permalink
Merge pull request #2335 from Nexus-Mods/load-order-styling-4
Browse files Browse the repository at this point in the history
Load order styling - Part 4
  • Loading branch information
Al12rs authored Dec 3, 2024
2 parents 00daa9f + 5f8ac6f commit 6e84064
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,14 @@ public class RedModSortableItemProviderFactory : ISortableItemProviderFactory
For example, the 1st position overwrites the 2nd, the 2nd overwrites the 3rd, and so on.
""";
public string WinnerIndexToolTip => "First Loaded RedMOD Wins: Items that load first will overwrite changes from items loaded after them.";

public string WinnerIndexToolTip => "The REDmod that will overwrite all others";
public string IndexColumnHeader => "LOAD ORDER";

public string IndexColumnHeader => "Load Order";

public string NameColumnHeader => "REDmod Name";
public string NameColumnHeader => "REDMOD NAME";

public string EmptyStateMessageTitle => "No REDmods detected";
public string EmptyStateMessageContents => "Some mods contain REDmods modules that can alter core gameplay elements. When detected they will appear here for load order configuration.";
public string EmptyStateMessageContents => "Some mods contain REDmod items that alter core gameplay elements. When detected, they will appear here for load order configuration.";

public ListSortDirection SortDirectionDefault => ListSortDirection.Ascending;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,24 @@ public interface ILoadOrderItemModel : ITreeDataGridItemModel<ILoadOrderItemMode

public string ModName { get; }
public bool IsActive { get; }
public string DisplaySortIndex { get; }

/// <summary>
/// Converts a zero-based index to an ordinal number string with the appropriate suffix.
/// </summary>
/// <param name="sortIndex">The zero-based index to convert</param>
/// <returns>A string representing the ordinal number with the appropriate suffix.</returns>
protected static string ConvertZeroIndexToOrdinalNumber(int sortIndex)
{
var displayIndex = sortIndex + 1;
var suffix = displayIndex switch
{
11 or 12 or 13 => "th",
_ when displayIndex % 10 == 1 => "st",
_ when displayIndex % 10 == 2 => "nd",
_ when displayIndex % 10 == 3 => "rd",
_ => "th"
};
return $"{displayIndex}{suffix}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ public class LoadOrderItemDesignModel : TreeDataGridItemModel<ILoadOrderItemMode
public string ModName { get; set; } = "Mod Name";
public bool IsActive { get; set; }
public Guid Guid { get; set; }
public string DisplaySortIndex => ILoadOrderItemModel.ConvertZeroIndexToOrdinalNumber(SortIndex);
}
14 changes: 11 additions & 3 deletions src/NexusMods.App.UI/Pages/Sorting/LoadOrder/LoadOrderItemModel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.ComponentModel;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using NexusMods.Abstractions.Games;
using NexusMods.App.UI.Controls;
using R3;
Expand Down Expand Up @@ -27,6 +28,8 @@ public class LoadOrderItemModel : TreeDataGridItemModel<ILoadOrderItemModel, Gui
[Reactive] public string ModName { get; private set; }
[Reactive] public bool IsActive { get; private set; }

[Reactive] public string DisplaySortIndex { get; private set; }

public LoadOrderItemModel(
ISortableItem sortableItem,
IObservable<ListSortDirection> sortDirectionObservable,
Expand All @@ -39,6 +42,7 @@ public LoadOrderItemModel(

IsActive = sortableItem.IsActive;
ModName = sortableItem.ModName;
DisplaySortIndex = SortIndex.ToString();

_sortDirectionObservable = sortDirectionObservable;
_lastIndexObservable = lastIndexObservable;
Expand Down Expand Up @@ -90,9 +94,13 @@ public LoadOrderItemModel(
},
canExecuteDown
);
}



sortIndexObservable
.Select(ILoadOrderItemModel.ConvertZeroIndexToOrdinalNumber)
.BindTo(this, vm => vm.DisplaySortIndex)
.DisposeWith(_disposables);
}

private bool _isDisposed;

protected override void Dispose(bool disposing)
Expand Down
62 changes: 43 additions & 19 deletions src/NexusMods.App.UI/Pages/Sorting/LoadOrder/LoadOrderView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,36 @@
<controls:EmptyState x:Name="EmptyState">

<controls:EmptyState.Subtitle>
<TextBlock x:Name="EmptySpaceMessageTextBlock"/>
<TextBlock x:Name="EmptySpaceMessageTextBlock" />
</controls:EmptyState.Subtitle>

<Grid RowDefinitions="Auto, Auto, *">

<!-- toolbar -->
<Border Grid.Row="0" Classes="Toolbar">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
<ComboBox x:Name="SortDirectionComboBox" SelectedIndex="0" Classes="Secondary Compact">
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<icons:UnifiedIcon Value="{x:Static icons:IconValues.SortAscending}" Size="20" />
<TextBlock Text="Ascending (1st top)" Theme="{StaticResource BodyMDNormalTheme}" />
<TextBlock Text="First -> Last" Theme="{StaticResource BodyMDNormalTheme}" />
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<icons:UnifiedIcon Value="{x:Static icons:IconValues.SortDescending}" Size="20" />
<TextBlock Text="Descending (1st bottom)" Theme="{StaticResource BodyMDNormalTheme}" />
<TextBlock Text="Last -> First" Theme="{StaticResource BodyMDNormalTheme}" />
</StackPanel>
</ComboBoxItem>
</ComboBox>
<CheckBox Content="Hide Disabled Collections" />
<Border Width="1" Height="28" Margin="4,0" Background="{StaticResource StrokeTranslucentWeakBrush}" />
<CheckBox Content="Hide Disabled Collections" IsEnabled="False" />
<Border Width="1" Height="28" Margin="4,0" Background="{StaticResource StrokeTranslucentWeakBrush}" />
<controls:StandardButton
Size="Small"
Text="Add to group" />
<ComboBox SelectedIndex="0" Classes="Secondary Compact">
Text="Add to group"
IsEnabled="False" />
<ComboBox SelectedIndex="0" Classes="Secondary Compact" IsEnabled="False">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="New group" Theme="{StaticResource BodyMDNormalTheme}" />
Expand All @@ -60,39 +64,42 @@
Severity="Info"
ShowDismiss="True"
Title="{CompiledBinding InfoAlertHeading}"
Body="{CompiledBinding InfoAlertMessage }"/>
Body="{CompiledBinding InfoAlertMessage }" />

<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock x:Name="TitleTextBlock" Theme="{StaticResource HeadingXSSemiTheme}" />
<controls:StandardButton x:Name="InfoAlertButton"
<controls:StandardButton x:Name="InfoAlertButton"
ShowIcon="IconOnly"
LeftIcon="{x:Static icons:IconValues.Info}"
Type="Tertiary"
Fill="None" />
</StackPanel>
</StackPanel>

<Grid Grid.Row="2" ColumnDefinitions="32, *" Margin="24,0,24,24">
<Grid Grid.Row="2" ColumnDefinitions="32, *" Margin="24,0, 24, 24">

<!-- left column (trophy bar) -->
<DockPanel x:Name="TrophyBarPanel" HorizontalAlignment="Left">
<!-- Transparent Background so the tooltip hit box covers the whole control -->
<DockPanel x:Name="TrophyBarPanel"
Background="{StaticResource SurfaceTransparentBrush}"
HorizontalAlignment="Left"
Margin="0,56,0,0"
ToolTip.Tip="{CompiledBinding TrophyToolTip}">
<icons:UnifiedIcon x:Name="TrophyIcon"
DockPanel.Dock="Top"
Margin="0,8,0,8"
Value="{x:Static icons:IconValues.Trophy}"
Size="20"
ToolTip.Tip="{CompiledBinding TrophyToolTip}" />

Size="20"/>
<Grid RowDefinitions="Auto, *, Auto" HorizontalAlignment="Center">
<icons:UnifiedIcon Grid.Row="0" x:Name="ArrowUpIcon"
Value="{x:Static icons:IconValues.ArrowUpThick}"
Size="20" />
Size="20"/>
<Border Grid.Row="1" x:Name="TrophyGradientBorder"
Width="3"
Margin="0,4" />
<icons:UnifiedIcon Grid.Row="2" x:Name="ArrowDownIcon"
Value="{x:Static icons:IconValues.ArrowDownThick}"
Size="20" />
Size="20"/>
</Grid>
</DockPanel>

Expand Down Expand Up @@ -125,7 +132,7 @@
Width="52"
Height="42">
<TextBlock x:Name="ItemIndex"
Text="{CompiledBinding SortIndex}"
Text="{CompiledBinding DisplaySortIndex}"
Foreground="{StaticResource NeutralTranslucentStrongBrush}"
Theme="{StaticResource BodyMDBoldTheme}"
HorizontalAlignment="Center" />
Expand All @@ -146,9 +153,26 @@

<DataTemplate x:Key="LoadOrderItemNameColumnTemplate"
DataType="sorting:ILoadOrderItemModel">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="ItemName"
Text="{CompiledBinding DisplayName}" />
<StackPanel Orientation="Horizontal" Spacing="12">

<Border
Background="{StaticResource SurfaceTranslucentMidBrush}"
Width="68"
Height="42"
BorderThickness="1"
BorderBrush="{StaticResource StrokeTranslucentSubduedBrush}"
CornerRadius="4">
<icons:UnifiedIcon Value="{x:Static icons:IconValues.Nexus}"
Foreground="{StaticResource NeutralSubduedBrush}" />
</Border>
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
<TextBlock x:Name="ItemName"
Text="{CompiledBinding ModName}"
Theme="{StaticResource BodySMNormalTheme}"
Foreground="{StaticResource NeutralTranslucentModerateBrush}" />
<TextBlock x:Name="ItemName2"
Text="{CompiledBinding DisplayName}" />
</StackPanel>
</StackPanel>
</DataTemplate>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public class LoadOrderDesignViewModel : AViewModel<ILoadOrderViewModel>, ILoadOr
public string InfoAlertMessage { get; set;} = "Info Alert Message";
public bool InfoAlertIsVisible { get; set; } = true;
public ReactiveCommand<Unit, Unit> InfoAlertCommand { get; } = ReactiveCommand.Create(() => { });
public string TrophyToolTip { get; set;} = "Trophy Tool Tip";
public string TrophyToolTip { get; } = "Winner Tooltip";
public ListSortDirection SortDirectionCurrent { get; set; }
public bool IsWinnerTop { get; set;}
public bool IsWinnerTop { get; set; } = true;
public string EmptyStateMessageTitle { get; } = "Empty State Message Title";
public string EmptyStateMessageContents { get; } = "Empty State Message Contents";
public AlertSettingsWrapper AlertSettingsWrapper { get; }
Expand All @@ -44,6 +44,21 @@ public LoadOrderDesignViewModel(ISettingsManager settingsManager)

AlertSettingsWrapper = new AlertSettingsWrapper(settingsManager, "cyberpunk2077 redmod load-order first-loaded-wins");
}

public LoadOrderDesignViewModel()
{
Adapter = new LoadOrderTreeDataGridDesignAdapter();

this.WhenActivated(d =>
{
Adapter.Activate();
Disposable.Create(() => Adapter.Deactivate())
.DisposeWith(d);
}
);

AlertSettingsWrapper = null!;
}
}


Expand All @@ -55,6 +70,10 @@ protected override IObservable<IChangeSet<ILoadOrderItemModel, Guid>> GetRootsOb
var items = new ObservableCollection<ILoadOrderItemModel>([
new LoadOrderItemDesignModel() { DisplayName = "Item 1", Guid = Guid.NewGuid(), SortIndex = 0 },
new LoadOrderItemDesignModel() { DisplayName = "Item 2", Guid = Guid.NewGuid(), SortIndex = 1 },
new LoadOrderItemDesignModel() { DisplayName = "Item 3", Guid = Guid.NewGuid(), SortIndex = 2 },
new LoadOrderItemDesignModel() { DisplayName = "Item 4", Guid = Guid.NewGuid(), SortIndex = 3 },
new LoadOrderItemDesignModel() { DisplayName = "Item 5", Guid = Guid.NewGuid(), SortIndex = 4 },
new LoadOrderItemDesignModel() { DisplayName = "Item 6", Guid = Guid.NewGuid(), SortIndex = 5 },
]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,37 @@ public SortingSelectionDesignViewModel(IServiceProvider serviceProvider)

var loadOrderViewModels = new ObservableCollection<ILoadOrderViewModel>
{
new LoadOrderDesignViewModel(_settingsManager)
new LoadOrderDesignViewModel()
{
SortOrderName = "Load order (RedMOD)",
InfoAlertHeading = "Load Order for REDmod files in Cyberpunk 2077 - First Loaded Wins",
InfoAlertMessage =
"Some Cyberpunk 2077 mods use REDmod files to alter core gameplay elements. If two REDmod files modify the same part of the game, the one loaded first will take priority and overwrite changes from those loaded later.\n\nFor example, the 1st position overwrites the 2nd, the 2nd overwrites the 3rd, and so on."
},
new LoadOrderDesignViewModel(_settingsManager) { SortOrderName = "Load Order (Archive XL)" },
new LoadOrderDesignViewModel(_settingsManager) { SortOrderName = "File Overwrites" }
new LoadOrderDesignViewModel() { SortOrderName = "Load Order (Archive XL)" },
new LoadOrderDesignViewModel() { SortOrderName = "File Overwrites" }
};

LoadOrderViewModels = new ReadOnlyObservableCollection<ILoadOrderViewModel>(loadOrderViewModels);
}

public SortingSelectionDesignViewModel()
{
_settingsManager = null!;

var loadOrderViewModels = new ObservableCollection<ILoadOrderViewModel>
{
new LoadOrderDesignViewModel()
{
SortOrderName = "Load order (RedMOD)",
InfoAlertHeading = "Load Order for REDmod files in Cyberpunk 2077 - First Loaded Wins",
InfoAlertMessage =
"Some Cyberpunk 2077 mods use REDmod files to alter core gameplay elements. If two REDmod files modify the same part of the game, the one loaded first will take priority and overwrite changes from those loaded later.\n\nFor example, the 1st position overwrites the 2nd, the 2nd overwrites the 3rd, and so on."
},
new LoadOrderDesignViewModel() { SortOrderName = "Load Order (Archive XL)" },
new LoadOrderDesignViewModel() { SortOrderName = "File Overwrites" }
};

LoadOrderViewModels = new ReadOnlyObservableCollection<ILoadOrderViewModel>(loadOrderViewModels);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveUi="http://reactiveui.net"
xmlns:sorting="clr-namespace:NexusMods.App.UI.Pages.Sorting"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600"
x:Class="NexusMods.App.UI.Pages.Sorting.SortingSelectionView">

<Design.DataContext>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@

<!-- header padding -->
<Style Selector="^ > Border > DockPanel > ItemsPresenter#PART_ItemsPresenter">
<Setter Property="Margin" Value="24,8" />
<Setter Property="Margin" Value="24,12" />
</Style>


Expand Down
Loading

0 comments on commit 6e84064

Please sign in to comment.