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

View File

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

View File

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

View File

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