fix ChristmaTree: Select Number Action
This commit is contained in:
parent
383db346eb
commit
56f3e63046
|
|
@ -453,7 +453,21 @@ public class ChristmasTreeGameLogicService : IGameLogicService
|
|||
Icon = "TouchApp",
|
||||
Color = "Primary",
|
||||
Tooltip = $"Wähle eine Zahl zum Streichen: {string.Join(", ", availableNumbers)}",
|
||||
Order = 1
|
||||
Order = 1,
|
||||
Parameters =
|
||||
[
|
||||
new ActionParameterDefinition
|
||||
{
|
||||
Key = "number",
|
||||
Label = "Wähle eine Zahl",
|
||||
Type = "select",
|
||||
Options = availableNumbers.Select(n => new ActionParameterOption
|
||||
{
|
||||
Value = n,
|
||||
Label = n.ToString()
|
||||
}).ToList()
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,53 @@ public record GameActionDescriptor
|
|||
/// Display order for sorting (lower = first).
|
||||
/// </summary>
|
||||
public int Order { get; init; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Parameter definitions if action requires user input.
|
||||
/// </summary>
|
||||
public IReadOnlyList<ActionParameterDefinition>? Parameters { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines a parameter that must be collected from the user before executing an action.
|
||||
/// </summary>
|
||||
public record ActionParameterDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// Parameter key (used in the parameters dictionary).
|
||||
/// </summary>
|
||||
public required string Key { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Display label for the parameter.
|
||||
/// </summary>
|
||||
public required string Label { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Parameter type: "select" for dropdown, "number" for numeric input.
|
||||
/// </summary>
|
||||
public string Type { get; init; } = "select";
|
||||
|
||||
/// <summary>
|
||||
/// Available options for "select" type.
|
||||
/// </summary>
|
||||
public IReadOnlyList<ActionParameterOption>? Options { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An option for a select-type parameter.
|
||||
/// </summary>
|
||||
public record ActionParameterOption
|
||||
{
|
||||
/// <summary>
|
||||
/// The value to use when this option is selected.
|
||||
/// </summary>
|
||||
public required object Value { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Display label for the option.
|
||||
/// </summary>
|
||||
public required string Label { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
Color="@GetColor(action.Color)"
|
||||
StartIcon="@GetIcon(action.Icon)"
|
||||
Disabled="@(!action.IsEnabled || GameState.Value.IsSaving || GameState.Value.IsLoading)"
|
||||
OnClick="@(() => ExecuteAction(action.ActionId))"
|
||||
OnClick="@(() => OnActionClick(action))"
|
||||
Title="@action.Tooltip"
|
||||
Class="game-action-button">
|
||||
@action.Label
|
||||
|
|
@ -26,6 +26,40 @@
|
|||
</div>
|
||||
}
|
||||
|
||||
<MudDialog @bind-Visible="_dialogVisible" Options="_dialogOptions">
|
||||
<TitleContent>
|
||||
<MudText Typo="Typo.h6">@_currentAction?.Label</MudText>
|
||||
</TitleContent>
|
||||
<DialogContent>
|
||||
@if (_currentAction?.Parameters != null)
|
||||
{
|
||||
@foreach (var param in _currentAction.Parameters)
|
||||
{
|
||||
@if (param.Type == "select" && param.Options != null)
|
||||
{
|
||||
<div class="parameter-select">
|
||||
<MudText Typo="Typo.subtitle2" Class="mb-2">@param.Label</MudText>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
@foreach (var option in param.Options)
|
||||
{
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
OnClick="@(() => SelectOption(param.Key, option.Value))"
|
||||
Class="parameter-option-button">
|
||||
@option.Label
|
||||
</MudButton>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="CloseDialog">Abbrechen</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
|
||||
<style>
|
||||
.game-action-panel {
|
||||
display: flex;
|
||||
|
|
@ -40,10 +74,21 @@
|
|||
.game-action-button {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.parameter-select {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.parameter-option-button {
|
||||
min-width: 60px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
private IReadOnlyList<GameActionDescriptor> _availableActions = [];
|
||||
private bool _dialogVisible;
|
||||
private GameActionDescriptor? _currentAction;
|
||||
private readonly DialogOptions _dialogOptions = new() { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Small };
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
|
|
@ -81,9 +126,32 @@
|
|||
}
|
||||
}
|
||||
|
||||
private void ExecuteAction(string actionId)
|
||||
private void OnActionClick(GameActionDescriptor action)
|
||||
{
|
||||
Dispatcher.Dispatch(new ExecuteGameActionAction(actionId));
|
||||
if (action.Parameters is { Count: > 0 })
|
||||
{
|
||||
_currentAction = action;
|
||||
_dialogVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.Dispatch(new ExecuteGameActionAction(action.ActionId));
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectOption(string paramKey, object value)
|
||||
{
|
||||
if (_currentAction == null) return;
|
||||
|
||||
var parameters = new Dictionary<string, object> { [paramKey] = value };
|
||||
Dispatcher.Dispatch(new ExecuteGameActionAction(_currentAction.ActionId, parameters));
|
||||
CloseDialog();
|
||||
}
|
||||
|
||||
private void CloseDialog()
|
||||
{
|
||||
_dialogVisible = false;
|
||||
_currentAction = null;
|
||||
}
|
||||
|
||||
private static Color GetColor(string colorName) => colorName switch
|
||||
|
|
|
|||
Loading…
Reference in New Issue