213 lines
6.4 KiB
C#
213 lines
6.4 KiB
C#
using System.Collections.ObjectModel;
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using CommunityToolkit.Mvvm.Messaging;
|
|
using SlipItIn.Messages;
|
|
using SlipItIn.Services.Interfaces;
|
|
using SlipItIn.Shared.DTOs;
|
|
|
|
namespace SlipItIn.ViewModels;
|
|
|
|
public partial class LobbyViewModel : BaseViewModel,
|
|
IRecipient<GameStateChangedMessage>,
|
|
IRecipient<LobbyCreatedMessage>,
|
|
IRecipient<GameStartedMessage>,
|
|
IRecipient<ErrorOccurredMessage>,
|
|
IRecipient<ConnectionStateChangedMessage>,
|
|
IRecipient<SyncStateChangedMessage>
|
|
{
|
|
private readonly ISignalRService _signalR;
|
|
private readonly IGameStateService _gameStateService;
|
|
private readonly IAuthSessionService _authSession;
|
|
private readonly IApiService _apiService;
|
|
|
|
[ObservableProperty]
|
|
public partial string LobbyCode { get; set; } = string.Empty;
|
|
|
|
[ObservableProperty]
|
|
public partial int GameId { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial bool IsHost { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial bool IsConnected { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial bool IsSyncing { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial string SyncStatusText { get; set; } = "Bereit";
|
|
|
|
[ObservableProperty]
|
|
public partial int PendingSyncActions { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial bool IsCurrentPlayerReady { get; set; }
|
|
|
|
[ObservableProperty]
|
|
public partial bool CanStartGame { get; set; }
|
|
|
|
public ObservableCollection<PlayerInfoDto> Players { get; } = [];
|
|
|
|
public LobbyViewModel(ISignalRService signalR, IGameStateService gameStateService, IAuthSessionService authSession, IApiService apiService)
|
|
{
|
|
_signalR = signalR;
|
|
_gameStateService = gameStateService;
|
|
_authSession = authSession;
|
|
_apiService = apiService;
|
|
|
|
IsConnected = _signalR.IsConnected;
|
|
IsActive = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reaktiviert das ViewModel nach einem Logout (Singleton-Lebensdauer).
|
|
/// Wird von LobbyPage.OnNavigatedTo aufgerufen.
|
|
/// </summary>
|
|
public void Activate()
|
|
{
|
|
IsConnected = _signalR.IsConnected;
|
|
IsActive = true;
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task CreateLobbyAsync()
|
|
{
|
|
await RunSafeAsync(async () =>
|
|
{
|
|
IsHost = true;
|
|
await _signalR.CreateLobbyAsync();
|
|
}, "Lobby wird erstellt...");
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task JoinLobbyAsync()
|
|
{
|
|
await RunSafeAsync(async () =>
|
|
{
|
|
IsHost = false;
|
|
await _signalR.JoinLobbyAsync(LobbyCode);
|
|
}, "Lobby wird beigetreten...");
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task SetReadyAsync()
|
|
{
|
|
await RunSafeAsync(async () =>
|
|
{
|
|
var currentPlayerId = GetCurrentPlayerId();
|
|
if (currentPlayerId <= 0 || GameId <= 0)
|
|
throw new InvalidOperationException("Spielstatus ist noch nicht verfügbar.");
|
|
|
|
await _signalR.PlayerReadyAsync(GameId, currentPlayerId);
|
|
});
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task StartGameAsync()
|
|
{
|
|
await RunSafeAsync(async () =>
|
|
{
|
|
if (GameId <= 0)
|
|
throw new InvalidOperationException("Keine aktive Lobby gefunden.");
|
|
|
|
if (!CanStartGame)
|
|
throw new InvalidOperationException("Alle Spieler müssen bereit sein, bevor das Spiel gestartet werden kann.");
|
|
|
|
await _signalR.StartGameAsync(GameId);
|
|
});
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async Task LogoutAsync()
|
|
{
|
|
await RunSafeAsync(async () =>
|
|
{
|
|
IsActive = false;
|
|
await _signalR.DisconnectAsync();
|
|
await _apiService.LogoutAsync();
|
|
await _gameStateService.ClearLocalGameDataAsync();
|
|
await Shell.Current.GoToAsync("//LoginPage");
|
|
});
|
|
}
|
|
|
|
public void Receive(GameStateChangedMessage message)
|
|
{
|
|
MainThread.BeginInvokeOnMainThread(() =>
|
|
{
|
|
GameId = message.Value.GameId;
|
|
LobbyCode = message.Value.LobbyCode;
|
|
|
|
Players.Clear();
|
|
foreach (var player in message.Value.Players)
|
|
Players.Add(player);
|
|
|
|
var currentUsername = _authSession.CurrentUser?.Username;
|
|
var currentUserId = _authSession.CurrentUser?.UserId ?? 0;
|
|
|
|
IsCurrentPlayerReady = message.Value.Players.Any(p =>
|
|
p.IsReady && string.Equals(p.Username, currentUsername, StringComparison.OrdinalIgnoreCase));
|
|
|
|
// Determine whether the current user is the host based on server-provided HostUserId
|
|
IsHost = currentUserId > 0 && message.Value.HostUserId > 0 && currentUserId == message.Value.HostUserId;
|
|
|
|
CanStartGame = message.Value.Players.Count >= 2 && message.Value.Players.All(p => p.IsReady);
|
|
});
|
|
}
|
|
|
|
public void Receive(LobbyCreatedMessage message)
|
|
{
|
|
MainThread.BeginInvokeOnMainThread(() =>
|
|
{
|
|
GameId = message.Value.GameId;
|
|
LobbyCode = message.Value.LobbyCode;
|
|
});
|
|
}
|
|
|
|
public void Receive(GameStartedMessage message)
|
|
{
|
|
MainThread.BeginInvokeOnMainThread(() =>
|
|
{
|
|
try
|
|
{
|
|
Shell.Current.GoToAsync(nameof(Views.GameBoardPage));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
StatusMessage = $"Navigation fehlgeschlagen: {ex.Message}";
|
|
}
|
|
});
|
|
}
|
|
|
|
public void Receive(ErrorOccurredMessage message)
|
|
{
|
|
MainThread.BeginInvokeOnMainThread(() => StatusMessage = message.Value);
|
|
}
|
|
|
|
public void Receive(ConnectionStateChangedMessage message)
|
|
{
|
|
MainThread.BeginInvokeOnMainThread(() => IsConnected = message.Value);
|
|
}
|
|
|
|
public void Receive(SyncStateChangedMessage message)
|
|
{
|
|
MainThread.BeginInvokeOnMainThread(() =>
|
|
{
|
|
IsSyncing = message.Value.IsSyncing;
|
|
SyncStatusText = message.Value.StatusText;
|
|
PendingSyncActions = message.Value.PendingActions;
|
|
});
|
|
}
|
|
|
|
private int GetCurrentPlayerId()
|
|
{
|
|
var username = _authSession.CurrentUser?.Username;
|
|
if (string.IsNullOrWhiteSpace(username))
|
|
return 0;
|
|
|
|
return _gameStateService.CurrentGameState?.Players
|
|
.FirstOrDefault(p => string.Equals(p.Username, username, StringComparison.OrdinalIgnoreCase))?.PlayerId ?? 0;
|
|
}
|
|
}
|