fix: open a livery's folder whatever the case of its name

"Open texture folder" finds the folder under dynamic, or from the game
folder, through CaseInsensitivePaths, so on Linux it opens the folder
when textures.txt names it in other letter case.
This commit is contained in:
maj00r
2026-11-13 16:09:52 +01:00
parent 2efae83b57
commit 7f57160aae
3 changed files with 50 additions and 8 deletions

View File

@@ -0,0 +1,22 @@
using StarterNG.Domain.Vehicles;
using StarterNG.Infrastructure.Vehicles;
using StarterNG.Tests.Fakes;
namespace StarterNG.Tests;
public class TextureFolderTests
{
private static readonly TestInstallation Installation = new(new InMemoryFileSystem(caseSensitive: true)
.WithFile("game/dynamic/PKP/EP09_v1/textures.txt", "")
.WithDirectory("game/Other/Folder"));
[Theory]
[InlineData("pkp/ep09_v1/", "dynamic/PKP/EP09_v1")]
[InlineData(@"PKP\EP09_V1", "dynamic/PKP/EP09_v1")]
[InlineData("other/folder/", "Other/Folder")]
[InlineData("pkp/brak/", "pkp/brak")]
public void A_liverys_folder_is_found_as_it_is_named_on_disk(string named, string onDisk) =>
Assert.Equal(Path.GetFullPath(Path.Combine("game", onDisk)),
Path.GetFullPath(TextureFolder.Of(Installation.Files, Installation.Paths,
new VehicleTexture { Directory = named })));
}

View File

@@ -0,0 +1,24 @@
using System.IO;
using StarterNG.Application.Abstractions;
using StarterNG.Domain.Vehicles;
namespace StarterNG.Infrastructure.Vehicles;
public static class TextureFolder
{
/// <summary>
/// A livery's folder as it is named on disk: under dynamic, or from the game's folder
/// when its name starts there, in any letter case. Where it would be when it is not there.
/// </summary>
public static string Of(IFileSystem files, IGamePaths paths, VehicleTexture texture)
{
string directory = texture.Directory.Replace('\\', '/').TrimEnd('/');
if (directory.Length == 0)
return paths.Dynamic;
var names = new CaseInsensitivePaths(files);
return names.Find(paths.Dynamic, directory, directory: true) ??
names.Find(paths.Root, directory, directory: true) ??
Path.Combine(paths.Root, directory.Replace('/', Path.DirectorySeparatorChar));
}
}

View File

@@ -1,8 +1,10 @@
using System.IO;
using Avalonia.Controls;
using Avalonia.Input.Platform;
using StarterNG.Application;
using StarterNG.Domain;
using StarterNG.Domain.Vehicles;
using StarterNG.Infrastructure.Vehicles;
namespace StarterNG.Views;
@@ -17,13 +19,7 @@ internal static class TextureMenuItems
if (TopLevel.GetTopLevel(owner)?.Clipboard is { } clipboard)
await clipboard.SetTextAsync(Consist.Base(texture.Skinfile));
});
menu.AddItem(App.Loc["OpenTextureFolder"], () => Infrastructure.Diagnostics.OpenOrReport(FolderOf(texture)));
}
private static string FolderOf(VehicleTexture texture)
{
string dir = Path.Combine(Directory.GetCurrentDirectory(), "dynamic",
texture.Directory.Replace('/', Path.DirectorySeparatorChar).TrimEnd('\\', '/'));
return Directory.Exists(dir) ? dir : Path.Combine(Directory.GetCurrentDirectory(), texture.Directory);
menu.AddItem(App.Loc["OpenTextureFolder"], () => Infrastructure.Diagnostics.OpenOrReport(
Path.GetFullPath(TextureFolder.Of(AppServices.Current.Files, AppServices.Current.Paths, texture))));
}
}