322 lines
12 KiB
Text
322 lines
12 KiB
Text
@page "/Games/{id:guid}"
|
|
@page "/Games/{id:guid}/{panel}"
|
|
@page "/Games/Add"
|
|
@using LANCommander.Components.FileManagerComponents;
|
|
@using LANCommander.Models;
|
|
@using LANCommander.Pages.Games.Components
|
|
@using System.IO.Compression;
|
|
@attribute [Authorize(Roles = "Administrator")]
|
|
@inject GameService GameService
|
|
@inject CompanyService CompanyService
|
|
@inject GenreService GenreService
|
|
@inject TagService TagService
|
|
@inject ArchiveService ArchiveService
|
|
@inject ScriptService ScriptService
|
|
@inject IMessageService MessageService
|
|
@inject NavigationManager NavigationManager
|
|
@inject ModalService ModalService
|
|
|
|
<Layout Class="panel-layout" Style="padding: 24px 0;">
|
|
<Sider Width="200">
|
|
<Menu Mode="@MenuMode.Inline" Style="height: 100%;">
|
|
<MenuItem RouterLink="@($"/Games/{Game.Id}/General")">General</MenuItem>
|
|
|
|
@if (Game != null && Game.Id != Guid.Empty)
|
|
{
|
|
<MenuItem RouterLink="@($"/Games/{Game.Id}/Actions")">Actions</MenuItem>
|
|
<MenuItem RouterLink="@($"/Games/{Game.Id}/Multiplayer")">Multiplayer</MenuItem>
|
|
<MenuItem RouterLink="@($"/Games/{Game.Id}/SavePaths")">Save Paths</MenuItem>
|
|
<MenuItem RouterLink="@($"/Games/{Game.Id}/Keys")">Keys</MenuItem>
|
|
<MenuItem RouterLink="@($"/Games/{Game.Id}/Scripts")">Scripts</MenuItem>
|
|
<MenuItem RouterLink="@($"/Games/{Game.Id}/Archives")">Archives</MenuItem>
|
|
}
|
|
</Menu>
|
|
</Sider>
|
|
|
|
<Content>
|
|
<PageHeader>
|
|
<PageHeaderTitle>
|
|
@if (Panel == null)
|
|
{
|
|
<Text>Add New Game</Text>
|
|
}
|
|
else if (PanelDisplayNames.ContainsKey(Panel))
|
|
{
|
|
@PanelDisplayNames[Panel]
|
|
}
|
|
else
|
|
{
|
|
@Panel
|
|
}
|
|
</PageHeaderTitle>
|
|
<PageHeaderExtra>
|
|
<Button Type="@ButtonType.Primary" OnClick="Save">Save</Button>
|
|
</PageHeaderExtra>
|
|
</PageHeader>
|
|
|
|
<div class="panel-layout-content">
|
|
<div data-panel="General">
|
|
<Form Model="@Game" Layout="@FormLayout.Vertical">
|
|
<FormItem Label="Title">
|
|
<Space Style="display: flex">
|
|
<SpaceItem Style="flex-grow: 1">
|
|
<Input @bind-Value="@context.Title" BindOnInput="true" />
|
|
</SpaceItem>
|
|
<SpaceItem>
|
|
<GameMetadataLookup ButtonText="Lookup" GameTitle="@context.Title" OnResultSelected="OnGameLookupResultSelected" />
|
|
</SpaceItem>
|
|
</Space>
|
|
</FormItem>
|
|
<FormItem Label="Sort Title">
|
|
<Input @bind-Value="@context.SortTitle" />
|
|
</FormItem>
|
|
<FormItem Label="Icon">
|
|
<FilePicker @bind-Value="context.Icon" ArchiveId="@LatestArchiveId" AllowDirectories="true" />
|
|
</FormItem>
|
|
<FormItem Label="Notes">
|
|
<TextArea @bind-Value="@context.Notes" MaxLength=2000 ShowCount />
|
|
</FormItem>
|
|
<FormItem Label="Description">
|
|
<TextArea @bind-Value="@context.Description" MaxLength=500 ShowCount />
|
|
</FormItem>
|
|
<FormItem Label="Released On">
|
|
<DatePicker TValue="DateTime?" @bind-Value="@context.ReleasedOn" Picker="@DatePickerType.Date" />
|
|
</FormItem>
|
|
<FormItem Label="Singleplayer">
|
|
<Checkbox @bind-Checked="@context.Singleplayer" />
|
|
</FormItem>
|
|
<FormItem Label="Developers">
|
|
<TagsInput Entities="Companies" @bind-Values="Game.Developers" OptionLabelSelector="c => c.Name" TItem="Company" />
|
|
</FormItem>
|
|
<FormItem Label="Publishers">
|
|
<TagsInput Entities="Companies" @bind-Values="Game.Publishers" OptionLabelSelector="c => c.Name" TItem="Company" />
|
|
</FormItem>
|
|
<FormItem Label="Genres">
|
|
<TagsInput Entities="Genres" @bind-Values="Game.Genres" OptionLabelSelector="c => c.Name" TItem="Genre" />
|
|
</FormItem>
|
|
<FormItem Label="Tags">
|
|
<TagsInput Entities="Tags" @bind-Values="Game.Tags" OptionLabelSelector="c => c.Name" TItem="Data.Models.Tag" />
|
|
</FormItem>
|
|
</Form>
|
|
</div>
|
|
|
|
@if (Game != null && Game.Id != Guid.Empty)
|
|
{
|
|
<div data-panel="Actions">
|
|
<ActionEditor @bind-Actions="Game.Actions" GameId="Game.Id" ArchiveId="@LatestArchiveId" />
|
|
</div>
|
|
|
|
<div data-panel="Multiplayer">
|
|
<MultiplayerModeEditor @bind-Value="Game.MultiplayerModes" />
|
|
</div>
|
|
|
|
<div data-panel="SavePaths">
|
|
<SavePathEditor @bind-Value="Game.SavePaths" GameId="Game.Id" ArchiveId="@LatestArchiveId" />
|
|
</div>
|
|
|
|
<div data-panel="Keys">
|
|
<KeysEditor @ref="KeysEditor" @bind-Keys="Game.Keys" GameId="Game.Id" />
|
|
|
|
<Button OnClick="() => KeysEditor.Edit()">Edit</Button>
|
|
</div>
|
|
|
|
<div data-panel="Scripts">
|
|
<ScriptEditor @bind-Scripts="Game.Scripts" GameId="Game.Id" ArchiveId="@LatestArchiveId" />
|
|
</div>
|
|
|
|
<div data-panel="Archives">
|
|
<ArchiveEditor @bind-Archives="Game.Archives" GameId="Game.Id" />
|
|
</div>
|
|
}
|
|
|
|
</div>
|
|
</Content>
|
|
</Layout>
|
|
|
|
@if (!String.IsNullOrWhiteSpace(Panel))
|
|
{
|
|
<style>
|
|
.panel-layout [data-panel="@Panel"] {
|
|
display: block;
|
|
}
|
|
</style>
|
|
}
|
|
else
|
|
{
|
|
<style>
|
|
.panel-layout [data-panel="General"] {
|
|
display: block;
|
|
}
|
|
</style>
|
|
}
|
|
|
|
@code {
|
|
[Parameter] public Guid Id { get; set; }
|
|
[Parameter] public string Panel { get; set; }
|
|
|
|
bool Success;
|
|
string[] Errors = { };
|
|
|
|
IEnumerable<Company> Companies;
|
|
IEnumerable<Genre> Genres;
|
|
IEnumerable<Data.Models.Tag> Tags;
|
|
|
|
FilePickerDialog ArchiveFilePickerDialog;
|
|
|
|
Modal FileSelectorModal;
|
|
|
|
private string value = "blazor";
|
|
|
|
private Game Game;
|
|
private KeysEditor? KeysEditor;
|
|
private GameMetadataLookup? GameMetadataLookup;
|
|
|
|
private Dictionary<string, string> PanelDisplayNames = new Dictionary<string, string>
|
|
{
|
|
{ "SavePaths", "Save Paths" }
|
|
};
|
|
|
|
private Guid LatestArchiveId
|
|
{
|
|
get
|
|
{
|
|
if (Game != null && Game.Archives != null && Game.Archives.Count > 0)
|
|
return Game.Archives.OrderByDescending(a => a.CreatedOn).FirstOrDefault().Id;
|
|
else
|
|
return Guid.Empty;
|
|
}
|
|
}
|
|
|
|
private int KeysAvailable { get {
|
|
return Game.Keys.Count(k =>
|
|
{
|
|
return (k.AllocationMethod == KeyAllocationMethod.MacAddress && String.IsNullOrWhiteSpace(k.ClaimedByMacAddress))
|
|
||
|
|
(k.AllocationMethod == KeyAllocationMethod.UserAccount && k.ClaimedByUser == null);
|
|
});
|
|
} }
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
if (Id == Guid.Empty)
|
|
Game = new Game();
|
|
else
|
|
Game = await GameService.Get(Id);
|
|
|
|
Companies = await CompanyService.Get();
|
|
Genres = await GenreService.Get();
|
|
Tags = await TagService.Get();
|
|
}
|
|
|
|
private async Task Save()
|
|
{
|
|
try
|
|
{
|
|
if (Game.Id != Guid.Empty)
|
|
{
|
|
Game = await GameService.Update(Game);
|
|
|
|
await MessageService.Success("Game updated!");
|
|
}
|
|
else
|
|
{
|
|
Game = await GameService.Add(Game);
|
|
|
|
NavigationManager.LocationChanged += NotifyGameAdded;
|
|
|
|
NavigationManager.NavigateTo($"/Games/{Game.Id}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await MessageService.Error("Could not save!");
|
|
}
|
|
}
|
|
|
|
private void NotifyGameAdded(object? sender, LocationChangedEventArgs e)
|
|
{
|
|
NavigationManager.LocationChanged -= NotifyGameAdded;
|
|
|
|
MessageService.Success("Game added!");
|
|
}
|
|
|
|
private async Task BrowseForIcon()
|
|
{
|
|
var modalOptions = new ModalOptions()
|
|
{
|
|
Title = "Choose Icon",
|
|
Maximizable = false,
|
|
DefaultMaximized = true,
|
|
Closable = true,
|
|
OkText = "Select File"
|
|
};
|
|
|
|
var browserOptions = new FilePickerOptions()
|
|
{
|
|
ArchiveId = Game.Archives.FirstOrDefault().Id,
|
|
Select = true,
|
|
Multiple = false
|
|
};
|
|
|
|
var modalRef = await ModalService.CreateModalAsync<FilePickerDialog, FilePickerOptions, IEnumerable<IFileManagerEntry>>(modalOptions, browserOptions);
|
|
|
|
modalRef.OnOk = (results) =>
|
|
{
|
|
Game.Icon = results.FirstOrDefault().Path;
|
|
StateHasChanged();
|
|
return Task.CompletedTask;
|
|
};
|
|
}
|
|
|
|
private async Task OnGameLookupResultSelected(GameLookupResult result)
|
|
{
|
|
Game.Title = result.IGDBMetadata.Name;
|
|
Game.Description = result.IGDBMetadata.Summary;
|
|
Game.ReleasedOn = result.IGDBMetadata.FirstReleaseDate.GetValueOrDefault().UtcDateTime;
|
|
Game.MultiplayerModes = result.MultiplayerModes.ToList();
|
|
Game.Developers = new List<Company>();
|
|
Game.Publishers = new List<Company>();
|
|
Game.Genres = new List<Genre>();
|
|
Game.Tags = new List<Data.Models.Tag>();
|
|
|
|
if (result.IGDBMetadata.GameModes != null && result.IGDBMetadata.GameModes.Values != null)
|
|
Game.Singleplayer = result.IGDBMetadata.GameModes.Values.Any(gm => gm.Name == "Singleplayer");
|
|
|
|
if (result.IGDBMetadata.InvolvedCompanies != null && result.IGDBMetadata.InvolvedCompanies.Values != null)
|
|
{
|
|
// Make sure companie
|
|
var developers = result.IGDBMetadata.InvolvedCompanies.Values.Where(c => c.Developer.GetValueOrDefault()).Select(c => c.Company.Value.Name);
|
|
var publishers = result.IGDBMetadata.InvolvedCompanies.Values.Where(c => c.Publisher.GetValueOrDefault()).Select(c => c.Company.Value.Name);
|
|
|
|
foreach (var developer in developers)
|
|
{
|
|
Game.Developers.Add(await CompanyService.AddMissing(c => c.Name == developer, new Company { Name = developer }));
|
|
}
|
|
|
|
foreach (var publisher in publishers)
|
|
{
|
|
Game.Publishers.Add(await CompanyService.AddMissing(c => c.Name == publisher, new Company { Name = publisher }));
|
|
}
|
|
}
|
|
|
|
if (result.IGDBMetadata.Genres != null && result.IGDBMetadata.Genres.Values != null)
|
|
{
|
|
var genres = result.IGDBMetadata.Genres.Values.Select(g => g.Name);
|
|
|
|
foreach (var genre in genres)
|
|
{
|
|
Game.Genres.Add(await GenreService.AddMissing(g => g.Name == genre, new Genre { Name = genre }));
|
|
}
|
|
}
|
|
|
|
if (result.IGDBMetadata.Keywords != null && result.IGDBMetadata.Keywords.Values != null)
|
|
{
|
|
var tags = result.IGDBMetadata.Keywords.Values.Select(t => t.Name).Take(20);
|
|
|
|
foreach (var tag in tags)
|
|
{
|
|
Game.Tags.Add(await TagService.AddMissing(t => t.Name == tag, new Data.Models.Tag { Name = tag }));
|
|
}
|
|
}
|
|
}
|
|
}
|