From 587b92409de4a8674f98da070233308507dc4a97 Mon Sep 17 00:00:00 2001 From: beo3000 Date: Sat, 3 Jan 2026 10:28:13 +0100 Subject: [PATCH] added ParticipantsMode.FreeToChoose: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- .../Components/Game/GameInputPanel.razor | 2 +- .../Game/PlayerSelectorDialog.razor | 156 ++++++++++++++++++ .../Components/Pages/Days/DayDetails.razor | 29 +++- 3 files changed, 183 insertions(+), 4 deletions(-) create mode 100644 src/Koogle.Web/Components/Game/PlayerSelectorDialog.razor diff --git a/src/Koogle.Web/Components/Game/GameInputPanel.razor b/src/Koogle.Web/Components/Game/GameInputPanel.razor index 6dffcc3..d16e414 100644 --- a/src/Koogle.Web/Components/Game/GameInputPanel.razor +++ b/src/Koogle.Web/Components/Game/GameInputPanel.razor @@ -23,7 +23,7 @@ @if (GameState.Value.Participants.Mode == ParticipantsMode.FreeToChoose) { diff --git a/src/Koogle.Web/Components/Game/PlayerSelectorDialog.razor b/src/Koogle.Web/Components/Game/PlayerSelectorDialog.razor new file mode 100644 index 0000000..589f9ad --- /dev/null +++ b/src/Koogle.Web/Components/Game/PlayerSelectorDialog.razor @@ -0,0 +1,156 @@ +@using Koogle.Application.Games.DeathBox +@using Koogle.Domain.Enums + + + + + + Spieler auswählen + + + + @if (FilterByGameLogic && HasEliminatedPlayers) + { + + } + + + @foreach (var player in FilteredPlayers) + { + + + + + @player.Name[0] + + + @player.Name + + @if (player.IsCurrentPlayer) + { + + Aktuell + + } + @if (player.IsEliminated) + { + + Ausgeschieden + + } + + + + } + + + + Abbrechen + + + + + +@code { + /// + /// Player IDs in the game (in turn order). + /// + [Parameter] + public Guid[] PlayerIds { get; set; } = []; + + /// + /// Current player ID. + /// + [Parameter] + public Guid? CurrentPlayerId { get; set; } + + /// + /// Function to resolve player names by ID. + /// + [Parameter] + public Func? PlayerNameResolver { get; set; } + + /// + /// Game model for determining eliminated players. + /// + [Parameter] + public object? GameModel { get; set; } + + /// + /// Whether to filter by game logic (hide eliminated players by default). + /// + [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 EliminatedPlayerIds => GetEliminatedPlayerIds(); + + private bool HasEliminatedPlayers => EliminatedPlayerIds.Count > 0; + + private IEnumerable AllPlayers => PlayerIds.Select(id => new PlayerInfo( + id, + PlayerNameResolver?.Invoke(id) ?? "Unbekannt", + id == CurrentPlayerId, + EliminatedPlayerIds.Contains(id) + )); + + private IEnumerable FilteredPlayers => + FilterByGameLogic && !_showEliminatedPlayers + ? AllPlayers.Where(p => !p.IsEliminated) + : AllPlayers; + + private HashSet 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(); + } +} diff --git a/src/Koogle.Web/Components/Pages/Days/DayDetails.razor b/src/Koogle.Web/Components/Pages/Days/DayDetails.razor index 153564d..c9f5136 100644 --- a/src/Koogle.Web/Components/Pages/Days/DayDetails.razor +++ b/src/Koogle.Web/Components/Pages/Days/DayDetails.razor @@ -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)GetPlayerName }, + { "GameModel", GameState.Value.GameModel }, + { "FilterByGameLogic", true } + }; + + var options = new DialogOptions + { + MaxWidth = MaxWidth.Small, + FullWidth = true, + CloseOnEscapeKey = true + }; + + var dialog = await DialogService.ShowAsync("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;