Skip to content

Commit

Permalink
Merge pull request #1967 from Nexus-Mods/fix/viewModFiles
Browse files Browse the repository at this point in the history
Add ViewModFiles implementation to new Loadout View
  • Loading branch information
Al12rs authored Sep 3, 2024
2 parents 522942d + d448c6d commit b93b0f6
Show file tree
Hide file tree
Showing 14 changed files with 266 additions and 143 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,34 @@
using System.Runtime.InteropServices;
using Avalonia.Controls;
using DynamicData;
using DynamicData.Kernel;
using Humanizer.Bytes;
using NexusMods.Abstractions.GameLocators;
using NexusMods.Abstractions.Loadouts;
using NexusMods.App.UI.Controls.Trees.Files;
using NexusMods.App.UI.Helpers.TreeDataGrid;
using NexusMods.App.UI.Resources;
using NexusMods.MnemonicDB.Abstractions;
using NexusMods.MnemonicDB.Abstractions.ElementComparers;
using NexusMods.MnemonicDB.Abstractions.IndexSegments;
using NexusMods.Paths;

namespace NexusMods.App.UI.Controls.Trees;
using DirectoryData = (Size size, uint numFiles, GamePath path, GamePath parentPath);

public class LoadoutGroupFileTreeViewModel : AViewModel<IFileTreeViewModel>, IFileTreeViewModel

public class LoadoutItemGroupFileTreeViewModel : AViewModel<IFileTreeViewModel>, IFileTreeViewModel
{
public ITreeDataGridSource<IFileTreeNodeViewModel> TreeSource { get; }
public ReadOnlyObservableCollection<string> StatusBarStrings { get; }

public LoadoutGroupFileTreeViewModel(LoadoutItemGroup.ReadOnly group)
public LoadoutItemGroupFileTreeViewModel(LoadoutItemGroup.ReadOnly group)
{
var totalNumFiles = 0;
var totalSize = Size.Zero;

var nodes = new List<IFileTreeNodeViewModel>();
var directories = new Dictionary<GamePath, (Size size, uint numFiles, GamePath path, GamePath parentPath)>();
var directories = new Dictionary<GamePath, DirectoryData>();

foreach (var loadoutItem in group.Children.OfTypeLoadoutItemWithTargetPath())
{
Expand All @@ -35,14 +41,7 @@ public LoadoutGroupFileTreeViewModel(LoadoutItemGroup.ReadOnly group)
size = loadoutFile.Size;
}

var node = new FileTreeNodeViewModel(
fullPath: loadoutItem.TargetPath,
parentPath: ((GamePath)loadoutItem.TargetPath).Parent,
isFile: true,
fileSize: size.Value,
numChildFiles: 0,
isDeletion: loadoutItem.IsDeletedFile()
);
var node = CreateFileNode(loadoutItem, size);

nodes.Add(node);

Expand Down Expand Up @@ -84,29 +83,14 @@ public LoadoutGroupFileTreeViewModel(LoadoutItemGroup.ReadOnly group)
foreach (var kv in directories)
{
var (_, directory) = kv;
var (size, numFiles, path, parentPath) = directory;

if (parentPath.Equals(IFileTreeViewModel.RootParentGamePath))
if (directory.parentPath.Equals(IFileTreeViewModel.RootParentGamePath))
{
nodes.Add(new FileTreeNodeViewModel(
name: locationsRegister[path.LocationId].ToString(),
fullPath: path,
parentPath: parentPath,
isFile: false,
fileSize: size.Value,
numChildFiles: numFiles
));
nodes.Add(CreateRootNode(locationsRegister, directory));
}
else
{
nodes.Add(new FileTreeNodeViewModel(
fullPath: path,
parentPath: parentPath,
isFile: false,
fileSize: size.Value,
numChildFiles: numFiles,
isDeletion: false
));
nodes.Add(CreateFolderNode(directory));
}
}

Expand All @@ -127,6 +111,85 @@ public LoadoutGroupFileTreeViewModel(LoadoutItemGroup.ReadOnly group)
string.Format(Language.ModFileTreeViewModel_StatusBar_Files__0__1, totalNumFiles, ByteSize.FromBytes(totalSize.Value).ToString()),
}));
}

/// <summary>
/// Returns the appropriate LoadoutItemGroup of files if the selection contains a LoadoutItemGroup containing files,
/// if the selection contains multiple LoadoutItemGroups of files, returns None.
/// </summary>
internal static Optional<LoadoutItemGroup.ReadOnly> GetViewModFilesLoadoutItemGroup(
IReadOnlyCollection<LoadoutItemId> loadoutItemIds,
IConnection connection)
{
var db = connection.Db;
// Only allow when selecting a single item, or an item with a single child
if (loadoutItemIds.Count != 1) return Optional<LoadoutItemGroup.ReadOnly>.None;
var currentGroupId = loadoutItemIds.First();

var groupDatoms = db.Datoms(LoadoutItemGroup.Group, Null.Instance);

while (true)
{
var childDatoms = db.Datoms(LoadoutItem.ParentId, currentGroupId);
var childGroups = groupDatoms.MergeByEntityId(childDatoms);

// We have no child groups, check if children are files
if (childGroups.Count == 0)
{
return LoadoutItemWithTargetPath.TryGet(db, childDatoms[0].E, out _)
? LoadoutItemGroup.Load(db, currentGroupId)
: Optional<LoadoutItemGroup.ReadOnly>.None;
}

// Single child group, check if that group is valid
if (childGroups.Count == 1)
{
currentGroupId = childGroups.First();
continue;
}

// We have multiple child groups, return None
if (childGroups.Count > 1) return Optional<LoadoutItemGroup.ReadOnly>.None;
}
}

private static FileTreeNodeViewModel CreateFolderNode(DirectoryData directory)
{
var (size, numFiles, path, parentPath) = directory;
return new FileTreeNodeViewModel(
fullPath: path,
parentPath: parentPath,
isFile: false,
fileSize: size.Value,
numChildFiles: numFiles,
isDeletion: false
);
}

private static FileTreeNodeViewModel CreateRootNode(IGameLocationsRegister locationsRegister, DirectoryData directory)
{
var (size, numFiles, path, parentPath) = directory;
return new FileTreeNodeViewModel(
name: locationsRegister[path.LocationId].ToString(),
fullPath: path,
parentPath: parentPath,
isFile: false,
fileSize: size.Value,
numChildFiles: numFiles
);
}


private static FileTreeNodeViewModel CreateFileNode(LoadoutItemWithTargetPath.ReadOnly loadoutItem, Size size)
{
return new FileTreeNodeViewModel(
fullPath: loadoutItem.TargetPath,
parentPath: ((GamePath)loadoutItem.TargetPath).Parent,
isFile: true,
fileSize: size.Value,
numChildFiles: 0,
isDeletion: loadoutItem.IsDeletedFile()
);
}

internal static HierarchicalTreeDataGridSource<IFileTreeNodeViewModel> CreateTreeSource(
ReadOnlyObservableCollection<IFileTreeNodeViewModel> roots)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace NexusMods.App.UI.Controls.Trees;
/// <summary>
/// This is one implementation of the IFileTreeViewModel, which is used to display a tree of files in a mod.
/// </summary>
[Obsolete($"To be replaced by {nameof(LoadoutGroupFileTreeViewModel)}")]
[Obsolete($"To be replaced by {nameof(LoadoutItemGroupFileTreeViewModel)}")]
public class ModFileTreeViewModel : AViewModel<IFileTreeViewModel>, IFileTreeViewModel
{
private readonly IConnection _conn;
Expand Down
8 changes: 7 additions & 1 deletion src/NexusMods.App.UI/NexusMods.App.UI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@
<Compile Update="Controls\LoadoutBadge\LoadoutBadgeViewModel.cs">
<DependentUpon>ILoadoutBadgeViewModel.cs</DependentUpon>
</Compile>
<Compile Update="Controls\Trees\LoadoutGroupFileTreeViewModel.cs">
<Compile Update="Controls\Trees\LoadoutItemGroupFileTreeViewModel.cs">
<DependentUpon>IFileTreeViewModel.cs</DependentUpon>
</Compile>
<Compile Update="Pages\LoadoutGroupFiles\LoadoutGroupFilesViewModel.cs">
Expand Down Expand Up @@ -622,6 +622,12 @@
<Compile Update="Pages\NexusModsDataProvider.cs">
<DependentUpon>ILibraryDataProvider.cs</DependentUpon>
</Compile>
<Compile Update="Pages\ItemContentsFileTree\ItemContentsFileTreeViewModel.cs">
<DependentUpon>IItemContentsFileTreeViewModel.cs</DependentUpon>
</Compile>
<Compile Update="Pages\ItemContentsFileTree\ItemContentsFileTreeView.cs">
<DependentUpon>ItemContentsFileTreeView.axaml</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
using NexusMods.App.UI.WorkspaceSystem;
using ReactiveUI;

namespace NexusMods.App.UI.Pages.LoadoutGroupFiles;
namespace NexusMods.App.UI.Pages.ItemContentsFileTree;

public interface ILoadoutGroupFilesViewModel : IPageViewModelInterface
public interface IItemContentsFileTreeViewModel : IPageViewModelInterface
{
LoadoutGroupFilesPageContext? Context { get; set; }
ItemContentsFileTreePageContext? Context { get; set; }

IFileTreeViewModel? FileTreeViewModel { get; }

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
using NexusMods.Abstractions.Loadouts;
using NexusMods.Abstractions.Serialization.Attributes;
using NexusMods.App.UI.WorkspaceSystem;

namespace NexusMods.App.UI.Pages.ItemContentsFileTree;

[JsonName("NexusMods.App.UI.Pages.ItemContentsFileTreePageContext")]
public record ItemContentsFileTreePageContext : IPageFactoryContext
{
public required LoadoutItemGroupId GroupId { get; init; }
}

[UsedImplicitly]
public class ItemContentsFileTreePageFactory : APageFactory<IItemContentsFileTreeViewModel, ItemContentsFileTreePageContext>
{
public ItemContentsFileTreePageFactory(IServiceProvider serviceProvider) : base(serviceProvider) { }

public static readonly PageFactoryId StaticId = PageFactoryId.From(Guid.Parse("85d19521-0414-4a31-a873-43757234ed43"));
public override PageFactoryId Id => StaticId;

public override IItemContentsFileTreeViewModel CreateViewModel(ItemContentsFileTreePageContext context)
{
var vm = ServiceProvider.GetRequiredService<IItemContentsFileTreeViewModel>();
vm.Context = context;
return vm;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<reactive:ReactiveUserControl
x:TypeArguments="local:ILoadoutGroupFilesViewModel"
x:TypeArguments="itemContentsFileTree:IItemContentsFileTreeViewModel"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Expand All @@ -8,9 +8,9 @@
xmlns:navigation="clr-namespace:NexusMods.App.UI.Controls.Navigation"
xmlns:icons="clr-namespace:NexusMods.Icons;assembly=NexusMods.Icons"
xmlns:reactive="http://reactiveui.net"
xmlns:local="clr-namespace:NexusMods.App.UI.Pages.LoadoutGroupFiles"
xmlns:itemContentsFileTree="clr-namespace:NexusMods.App.UI.Pages.ItemContentsFileTree"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="NexusMods.App.UI.Pages.LoadoutGroupFiles.LoadoutGroupFilesView">
x:Class="NexusMods.App.UI.Pages.ItemContentsFileTree.ItemContentsFileTreeView">

<Grid RowDefinitions="Auto, *">
<Border Grid.Row="0" Classes="Toolbar">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
using Avalonia.ReactiveUI;
using ReactiveUI;

namespace NexusMods.App.UI.Pages.LoadoutGroupFiles;
namespace NexusMods.App.UI.Pages.ItemContentsFileTree;

public partial class LoadoutGroupFilesView : ReactiveUserControl<ILoadoutGroupFilesViewModel>
public partial class ItemContentsFileTreeView : ReactiveUserControl<IItemContentsFileTreeViewModel>
{
public LoadoutGroupFilesView()
public ItemContentsFileTreeView()
{
InitializeComponent();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@
using ReactiveUI;
using ReactiveUI.Fody.Helpers;

namespace NexusMods.App.UI.Pages.LoadoutGroupFiles;
namespace NexusMods.App.UI.Pages.ItemContentsFileTree;

[UsedImplicitly]
public class LoadoutGroupFilesViewModel : APageViewModel<ILoadoutGroupFilesViewModel>, ILoadoutGroupFilesViewModel
public class ItemContentsFileTreeViewModel : APageViewModel<IItemContentsFileTreeViewModel>, IItemContentsFileTreeViewModel
{
[Reactive] public LoadoutGroupFilesPageContext? Context { get; set; }
[Reactive] public ItemContentsFileTreePageContext? Context { get; set; }
[Reactive] public IFileTreeViewModel? FileTreeViewModel { get; [UsedImplicitly] private set; }
[Reactive] public FileTreeNodeViewModel? SelectedItem { get; [UsedImplicitly] private set; }

public ReactiveCommand<NavigationInformation, Unit> OpenEditorCommand { get; }

public LoadoutGroupFilesViewModel(
ILogger<LoadoutGroupFilesViewModel> logger,
public ItemContentsFileTreeViewModel(
ILogger<ItemContentsFileTreeViewModel> logger,
IWindowManager windowManager,
IConnection connection) : base(windowManager)
{
Expand Down Expand Up @@ -71,7 +71,7 @@ public LoadoutGroupFilesViewModel(
.WhereNotNull()
.Select(context => LoadoutItemGroup.Load(connection.Db, context.GroupId))
.Where(group => group.IsValid())
.Select(group => new LoadoutGroupFileTreeViewModel(group))
.Select(group => new LoadoutItemGroupFileTreeViewModel(group))
.BindToVM(this, vm => vm.FileTreeViewModel)
.DisposeWith(disposables);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
using NexusMods.Abstractions.Settings;
using NexusMods.App.UI.Controls.DataGrid;
using NexusMods.App.UI.Controls.Navigation;
using NexusMods.App.UI.Pages.ItemContentsFileTree;
using NexusMods.App.UI.Pages.LoadoutGrid.Columns.ModEnabled;
using NexusMods.App.UI.Pages.LoadoutGrid.Columns.ModInstalled;
using NexusMods.App.UI.Pages.LoadoutGrid.Columns.ModName;
using NexusMods.App.UI.Pages.LoadoutGroupFiles;
using NexusMods.App.UI.Pages.ModLibrary;
using NexusMods.App.UI.Resources;
using NexusMods.App.UI.Windows;
Expand Down Expand Up @@ -107,8 +107,8 @@ public LoadoutGridViewModel(

var pageData = new PageData
{
FactoryId = LoadoutGroupFilesPageFactory.StaticId,
Context = new LoadoutGroupFilesPageContext
FactoryId = ItemContentsFileTreePageFactory.StaticId,
Context = new ItemContentsFileTreePageContext
{
GroupId = groupId,
},
Expand Down

This file was deleted.

3 changes: 2 additions & 1 deletion src/NexusMods.App.UI/Pages/LoadoutPage/ILoadoutViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using NexusMods.App.UI.Controls.Navigation;
using NexusMods.App.UI.WorkspaceSystem;

namespace NexusMods.App.UI.Pages.LoadoutPage;
Expand All @@ -8,7 +9,7 @@ public interface ILoadoutViewModel : IPageViewModelInterface

R3.ReactiveCommand<R3.Unit> SwitchViewCommand { get; }

R3.ReactiveCommand<R3.Unit> ViewFilesCommand { get; }
R3.ReactiveCommand<NavigationInformation> ViewFilesCommand { get; }

R3.ReactiveCommand<R3.Unit> RemoveItemCommand { get; }
}
Loading

0 comments on commit b93b0f6

Please sign in to comment.