303 lines
12 KiB
Text
303 lines
12 KiB
Text
@page "/Games/{id:guid}/General"
|
|
@page "/Games/{id:guid}"
|
|
@page "/Games/Add"
|
|
@attribute [Authorize(Roles = RoleService.AdministratorRoleName)]
|
|
@inject CollectionService CollectionService
|
|
@inject CompanyService CompanyService
|
|
@inject EngineService EngineService
|
|
@inject GameService GameService
|
|
@inject GenreService GenreService
|
|
@inject IGDBService IgdbService
|
|
@inject PlatformService PlatformService
|
|
@inject RedistributableService RedistributableService
|
|
@inject TagService TagService
|
|
@inject IMessageService MessageService
|
|
@inject ModalService ModalService
|
|
@inject NavigationManager NavigationManager
|
|
@inject ILogger<General> Logger
|
|
|
|
<GameEditView Id="Id">
|
|
<TitleTemplate>
|
|
@if (context.Id == Guid.Empty)
|
|
{
|
|
<Text>Add New Game</Text>
|
|
}
|
|
else
|
|
{
|
|
<Text>General</Text>
|
|
}
|
|
</TitleTemplate>
|
|
<TitleExtraTemplate>
|
|
<Flex Gap="FlexGap.Small" Justify="FlexJustify.End">
|
|
@if (context != null && (context.Scripts?.Any(s => s.Type == ScriptType.Package) ?? false))
|
|
{
|
|
<Button OnClick="Package" Loading="Packaging">Package</Button>
|
|
}
|
|
|
|
@if (context != null && context.Id != Guid.Empty)
|
|
{
|
|
<Button OnClick="OpenExportDialog">Export</Button>
|
|
}
|
|
|
|
<Button Type="ButtonType.Primary" OnClick="() => Save(context)">Save</Button>
|
|
</Flex>
|
|
</TitleExtraTemplate>
|
|
|
|
<ChildContent>
|
|
<Form Model="@context" Layout="@FormLayout.Vertical" Context="formContext">
|
|
<FormItem Label="Title">
|
|
<GameMetadataLookup
|
|
ButtonText="Lookup"
|
|
AutoFocus="context.Id == Guid.Empty"
|
|
@bind-Value="context.Title"
|
|
OnResultSelected="(result) => OnGameLookupResultSelected(result, context)" />
|
|
</FormItem>
|
|
<FormItem Label="Sort Title">
|
|
<Input @bind-Value="@context.SortTitle" />
|
|
</FormItem>
|
|
<FormItem Label="Notes">
|
|
<TextArea @bind-Value="@context.Notes" MaxLength=2000 ShowCount />
|
|
</FormItem>
|
|
<FormItem Label="Description">
|
|
<TextArea @bind-Value="@context.Description" />
|
|
</FormItem>
|
|
<FormItem Label="Engine">
|
|
<Select TItem="Engine"
|
|
TItemValue="Guid?"
|
|
DataSource="@Engines.OrderBy(e => e.Name)"
|
|
@bind-Value="@context.EngineId"
|
|
LabelName="Name"
|
|
ValueName="Id"
|
|
Placeholder="Select an Engine"
|
|
DefaultActiveFirstOption="false"
|
|
EnableSearch />
|
|
</FormItem>
|
|
<FormItem Label="Type">
|
|
<Select @bind-Value="@context.Type" TItem="GameType" TItemValue="GameType" DataSource="Enum.GetValues<GameType>()">
|
|
<LabelTemplate Context="Value">@Value.GetDisplayName()</LabelTemplate>
|
|
<ItemTemplate Context="Value">@Value.GetDisplayName()</ItemTemplate>
|
|
</Select>
|
|
</FormItem>
|
|
@if (context.Type != GameType.MainGame)
|
|
{
|
|
<FormItem Label="Base Game">
|
|
<Flex Gap="FlexGap.Small" Wrap="FlexWrap.NoWrap">
|
|
<Select TItem="Game"
|
|
TItemValue="Guid?"
|
|
DataSource="@Games.Where(g => g.Id != context.Id).OrderBy(g => String.IsNullOrWhiteSpace(g.SortTitle) ? g.Title : g.SortTitle)"
|
|
@bind-Value="@context.BaseGameId"
|
|
LabelName="Title"
|
|
ValueName="Id"
|
|
Placeholder="Select a Game"
|
|
DefaultActiveFirstOption="false"
|
|
EnableSearch>
|
|
<ItemTemplate Context="baseGame">
|
|
<Image Src="@GetIcon(baseGame)" Height="32" Width="32" Preview="false"></Image>
|
|
@baseGame.Title
|
|
</ItemTemplate>
|
|
</Select>
|
|
|
|
@if (context.BaseGameId == null || context.BaseGameId == Guid.Empty)
|
|
{
|
|
<Button Type="ButtonType.Primary" Disabled>Edit</Button>
|
|
}
|
|
else
|
|
{
|
|
<a href="@($"/Games/{context.BaseGameId}")" class="ant-btn ant-btn-primary" target="_blank">Edit</a>
|
|
}
|
|
</Flex>
|
|
</FormItem>
|
|
}
|
|
<FormItem Label="Key Allocation Method">
|
|
<Select @bind-Value="@context.KeyAllocationMethod" TItem="KeyAllocationMethod" TItemValue="KeyAllocationMethod" DataSource="Enum.GetValues<KeyAllocationMethod>()">
|
|
<LabelTemplate Context="Value">@Value.GetDisplayName()</LabelTemplate>
|
|
<ItemTemplate Context="Value">@Value.GetDisplayName()</ItemTemplate>
|
|
</Select>
|
|
</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="context.Developers" OptionLabelSelector="c => c.Name" TItem="Company" />
|
|
</FormItem>
|
|
<FormItem Label="Publishers">
|
|
<TagsInput Entities="Companies" @bind-Values="context.Publishers" OptionLabelSelector="c => c.Name" TItem="Company" />
|
|
</FormItem>
|
|
<FormItem Label="Platforms">
|
|
<TagsInput Entities="Platforms" @bind-Values="context.Platforms" OptionLabelSelector="c => c.Name" TItem="Platform" />
|
|
</FormItem>
|
|
<FormItem Label="Genres">
|
|
<TagsInput Entities="Genres" @bind-Values="context.Genres" OptionLabelSelector="c => c.Name" TItem="Genre" />
|
|
</FormItem>
|
|
<FormItem Label="Tags">
|
|
<TagsInput Entities="Tags" @bind-Values="context.Tags" OptionLabelSelector="c => c.Name" TItem="Data.Models.Tag" />
|
|
</FormItem>
|
|
<FormItem Label="Collections">
|
|
<TagsInput Entities="Collections" @bind-Values="context.Collections" OptionLabelSelector="c => c.Name" TItem="Collection" />
|
|
</FormItem>
|
|
<FormItem Label="Redistributables">
|
|
<TransferInput
|
|
Style="height: 350px"
|
|
Searchable
|
|
LeftTitle="Available"
|
|
RightTitle="Selected"
|
|
DataSource="Redistributables"
|
|
TitleSelector="r => r.Name"
|
|
@bind-Values="context.Redistributables" />
|
|
</FormItem>
|
|
</Form>
|
|
</ChildContent>
|
|
</GameEditView>
|
|
|
|
@code {
|
|
[Parameter] public Guid Id { get; set; }
|
|
|
|
bool Loaded;
|
|
bool Success;
|
|
bool Packaging;
|
|
|
|
IEnumerable<Engine> Engines = new List<Engine>();
|
|
IEnumerable<Company> Companies = new List<Company>();
|
|
IEnumerable<Genre> Genres = new List<Genre>();
|
|
IEnumerable<Platform> Platforms = new List<Platform>();
|
|
IEnumerable<Data.Models.Tag> Tags = new List<Data.Models.Tag>();
|
|
IEnumerable<Collection> Collections = new List<Collection>();
|
|
IEnumerable<Redistributable> Redistributables = new List<Redistributable>();
|
|
IEnumerable<Game> Games = new List<Game>();
|
|
|
|
private GameMetadataLookup? GameMetadataLookup;
|
|
|
|
protected override async Task OnParametersSetAsync()
|
|
{
|
|
if (!Loaded)
|
|
await LoadData();
|
|
}
|
|
|
|
private async Task LoadData()
|
|
{
|
|
var allowedTypes = new[] { GameType.MainGame, GameType.StandaloneExpansion, GameType.StandaloneMod };
|
|
|
|
Engines = await EngineService.SortBy(g => g.Name).GetAsync();
|
|
Companies = await CompanyService.SortBy(g => g.Name).GetAsync();
|
|
Genres = await GenreService.SortBy(g => g.Name).GetAsync();
|
|
Platforms = await PlatformService.SortBy(g => g.Name).GetAsync();
|
|
Tags = await TagService.SortBy(g => g.Name).GetAsync();
|
|
Collections = await CollectionService.SortBy(g => g.Name).GetAsync();
|
|
Games = (await GameService
|
|
.Include(g => g.Media.Where(m => m.Type == MediaType.Icon))
|
|
.GetAsync(g => allowedTypes.Contains(g.Type)))
|
|
.OrderByTitle(g => String.IsNullOrWhiteSpace(g.SortTitle) ? g.Title : g.SortTitle);
|
|
Redistributables = (await RedistributableService.GetAsync()).OrderByTitle(r => r.Name);
|
|
|
|
Loaded = true;
|
|
}
|
|
|
|
private async Task Save(Game game)
|
|
{
|
|
try
|
|
{
|
|
if (game.Id != Guid.Empty)
|
|
{
|
|
game.BaseGame = null; // clearing base game, model setup will write the BaseGameId value, referenced model will be loaded on update/get
|
|
game = await GameService.UpdateAsync(game);
|
|
|
|
await MessageService.SuccessAsync("Game updated!");
|
|
}
|
|
else
|
|
{
|
|
game = await GameService.AddAsync(game);
|
|
|
|
NavigationManager.LocationChanged += NotifyGameAdded;
|
|
|
|
NavigationManager.NavigateTo($"/Games/{game.Id}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageService.Error("Could not save game!");
|
|
Logger.LogError(ex, "Could not save game!");
|
|
}
|
|
}
|
|
|
|
private void NotifyGameAdded(object? sender, LocationChangedEventArgs e)
|
|
{
|
|
NavigationManager.LocationChanged -= NotifyGameAdded;
|
|
|
|
MessageService.Success("Game added!");
|
|
}
|
|
|
|
private async Task OnGameLookupResultSelected(GameLookupResult result, Game game)
|
|
{
|
|
try
|
|
{
|
|
game = await IgdbService.ImportGameAsync(result, game);
|
|
|
|
NavigationManager.NavigateTo($"/Games/{game.Id}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageService.Error("Could not import info from IGDB!");
|
|
Logger.LogError(ex, "Could not import info from IGDB!");
|
|
}
|
|
}
|
|
|
|
private string GetIcon(Game game)
|
|
{
|
|
var media = game?.Media?.FirstOrDefault(m => m.Type == SDK.Enums.MediaType.Icon);
|
|
|
|
if (media != null)
|
|
return $"/api/Media/{media.Id}/Download?fileId={media.FileId}";
|
|
else
|
|
return "/favicon.ico";
|
|
}
|
|
|
|
private async Task Delete(Game game)
|
|
{
|
|
Games = new List<Game>();
|
|
|
|
try
|
|
{
|
|
await GameService.DeleteAsync(game);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageService.Error($"Could not delete the {game.Type.GetDisplayName().ToLower()}!");
|
|
Logger.LogError(ex, $"Could not delete the {game.Type.GetDisplayName().ToLower()}!");
|
|
}
|
|
}
|
|
|
|
private async Task OpenExportDialog()
|
|
{
|
|
var game = await GameService.GetAsync(Id);
|
|
|
|
var modalOptions = new ModalOptions()
|
|
{
|
|
Title = $"Export {game.Title}",
|
|
Maximizable = false,
|
|
DefaultMaximized = false,
|
|
Closable = true,
|
|
OkText = "Add",
|
|
Footer = null,
|
|
};
|
|
|
|
var options = new ExportDialogOptions()
|
|
{
|
|
RecordId = Id,
|
|
RecordType = ImportExportRecordType.Game
|
|
};
|
|
|
|
var modalRef = await ModalService.CreateModalAsync<ExportDialog, ExportDialogOptions>(modalOptions, options);
|
|
}
|
|
|
|
private async Task Package()
|
|
{
|
|
Packaging = true;
|
|
|
|
await GameService.PackageAsync(Id);
|
|
|
|
Packaging = false;
|
|
}
|
|
}
|