diff --git a/KoogleApp/Components/Controls/BoardPanel.razor b/KoogleApp/Components/Controls/BoardPanel.razor
index 380d804..d049e0b 100644
--- a/KoogleApp/Components/Controls/BoardPanel.razor
+++ b/KoogleApp/Components/Controls/BoardPanel.razor
@@ -1,8 +1,15 @@
@using KoogleApp.Model
+@using KoogleApp.Store.Game.ThrowTimer
+
+@inherits FluxorComponent
+
+
+
+
Tafel
diff --git a/KoogleApp/Components/Controls/DrawerPanel.razor b/KoogleApp/Components/Controls/DrawerPanel.razor
index 04b4148..6a81485 100644
--- a/KoogleApp/Components/Controls/DrawerPanel.razor
+++ b/KoogleApp/Components/Controls/DrawerPanel.razor
@@ -2,7 +2,7 @@
Spieler
-
+
@code {
diff --git a/KoogleApp/Components/Controls/PlayersPanel.razor b/KoogleApp/Components/Controls/PlayersPanel.razor
index 9e12f46..7ae0d05 100644
--- a/KoogleApp/Components/Controls/PlayersPanel.razor
+++ b/KoogleApp/Components/Controls/PlayersPanel.razor
@@ -21,14 +21,18 @@
@inject IDialogService DialogService
@* @inject SharedDataService _dataService *@
-
-
-
-
-
+
+@if (ShowMenu)
+{
+
+
+
+
+
+}
@if (PlayersState.Value != null)
{
@@ -50,6 +54,8 @@
@code {
+ [Parameter] public bool ShowMenu { get; set; } = false;
+
private PlayerState _selectedValue;
public PlayerState? SelectedValue
diff --git a/KoogleApp/Components/Controls/ThrowPanel.razor b/KoogleApp/Components/Controls/ThrowPanel.razor
index 73a9677..b281801 100644
--- a/KoogleApp/Components/Controls/ThrowPanel.razor
+++ b/KoogleApp/Components/Controls/ThrowPanel.razor
@@ -1,6 +1,7 @@
@using KoogleApp.Model
@using KoogleApp.Store.Game
@using KoogleApp.Store.Game.ThrowPanel
+@using KoogleApp.Store.Game.ThrowTimer
@using KoogleApp.Store.Game.UndoRedo
@using Microsoft.AspNetCore.Mvc.TagHelpers
@@ -129,6 +130,7 @@
{
_correcting = false;
Dispatcher.Dispatch(new ThrowAction(LeftSink: leftSink, RightSink: rightSink));
+
}
private async Task UnlockClick(MouseEventArgs obj)
diff --git a/KoogleApp/Components/Controls/ThrowPanelMenu.razor b/KoogleApp/Components/Controls/ThrowPanelMenu.razor
index ba6d43a..d407746 100644
--- a/KoogleApp/Components/Controls/ThrowPanelMenu.razor
+++ b/KoogleApp/Components/Controls/ThrowPanelMenu.razor
@@ -56,7 +56,6 @@
};
-
var dialog = await DialogService.ShowAsync("Spiel starten", parameters, options);
var result = await dialog.Result;
var startParams = result.Data as StartParams;
@@ -69,7 +68,7 @@
else
{
var result = await DialogService.ShowMessageBox("Spiel beenden?", "Spiel wirklich abbrechen?", "JA", "NEIN", cancelText: "Abbrechen");
- if (result.Value)
+ if (result.HasValue && result.Value)
{
var action = new StartStopAction(ThrowPanelState.Value, null);
Dispatcher.Dispatch(action);
diff --git a/KoogleApp/Components/Controls/ThrowTimer.razor b/KoogleApp/Components/Controls/ThrowTimer.razor
new file mode 100644
index 0000000..cc183b6
--- /dev/null
+++ b/KoogleApp/Components/Controls/ThrowTimer.razor
@@ -0,0 +1,21 @@
+@using KoogleApp.Store.Game.ThrowTimer
+
+@inherits FluxorComponent
+
+@inject IState TimerState
+@inject IDispatcher Dispatcher
+
+@if (TimerState.Value.IsRunning)
+{
+
+ @TimerState.Value.RemainingSeconds
+}
+
+@code {
+
+ private void AbortTimer(MouseEventArgs obj)
+ {
+ Dispatcher.Dispatch(new StopTimerAction());
+ }
+
+}
diff --git a/KoogleApp/Components/Dialogs/StartGameDialog.razor b/KoogleApp/Components/Dialogs/StartGameDialog.razor
index 1923f28..0dba39e 100644
--- a/KoogleApp/Components/Dialogs/StartGameDialog.razor
+++ b/KoogleApp/Components/Dialogs/StartGameDialog.razor
@@ -1,11 +1,13 @@
@using KoogleApp.Games
@using KoogleApp.Model
@using KoogleApp.Services
+@using KoogleApp.Store.DayFeature
@using KoogleApp.Store.Game.Setup
@using KoogleApp.Store.Game.ThrowPanel
@inject GameTypeService GameTypeService
@inject IState SetupState
+@inject IState DayState
@@ -74,7 +76,7 @@
// if (!string.IsNullOrEmpty(Description))
{
// Snackbar.Add("Favorite added", Severity.Success);
- MudDialog.Close(DialogResult.Ok(new StartParams(SetupState.Value.ThrowMode, SetupState.Value.ThrowsPerRound)));
+ MudDialog.Close(DialogResult.Ok(new StartParams(DayState.Value.Id, SetupState.Value.ThrowMode, SetupState.Value.ThrowsPerRound)));
}
}
}
diff --git a/KoogleApp/Components/Pages/Game.razor b/KoogleApp/Components/Pages/Game.razor
index 2d005d5..3fdfcfc 100644
--- a/KoogleApp/Components/Pages/Game.razor
+++ b/KoogleApp/Components/Pages/Game.razor
@@ -11,6 +11,7 @@
@using KoogleApp.Store.DayFeature
@using KoogleApp.Store.Game
@using KoogleApp.Store.Game.ThrowPanel
+@using KoogleApp.Store.Game.ThrowTimer
@using KoogleApp.Store.Game.UndoRedo
@inherits FluxorComponent
@@ -25,6 +26,7 @@
@inject IMyEventAggregator EventAggregator
@inject IState ThrowPanelState
@inject IState DayState
+
@inject IDispatcher Dispatcher
@inject IDialogService DialogService
@@ -48,7 +50,7 @@
break;
case GameView.Board:
-
+
break;
case GameView.Players:
@@ -79,7 +81,7 @@
break;
case GameView.Players:
-
+
break;
case GameView.Player:
@@ -227,6 +229,11 @@
public async Task HandleAsync(GameViewChangedMessage message)
{
+ if (message is { GameView: GameView.Throw, AutoReturnFromTimer: false })
+ {
+ Dispatcher.Dispatch(new StopTimerAction());
+ }
+
_gameView = message.GameView;
await InvokeAsync(StateHasChanged);
}
diff --git a/KoogleApp/Model/EventMessages/GameViewChangedMessage.cs b/KoogleApp/Model/EventMessages/GameViewChangedMessage.cs
index c7b0ad7..5911f22 100644
--- a/KoogleApp/Model/EventMessages/GameViewChangedMessage.cs
+++ b/KoogleApp/Model/EventMessages/GameViewChangedMessage.cs
@@ -10,8 +10,10 @@ namespace KoogleApp.Model.EventMessages
Player
}
- public class GameViewChangedMessage(GameView gameView) : ScopedEventBase
+ public class GameViewChangedMessage(GameView gameView, bool autoReturnFromTimer=false) : ScopedEventBase
{
public GameView GameView { get; private set; } = gameView;
+
+ public bool AutoReturnFromTimer { get; private set; } = autoReturnFromTimer;
}
}
diff --git a/KoogleApp/Model/StartParams.cs b/KoogleApp/Model/StartParams.cs
index 5de2d33..1ccfa3f 100644
--- a/KoogleApp/Model/StartParams.cs
+++ b/KoogleApp/Model/StartParams.cs
@@ -2,9 +2,9 @@
namespace KoogleApp.Model
{
- public record StartParams(ThrowMode ThrowMode, int ThrowsPerRound)
+ public record StartParams(int DayId, ThrowMode ThrowMode, int ThrowsPerRound)
{
- public StartParams() : this(ThrowMode: ThrowMode.Reposition, ThrowsPerRound:3)
+ public StartParams() : this(DayId:0, ThrowMode: ThrowMode.Reposition, ThrowsPerRound:3)
{}
}
}
diff --git a/KoogleApp/Store/Game/ThrowPanel/Effects.cs b/KoogleApp/Store/Game/ThrowPanel/Effects.cs
index 250831c..d7d71b6 100644
--- a/KoogleApp/Store/Game/ThrowPanel/Effects.cs
+++ b/KoogleApp/Store/Game/ThrowPanel/Effects.cs
@@ -1,7 +1,10 @@
using Fluxor;
using KoogleApp.Hub;
using KoogleApp.Model;
+using KoogleApp.Model.EventMessages;
+using KoogleApp.Model.Framework;
using KoogleApp.Services;
+using KoogleApp.Store.Game.ThrowTimer;
using KoogleApp.Store.Game.UndoRedo;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Win32.SafeHandles;
@@ -20,8 +23,10 @@ namespace KoogleApp.Store.Game.ThrowPanel
private readonly AuthenticationStateProvider _authenticationStateProvider;
private readonly IGameStatusDataService _dataService;
private readonly Lock _lock = new Lock();
+ private readonly IMyEventAggregator _eventAggregator;
public ThrowPanelEffects(
+ IMyEventAggregator eventAggregator,
ILogger logger,
HubConnectionService sharedHubService,
IState state,
@@ -35,6 +40,7 @@ namespace KoogleApp.Store.Game.ThrowPanel
_sessionStorage = sessionStorage;
_dataService = dataService;
_authenticationStateProvider = authenticationStateProvider;
+ _eventAggregator = eventAggregator;
}
public void Dispose()
@@ -101,6 +107,9 @@ namespace KoogleApp.Store.Game.ThrowPanel
[EffectMethod]
public async Task HandleThrowAction(ThrowAction throwAction, IDispatcher dispatcher)
{
+ await ShowBoardForSeconds(dispatcher);
+
+
// change ThrowStatus and save - here we need to save the old state, before it is changed by ThrowUpdateAction, so that undo/redo works correctly
dispatcher.Dispatch(new EnsureBeforeThrowStatusAction());
@@ -111,6 +120,12 @@ namespace KoogleApp.Store.Game.ThrowPanel
dispatcher.Dispatch(new TriggerNewThrowPanelStateChangedAction(true)); // this will trigger ThrowPanelStateChangedAction with the new state (not current _state.Value)
}
+ private async Task ShowBoardForSeconds(IDispatcher dispatcher)
+ {
+ dispatcher.Dispatch(new StartTimerAction(5));
+ await _eventAggregator.PublishAsync(new GameViewChangedMessage(GameView.Board) { Scope = EventScope.Circuit });
+ }
+
[EffectMethod]
public Task HandleTriggerNewThrowPanelStateChangedAction(TriggerNewThrowPanelStateChangedAction action,
IDispatcher dispatcher)
diff --git a/KoogleApp/Store/Game/ThrowPanel/Reducers.cs b/KoogleApp/Store/Game/ThrowPanel/Reducers.cs
index 8fe662d..03d8aaf 100644
--- a/KoogleApp/Store/Game/ThrowPanel/Reducers.cs
+++ b/KoogleApp/Store/Game/ThrowPanel/Reducers.cs
@@ -93,7 +93,8 @@ namespace KoogleApp.Store.Game.ThrowPanel
IsStated = !state.IsStated,
ThrowMode = startStopAction.StartParams.ThrowMode,
ThrowsPerRound = startStopAction.StartParams.ThrowsPerRound,
- ThrowPanelStateStatus = ThrowPanelStateStatus.GameStart
+ ThrowPanelStateStatus = ThrowPanelStateStatus.GameStart,
+ DayId = startStopAction.StartParams.DayId
};
return state;
diff --git a/KoogleApp/Store/Game/ThrowPanel/State.cs b/KoogleApp/Store/Game/ThrowPanel/State.cs
index f6aa3e5..3672622 100644
--- a/KoogleApp/Store/Game/ThrowPanel/State.cs
+++ b/KoogleApp/Store/Game/ThrowPanel/State.cs
@@ -32,12 +32,14 @@ namespace KoogleApp.Store.Game.ThrowPanel
[FeatureState]
public record ThrowPanelState(bool IsStated, bool BellValue,
PinStatus Pin1State, PinStatus Pin2State, PinStatus Pin3State, PinStatus Pin4State, PinStatus Pin5State, PinStatus Pin6State, PinStatus Pin7State, PinStatus Pin8State, PinStatus Pin9State,
- int ThrowsPerRound, int ThrowCounterPerRound, ThrowMode ThrowMode, ThrowPanelStateStatus ThrowPanelStateStatus, int ThrowCounter)
+ int ThrowsPerRound, int ThrowCounterPerRound, ThrowMode ThrowMode, ThrowPanelStateStatus ThrowPanelStateStatus, int ThrowCounter,
+ int DayId)
{
// Required for creating initial state
public ThrowPanelState() : this(BellValue:false, IsStated:false,
Pin1State : PinStatus.Standing, Pin2State: PinStatus.Standing, Pin3State: PinStatus.Standing, Pin4State: PinStatus.Standing, Pin5State: PinStatus.Standing, Pin6State: PinStatus.Standing, Pin7State: PinStatus.Standing, Pin8State: PinStatus.Standing, Pin9State: PinStatus.Standing,
- ThrowsPerRound : 3, ThrowCounterPerRound : 1, ThrowMode : ThrowMode.Reposition, ThrowPanelStateStatus: ThrowPanelStateStatus.Undefined, ThrowCounter:0
+ ThrowsPerRound : 3, ThrowCounterPerRound : 1, ThrowMode : ThrowMode.Reposition, ThrowPanelStateStatus: ThrowPanelStateStatus.Undefined, ThrowCounter:0,
+ DayId:0
)
{ }
}
diff --git a/KoogleApp/Store/Game/ThrowTimer/Actions.cs b/KoogleApp/Store/Game/ThrowTimer/Actions.cs
new file mode 100644
index 0000000..dc4ca37
--- /dev/null
+++ b/KoogleApp/Store/Game/ThrowTimer/Actions.cs
@@ -0,0 +1,13 @@
+namespace KoogleApp.Store.Game.ThrowTimer
+{
+ public class StartTimerAction(int seconds)
+ {
+ public int Seconds { get; } = seconds;
+ }
+
+ public class TimerCompletedAction { }
+
+ public class StopTimerAction { }
+
+ public class TickAction { }
+}
diff --git a/KoogleApp/Store/Game/ThrowTimer/Effects.cs b/KoogleApp/Store/Game/ThrowTimer/Effects.cs
new file mode 100644
index 0000000..22f2316
--- /dev/null
+++ b/KoogleApp/Store/Game/ThrowTimer/Effects.cs
@@ -0,0 +1,70 @@
+using Fluxor;
+using KoogleApp.Model.EventMessages;
+using KoogleApp.Model.Framework;
+using KoogleApp.Services;
+
+namespace KoogleApp.Store.Game.ThrowTimer
+{
+ public class TimerEffects
+ {
+ private readonly ILogger _logger;
+ private readonly IMyEventAggregator _eventAggregator;
+ private CancellationTokenSource? _timerCancellation;
+
+ public TimerEffects(ILogger logger, IMyEventAggregator eventAggregator)
+ {
+ _logger = logger;
+ _eventAggregator = eventAggregator;
+ }
+
+ [EffectMethod]
+ public async Task HandleStartTimer(StartTimerAction action, IDispatcher dispatcher)
+ {
+ _logger.LogInformation("Timer gestartet für {Seconds} Sekunden", action.Seconds);
+
+ // Vorherigen Timer stoppen falls vorhanden
+ _timerCancellation?.Cancel();
+ _timerCancellation = new CancellationTokenSource();
+
+ try
+ {
+ for (int i = 0; i < action.Seconds; i++)
+ {
+ await Task.Delay(1000, _timerCancellation.Token);
+ dispatcher.Dispatch(new TickAction());
+ }
+
+ // Timer abgelaufen
+ dispatcher.Dispatch(new TimerCompletedAction());
+ _logger.LogInformation("Timer abgelaufen");
+ }
+ catch (TaskCanceledException)
+ {
+ _logger.LogInformation("Timer wurde abgebrochen");
+ }
+ }
+
+ [EffectMethod]
+ public async Task HandleStopTimer(StopTimerAction action, IDispatcher dispatcher)
+ {
+ _logger.LogInformation("Timer wird gestoppt");
+ _timerCancellation?.Cancel();
+ _timerCancellation = null;
+
+ await ReturnToThrowView();
+ }
+
+ private async Task ReturnToThrowView()
+ {
+ await _eventAggregator.PublishAsync(new GameViewChangedMessage(GameView.Throw, true) { Scope = EventScope.Circuit });
+ }
+
+ [EffectMethod]
+ public async Task HandleTimerCompleted(TimerCompletedAction action, IDispatcher dispatcher)
+ {
+ _logger.LogInformation("Timer-Completed Action wurde verarbeitet");
+
+ await ReturnToThrowView();
+ }
+ }
+}
diff --git a/KoogleApp/Store/Game/ThrowTimer/Reducers.cs b/KoogleApp/Store/Game/ThrowTimer/Reducers.cs
new file mode 100644
index 0000000..679b36f
--- /dev/null
+++ b/KoogleApp/Store/Game/ThrowTimer/Reducers.cs
@@ -0,0 +1,50 @@
+using Fluxor;
+
+namespace KoogleApp.Store.Game.ThrowTimer
+{
+ public static class Reducers
+ {
+ [ReducerMethod]
+ public static TimerState OnStartTimer(TimerState state, StartTimerAction action)
+ {
+ return state with
+ {
+ RemainingSeconds = action.Seconds,
+ IsRunning = true
+ };
+ }
+
+ [ReducerMethod]
+ public static TimerState OnTick(TimerState state, TickAction action)
+ {
+ if (!state.IsRunning || state.RemainingSeconds <= 0)
+ return state;
+
+ return state with
+ {
+ RemainingSeconds = state.RemainingSeconds - 1,
+ IsRunning = state.RemainingSeconds - 1 > 0
+ };
+ }
+
+ [ReducerMethod]
+ public static TimerState OnTimerCompleted(TimerState state, TimerCompletedAction action)
+ {
+ return state with
+ {
+ IsRunning = false,
+ RemainingSeconds = 0
+ };
+ }
+
+ [ReducerMethod]
+ public static TimerState OnStopTimer(TimerState state, StopTimerAction action)
+ {
+ return state with
+ {
+ IsRunning = false,
+ RemainingSeconds = 0
+ };
+ }
+ }
+}
diff --git a/KoogleApp/Store/Game/ThrowTimer/State.cs b/KoogleApp/Store/Game/ThrowTimer/State.cs
new file mode 100644
index 0000000..9dc4931
--- /dev/null
+++ b/KoogleApp/Store/Game/ThrowTimer/State.cs
@@ -0,0 +1,11 @@
+using Fluxor;
+
+namespace KoogleApp.Store.Game.ThrowTimer
+{
+ [FeatureState]
+ public record TimerState(int RemainingSeconds, bool IsRunning)
+ {
+ public TimerState():this(0, false)
+ {}
+ }
+}
diff --git a/KoogleApp/ThrowPanelState.json b/KoogleApp/ThrowPanelState.json
index d03461c..6e3b3f4 100644
--- a/KoogleApp/ThrowPanelState.json
+++ b/KoogleApp/ThrowPanelState.json
@@ -14,5 +14,6 @@
"ThrowCounterPerRound": 1,
"ThrowMode": 0,
"ThrowPanelStateStatus": 4,
- "ThrowCounter": 0
+ "ThrowCounter": 0,
+ "DayId": 0
}
\ No newline at end of file