added ParticipantsMode.FreeToChoose:

Neue Datei erstellt:
  - src/Koogle.Web/Components/Game/PlayerSelectorDialog.razor - Dialog zur manuellen Spielerauswahl

  Geändert:
  - src/Koogle.Web/Components/Pages/Days/DayDetails.razor:863-891 - ShowPlayerSelector implementiert

  Funktionsweise:
  1. Bei ParticipantsMode.FreeToChoose zeigt GameInputPanel.razor:23-32 den Button "Spieler wechseln"
  2. Der neue Dialog listet alle Spieler aus Participants.PlayerIds
  3. Bei DeathBox werden ausgeschiedene Spieler standardmäßig ausgeblendet (Toggle verfügbar)
  4. Bei Spielerauswahl wird SetCurrentPlayerAction dispatcht

  Features:
  - Aktueller Spieler ist markiert (grün)
  - Ausgeschiedene Spieler sind durchgestrichen mit "Ausgeschieden"-Badge
  - Optional können ausgeschiedene Spieler eingeblendet werden (falls nötig)
  - Funktioniert mit allen Game-Typen (DeathBox, Shit, Training)
This commit is contained in:
beo3000 2026-01-03 10:28:13 +01:00
parent 39d4629e72
commit 587b92409d
3 changed files with 183 additions and 4 deletions

View File

@ -23,7 +23,7 @@
@if (GameState.Value.Participants.Mode == ParticipantsMode.FreeToChoose)
{
<MudButton Variant="Variant.Outlined"
Color="Color.Primary"
Color="Color.Warning"
Size="Size.Small"
OnClick="ShowPlayerSelector"
StartIcon="@Icons.Material.Filled.SwapHoriz">

View File

@ -0,0 +1,156 @@
@using Koogle.Application.Games.DeathBox
@using Koogle.Domain.Enums
<MudDialog>
<TitleContent>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudIcon Icon="@Icons.Material.Filled.Person" />
<MudText Typo="Typo.h6">Spieler auswählen</MudText>
</MudStack>
</TitleContent>
<DialogContent>
@if (FilterByGameLogic && HasEliminatedPlayers)
{
<MudSwitch @bind-Value="_showEliminatedPlayers"
Color="Color.Secondary"
Label="Ausgeschiedene anzeigen"
Class="mb-3" />
}
<MudList T="PlayerInfo" Dense="false" Class="player-selector-list">
@foreach (var player in FilteredPlayers)
{
<MudListItem T="PlayerInfo"
Class="@GetPlayerClass(player)"
OnClick="@(() => SelectPlayer(player))"
Disabled="@(player.IsEliminated && !_showEliminatedPlayers)">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Style="width: 100%">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudAvatar Size="Size.Medium"
Color="@(player.IsCurrentPlayer ? Color.Success : (player.IsEliminated ? Color.Default : Color.Primary))">
@player.Name[0]
</MudAvatar>
<MudText Style="@(player.IsEliminated ? "text-decoration: line-through; opacity: 0.6" : "")">
@player.Name
</MudText>
@if (player.IsCurrentPlayer)
{
<MudChip T="string" Size="Size.Small" Color="Color.Success" Variant="Variant.Outlined">
Aktuell
</MudChip>
}
@if (player.IsEliminated)
{
<MudChip T="string" Size="Size.Small" Color="Color.Error" Variant="Variant.Outlined">
Ausgeschieden
</MudChip>
}
</MudStack>
</MudStack>
</MudListItem>
}
</MudList>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel" Color="Color.Default">Abbrechen</MudButton>
</DialogActions>
</MudDialog>
<style>
.player-selector-list .mud-list-item {
border-radius: 8px;
margin-bottom: 4px;
cursor: pointer;
}
.player-selector-list .mud-list-item:hover:not(.mud-list-item-disabled) {
background-color: var(--mud-palette-action-default-hover);
}
.player-selector-list .current-player {
border: 2px solid var(--mud-palette-success);
background-color: var(--mud-palette-success-lighten);
}
</style>
@code {
/// <summary>
/// Player IDs in the game (in turn order).
/// </summary>
[Parameter]
public Guid[] PlayerIds { get; set; } = [];
/// <summary>
/// Current player ID.
/// </summary>
[Parameter]
public Guid? CurrentPlayerId { get; set; }
/// <summary>
/// Function to resolve player names by ID.
/// </summary>
[Parameter]
public Func<Guid, string>? PlayerNameResolver { get; set; }
/// <summary>
/// Game model for determining eliminated players.
/// </summary>
[Parameter]
public object? GameModel { get; set; }
/// <summary>
/// Whether to filter by game logic (hide eliminated players by default).
/// </summary>
[Parameter]
public bool FilterByGameLogic { get; set; } = true;
[CascadingParameter]
private IMudDialogInstance MudDialog { get; set; } = null!;
private bool _showEliminatedPlayers;
private record PlayerInfo(Guid Id, string Name, bool IsCurrentPlayer, bool IsEliminated);
private HashSet<Guid> EliminatedPlayerIds => GetEliminatedPlayerIds();
private bool HasEliminatedPlayers => EliminatedPlayerIds.Count > 0;
private IEnumerable<PlayerInfo> AllPlayers => PlayerIds.Select(id => new PlayerInfo(
id,
PlayerNameResolver?.Invoke(id) ?? "Unbekannt",
id == CurrentPlayerId,
EliminatedPlayerIds.Contains(id)
));
private IEnumerable<PlayerInfo> FilteredPlayers =>
FilterByGameLogic && !_showEliminatedPlayers
? AllPlayers.Where(p => !p.IsEliminated)
: AllPlayers;
private HashSet<Guid> GetEliminatedPlayerIds()
{
return GameModel switch
{
DeathBoxGameModel deathBox => deathBox.EliminatedPlayers.ToHashSet(),
_ => []
};
}
private string GetPlayerClass(PlayerInfo player)
{
return player.IsCurrentPlayer ? "current-player" : "";
}
private void SelectPlayer(PlayerInfo player)
{
if (player.IsEliminated && !_showEliminatedPlayers)
return;
MudDialog.Close(DialogResult.Ok(player.Id));
}
private void Cancel()
{
MudDialog.Cancel();
}
}

View File

@ -862,9 +862,32 @@ else
private async Task ShowPlayerSelector()
{
// TODO: Implement player selector dialog
await Task.CompletedTask;
Snackbar.Add("Spieler-Auswahl noch nicht implementiert", Severity.Info);
if (!GameState.Value.IsGameActive) return;
var parameters = new DialogParameters
{
{ "PlayerIds", GameState.Value.Participants.PlayerIds },
{ "CurrentPlayerId", GameState.Value.Participants.CurrentPlayerId },
{ "PlayerNameResolver", (Func<Guid, string>)GetPlayerName },
{ "GameModel", GameState.Value.GameModel },
{ "FilterByGameLogic", true }
};
var options = new DialogOptions
{
MaxWidth = MaxWidth.Small,
FullWidth = true,
CloseOnEscapeKey = true
};
var dialog = await DialogService.ShowAsync<PlayerSelectorDialog>("Spieler auswählen", parameters, options);
var result = await dialog.Result;
if (result != null && !result.Canceled && result.Data is Guid selectedPlayerId)
{
Dispatcher.Dispatch(new SetCurrentPlayerAction(selectedPlayerId));
Snackbar.Add($"Spieler gewechselt zu {GetPlayerName(selectedPlayerId)}", Severity.Success);
}
}
private const int TimerDurationSeconds = 3;