add appsettings, undo/redo without saving

This commit is contained in:
beo3000 2025-12-27 22:11:30 +01:00
parent 03364291aa
commit 125226127d
6 changed files with 69 additions and 23 deletions

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Koogle.Infrastructure.Configuration
{
public class AppSettings
{
public const string SectionName = "AppSettings";
public bool SaveOnUndoRedo { get; set; }= false;
}
}

View File

@ -1,4 +1,5 @@
using Koogle.Domain.Interfaces;
using Koogle.Infrastructure.Configuration;
using Koogle.Infrastructure.Data;
using Koogle.Infrastructure.Identity;
using Koogle.Infrastructure.Repositories;
@ -86,6 +87,10 @@ public static class DependencyInjection
services.AddCascadingAuthenticationState();
// Configurations
services.Configure<AppSettings>(configuration.GetSection(AppSettings.SectionName));
return services;
}
}

View File

@ -181,7 +181,8 @@ public record UndoThrowAction;
public record UndoThrowSuccessAction(
ThrowPanelState ThrowPanel,
ParticipantsState Participants,
object? GameModel);
object? GameModel,
bool IsSaving);
/// <summary>
/// Action dispatched when undo fails (e.g., empty stack).
@ -201,7 +202,8 @@ public record RedoThrowAction;
public record RedoThrowSuccessAction(
ThrowPanelState ThrowPanel,
ParticipantsState Participants,
object? GameModel);
object? GameModel,
bool IsSaving);
/// <summary>
/// Action dispatched when redo fails (e.g., empty stack).

View File

@ -4,8 +4,10 @@ using Koogle.Application.DTOs;
using Koogle.Application.Games;
using Koogle.Application.Interfaces;
using Koogle.Domain.Enums;
using Koogle.Infrastructure.Configuration;
using Koogle.Web.Hubs;
using Koogle.Web.Services;
using Microsoft.Extensions.Options;
namespace Koogle.Web.Store.GameState;
@ -21,6 +23,7 @@ public class GameEffects
private readonly ICurrentClubContext _clubContext;
private readonly GameDefinitionRegistry _gameRegistry;
private readonly GameHubService _hubService;
private readonly IOptions<AppSettings> _appSettings;
// Debounce timer for save operations
private Timer? _saveDebounceTimer;
@ -35,7 +38,8 @@ public class GameEffects
IGamePersistenceService persistenceService,
ICurrentClubContext clubContext,
GameDefinitionRegistry gameRegistry,
GameHubService hubService)
GameHubService hubService,
IOptions<AppSettings> appSettings)
{
_logger = logger;
_gameState = gameState;
@ -43,6 +47,7 @@ public class GameEffects
_clubContext = clubContext;
_gameRegistry = gameRegistry;
_hubService = hubService;
_appSettings = appSettings;
}
/// <summary>
@ -478,20 +483,23 @@ public class GameEffects
public Task HandleUndoThrowSuccess(UndoThrowSuccessAction action, IDispatcher dispatcher)
{
var stateAfterReducer = _gameState.Value;
_logger.LogInformation(
_logger.LogDebug(
"UNDO SUCCESS: State after reducer - pins fallen={Fallen}, total={Total}, UndoStack={UndoCount}, RedoStack={RedoCount}",
stateAfterReducer.ThrowPanelAfter.CountFallenPins(),
stateAfterReducer.ThrowPanelAfter.TotalThrowCounter,
stateAfterReducer.UndoStack.Count,
stateAfterReducer.RedoStack.Count);
// Save after undo as well
_saveDebounceTimer?.Dispose();
_saveDebounceTimer = new Timer(
async _ => await DebouncedSaveAsync(dispatcher),
null,
SaveDebounceMs,
Timeout.Infinite);
if (_appSettings.Value.SaveOnUndoRedo)
{
// Save after undo as well
_saveDebounceTimer?.Dispose();
_saveDebounceTimer = new Timer(
async _ => await DebouncedSaveAsync(dispatcher),
null,
SaveDebounceMs,
Timeout.Infinite);
}
return Task.CompletedTask;
}
@ -524,7 +532,8 @@ public class GameEffects
dispatcher.Dispatch(new UndoThrowSuccessAction(
lastSnapshot.ThrowPanelAfter,
lastSnapshot.Participants,
lastSnapshot.GameModel));
lastSnapshot.GameModel,
_appSettings.Value.SaveOnUndoRedo));
return Task.CompletedTask;
}
@ -554,7 +563,8 @@ public class GameEffects
dispatcher.Dispatch(new RedoThrowSuccessAction(
lastSnapshot.ThrowPanelAfter,
lastSnapshot.Participants,
lastSnapshot.GameModel));
lastSnapshot.GameModel,
_appSettings.Value.SaveOnUndoRedo));
return Task.CompletedTask;
}
@ -565,13 +575,24 @@ public class GameEffects
[EffectMethod]
public Task HandleRedoThrowSuccess(RedoThrowSuccessAction action, IDispatcher dispatcher)
{
// Save after redo
_saveDebounceTimer?.Dispose();
_saveDebounceTimer = new Timer(
async _ => await DebouncedSaveAsync(dispatcher),
null,
SaveDebounceMs,
Timeout.Infinite);
var stateAfterReducer = _gameState.Value;
_logger.LogDebug(
"REDO SUCCESS: State after reducer - pins fallen={Fallen}, total={Total}, UndoStack={UndoCount}, RedoStack={RedoCount}",
stateAfterReducer.ThrowPanelAfter.CountFallenPins(),
stateAfterReducer.ThrowPanelAfter.TotalThrowCounter,
stateAfterReducer.UndoStack.Count,
stateAfterReducer.RedoStack.Count);
if (_appSettings.Value.SaveOnUndoRedo)
{
// Save after redo
_saveDebounceTimer?.Dispose();
_saveDebounceTimer = new Timer(
async _ => await DebouncedSaveAsync(dispatcher),
null,
SaveDebounceMs,
Timeout.Infinite);
}
return Task.CompletedTask;
}

View File

@ -366,7 +366,7 @@ public static class GameReducers
GameModel = action.GameModel,
UndoStack = newUndoStack,
RedoStack = state.RedoStack.Add(currentSnapshot),
IsSaving = true
IsSaving = action.IsSaving
};
}
@ -408,7 +408,7 @@ public static class GameReducers
GameModel = action.GameModel,
UndoStack = state.UndoStack.Add(currentSnapshot),
RedoStack = newRedoStack,
IsSaving = true
IsSaving = action.IsSaving
};
}

View File

@ -8,5 +8,8 @@
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
"AllowedHosts": "*",
"AppSettings": {
"SaveOnUndoRedo" : false
}
}