Better move error visibility

This commit is contained in:
2024-11-03 14:36:37 -06:00
parent 7258ac29a0
commit 8a415a6c9d
7 changed files with 148 additions and 29 deletions

View File

@@ -87,28 +87,21 @@ public class ShogiApplication(
return new ForbidResult(); return new ForbidResult();
} }
try var moveResult = command.PieceFromHand.HasValue
? session.Board.Move(command.PieceFromHand.Value.ToDomain(), command.To)
: session.Board.Move(command.From!, command.To, command.IsPromotion ?? false);
if (moveResult.IsSuccess)
{ {
if (command.PieceFromHand.HasValue) await sessionRepository.CreateMove(sessionId, command);
{ await gameHubContext.Emit_PieceMoved(sessionId);
session.Board.Move(command.PieceFromHand.Value.ToDomain(), command.To); return new NoContentResult();
} }
else else
{ {
var isPromotion = command.IsPromotion ?? false; return new ConflictObjectResult(moveResult.Reason);
session.Board.Move(command.From!, command.To, isPromotion);
}
}
catch (InvalidOperationException e)
{
return new ConflictObjectResult(e.Message);
} }
await sessionRepository.CreateMove(sessionId, command);
await gameHubContext.Emit_PieceMoved(sessionId);
return new NoContentResult();
} }
public async Task<IActionResult> JoinSession(string sessionId, string player2Id) public async Task<IActionResult> JoinSession(string sessionId, string player2Id)

View File

@@ -31,13 +31,11 @@
<h3>Capturing and the Hand</h3> <h3>Capturing and the Hand</h3>
<h3>The King and "Check"</h3> <h3>The King and "Check"</h3>
<h3>Victory</h3> <h3>Victory</h3>
</main> </main>
@code { @code {
private bool show = true;
private string activeSessionName = string.Empty; private string activeSessionName = string.Empty;
private Task OnLoginChanged() private Task OnLoginChanged()
{ {
StateHasChanged(); StateHasChanged();
@@ -48,4 +46,10 @@
activeSessionName = s.SessionId.ToString(); activeSessionName = s.SessionId.ToString();
StateHasChanged(); StateHasChanged();
} }
private void OnClickClose()
{
show = false;
StateHasChanged();
}
} }

View File

@@ -14,8 +14,6 @@
@if (showPromotePrompt) @if (showPromotePrompt)
{ {
<!-- Promote prompt -->
<!-- TODO: Add a background div which prevents mouse inputs to the board while this decision is being made. -->
<section class="promote-prompt"> <section class="promote-prompt">
<p>Do you wish to promote?</p> <p>Do you wish to promote?</p>
<div> <div>
@@ -25,10 +23,17 @@
</div> </div>
</section> </section>
} }
@if (showError)
{
<div class="errorModal">
<TemporaryModal OnClickClose="HideError">
<p>That is not a valid move.</p>
</TemporaryModal>
</div>
}
</Stretch>
</Stretch> @code {
@code {
[Parameter, EditorRequired] [Parameter, EditorRequired]
public WhichPlayer Perspective { get; set; } public WhichPlayer Perspective { get; set; }
[Parameter, EditorRequired] [Parameter, EditorRequired]
@@ -37,6 +42,7 @@
private WhichPiece? selectedPieceFromHand; private WhichPiece? selectedPieceFromHand;
private bool showPromotePrompt; private bool showPromotePrompt;
private string? moveTo; private string? moveTo;
private bool showError = false;
protected override void OnParametersSet() protected override void OnParametersSet()
{ {
@@ -96,6 +102,7 @@
if (!success) if (!success)
{ {
selectedPieceFromHand = null; selectedPieceFromHand = null;
showError = true;
} }
} }
StateHasChanged(); StateHasChanged();
@@ -119,9 +126,12 @@
else else
{ {
var success = await ShogiApi.Move(Session.SessionId, new MovePieceCommand(selectedBoardPosition, position, false)); var success = await ShogiApi.Move(Session.SessionId, new MovePieceCommand(selectedBoardPosition, position, false));
Console.WriteLine("Success? {0}", success);
if (!success) if (!success)
{ {
selectedBoardPosition = null; selectedBoardPosition = null;
showError = true;
Console.WriteLine("Show error");
} }
} }
StateHasChanged(); StateHasChanged();
@@ -149,11 +159,16 @@
{ {
if (selectedBoardPosition != null && moveTo != null) if (selectedBoardPosition != null && moveTo != null)
{ {
await ShogiApi.Move(Session.SessionId, new MovePieceCommand(selectedBoardPosition, moveTo, shouldPromote)); showError = await ShogiApi.Move(Session.SessionId, new MovePieceCommand(selectedBoardPosition, moveTo, shouldPromote));
showPromotePrompt = false; showPromotePrompt = false;
return; return;
} }
throw new InvalidOperationException("Unexpected scenario during OnClickPromotionChoice."); throw new InvalidOperationException("Unexpected scenario during OnClickPromotionChoice.");
} }
void HideError()
{
showError = false;
}
} }

View File

@@ -8,7 +8,12 @@
box-shadow: 1px 1px 1px #444; box-shadow: 1px 1px 1px #444;
text-align: center; text-align: center;
z-index: 101; z-index: 101;
background-color: #444; background-color: #444;
border: 1px solid black; border: 1px solid black;
} }
.errorModal {
position: absolute;
top: 1rem;
right: 1rem;
}

View File

@@ -1,4 +1,3 @@
.SearchPage { .SearchPage {
background-color: var(--contrast-color);
padding: 0 0.5rem; padding: 0 0.5rem;
} }

View File

@@ -0,0 +1,39 @@
@using System.Timers
<div class="TemporaryModal PrimaryTheme ThemeVariant--Contrast">
<div class="content">
@ChildContent
</div>
<button class="close" @onclick="OnClickClose">X</button>
<div class="countdown" style="--timeToClose: @TimeToClose">
<div class="time-background">
<div class="time"></div>
</div>
<div class="time-helper-text">This message will close soon.</div>
</div>
</div>
@code {
[Parameter][EditorRequired] public RenderFragment? ChildContent { get; set; }
[Parameter][EditorRequired] public EventCallback OnClickClose { get; set; }
[Parameter] public int SecondsUntilClose { get; set; } = 3;
private string TimeToClose => $"{SecondsUntilClose}s";
private System.Timers.Timer closingTimer = new System.Timers.Timer();
protected override void OnParametersSet()
{
closingTimer = new System.Timers.Timer(TimeSpan.FromSeconds(SecondsUntilClose).TotalMilliseconds)
{
AutoReset = false
};
closingTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimerElapsed);
closingTimer.Start();
}
private void OnTimerElapsed(object? source, ElapsedEventArgs elapsedEventArgs)
{
OnClickClose.InvokeAsync();
}
}

View File

@@ -0,0 +1,64 @@
/* Grid layout */
.TemporaryModal {
--timeToClose: 3s;
display: grid;
grid-template-columns: 1fr auto;
grid-template-rows: repeat(1fr, 3) auto;
grid-template-areas:
"content close"
"content ."
"countdown countdown"
"helper-text helper-text";
gap: 0.5rem;
}
.content {
grid-area: content;
}
button.close {
grid-area: close;
}
.countdown {
grid-area: countdown;
}
.time-helper-text {
grid-area: helper-text;
}
/* Apperance */
.TemporaryModal {
padding: 0.5rem;
}
.countdown .time-background {
background-color: beige;
height: 1ch;
}
.countdown .time {
background-color: red;
height: 100%;
width: 100%;
animation: countdown var(--timeToClose) ease-in-out;
animation-fill-mode: both;
}
.countdown .time-helper-text {
font-size: 70%;
text-align: center;
}
@keyframes countdown {
0% {
width: 100%;
}
100% {
width: 0
}
}