MemoryGame/docs/plans/2026-02-24-statistics-screen.md
Claudio Schaad c4656a879e Add statistics screen implementation plan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 20:16:40 +01:00

11 KiB

Statistics Screen Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Add a statistics screen accessible from the results screen showing word mastery progress with accuracy percentage, progress bars, and a reset option.

Architecture: Add a _showStatistics boolean flag to Home.razor that toggles a new view state within the existing if/else chain. Expose words from GameService via a new public method. Add ResetStatisticsAsync() to zero all counts.

Tech Stack: Blazor WebAssembly (.NET 10), C#, CSS (no additional dependencies)


Task 1: Expose statistics words from GameService

Files:

  • Modify: MemoryGame/Services/GameService.cs

Step 1: Add public GetWords() method to GameService

Add this method after UpdateStatisticsAsync:

public IReadOnlyList<GameWord> GetWords()
{
    return _statistics?.Words ?? [];
}

Step 2: Verify it compiles

cd MemoryGame && dotnet build

Expected: Build succeeded, 0 errors.

Step 3: Commit

git add MemoryGame/Services/GameService.cs
git commit -m "feat: expose GetWords() on GameService for statistics screen"

Task 2: Add ResetStatisticsAsync to GameService

Files:

  • Modify: MemoryGame/Services/GameService.cs

Step 1: Add ResetStatisticsAsync() method

Add this method after GetWords():

public async Task ResetStatisticsAsync()
{
    if (_statistics == null)
        return;

    foreach (var word in _statistics.Words)
    {
        word.CorrectCount = 0;
        word.IncorrectCount = 0;
    }

    await _localStorage.SaveStatisticsAsync(_statistics);
}

Step 2: Verify it compiles

cd MemoryGame && dotnet build

Expected: Build succeeded, 0 errors.

Step 3: Commit

git add MemoryGame/Services/GameService.cs
git commit -m "feat: add ResetStatisticsAsync to GameService"

Task 3: Add statistics view state and UI to Home.razor

Files:

  • Modify: MemoryGame/Pages/Home.razor

Step 1: Add _showStatistics field

In the @code block, add after _feedbackClass:

private bool _showStatistics;

Step 2: Add "Statistik anzeigen" button to the results screen

Find the results screen section (ends with <button class="btn-start" @onclick="StartNewGame">Nochmal spielen</button>).

Replace:

<button class="btn-start" @onclick="StartNewGame">Nochmal spielen</button>

With:

<button class="btn-start" @onclick="StartNewGame">Nochmal spielen</button>
<button class="btn-stats" @onclick="ShowStatistics">Statistik anzeigen</button>

Step 3: Change results screen condition

Find:

else if (_currentSession.IsComplete)

Replace with:

else if (_currentSession.IsComplete && !_showStatistics)

Step 4: Add statistics screen section

Add this new block after the results screen closing } and before the final else:

else if (_currentSession.IsComplete && _showStatistics)
{
    var words = GameService.GetWords()
        .OrderBy(w => w.CorrectCount + w.IncorrectCount == 0 ? 1 : 0)
        .ThenBy(w => w.CorrectCount + w.IncorrectCount == 0
            ? 0
            : (double)w.CorrectCount / (w.CorrectCount + w.IncorrectCount))
        .ToList();

    var playedWords = words.Where(w => w.CorrectCount + w.IncorrectCount > 0).ToList();
    var overallAccuracy = playedWords.Count == 0
        ? 0
        : (int)Math.Round(100.0 * playedWords.Sum(w => w.CorrectCount) / playedWords.Sum(w => w.CorrectCount + w.IncorrectCount));

    <div class="stats-screen">
        <h1>Statistik</h1>

        <div class="stats-summary">
            @playedWords.Count von @words.Count Wörtern geübt
            @if (playedWords.Count > 0)
            {
                <span> · @overallAccuracy% richtig</span>
            }
        </div>

        <div class="stats-list">
            @foreach (var word in words)
            {
                var total = word.CorrectCount + word.IncorrectCount;
                var accuracy = total == 0 ? 0 : (int)Math.Round(100.0 * word.CorrectCount / total);
                var barClass = total == 0 ? "bar-unplayed" : accuracy >= 70 ? "bar-green" : accuracy >= 40 ? "bar-orange" : "bar-red";

                <div class="stats-row">
                    <img src="@word.ImagePath" alt="@word.Word" class="stats-thumbnail" />
                    <div class="stats-word-info">
                        <span class="stats-word-name">@word.Word</span>
                        <div class="stats-bar-container">
                            <div class="stats-bar @barClass" style="width: @(total == 0 ? 0 : accuracy)%"></div>
                        </div>
                    </div>
                    <span class="stats-accuracy">@(total == 0 ? "—" : $"{accuracy}% richtig")</span>
                </div>
            }
        </div>

        @if (_confirmReset)
        {
            <div class="reset-confirm">
                <span>Alle Statistiken wirklich zurücksetzen?</span>
                <button class="btn-confirm-yes" @onclick="ConfirmReset">Ja, zurücksetzen</button>
                <button class="btn-confirm-no" @onclick="() => _confirmReset = false">Abbrechen</button>
            </div>
        }
        else
        {
            <button class="btn-reset" @onclick="() => _confirmReset = true">Zurücksetzen</button>
        }

        <button class="btn-start" @onclick="GoToStart">Zurück zum Start</button>
    </div>
}

Step 5: Add _confirmReset field and helper methods

In the @code block, add after _showStatistics:

private bool _confirmReset;

Add these methods after SelectAnswer:

private void ShowStatistics()
{
    _showStatistics = true;
}

private void GoToStart()
{
    _currentSession = null;
    _showStatistics = false;
    _confirmReset = false;
}

private async Task ConfirmReset()
{
    await GameService.ResetStatisticsAsync();
    _confirmReset = false;
    StateHasChanged();
}

Step 6: Verify it compiles

cd MemoryGame && dotnet build

Expected: Build succeeded, 0 errors.

Step 7: Commit

git add MemoryGame/Pages/Home.razor
git commit -m "feat: add statistics screen view state to Home.razor"

Task 4: Add CSS styles for statistics screen

Files:

  • Modify: MemoryGame/wwwroot/css/app.css

Step 1: Add base statistics styles

Append to the end of the base styles section (before the @media (max-width: 768px) block at line 335):

/* Statistics Screen */
.stats-screen {
    width: 100%;
    max-width: 900px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;
    padding: 20px 0;
}

.stats-screen h1 {
    font-size: 2.2rem;
    color: #333;
    margin: 0;
}

.stats-summary {
    font-size: 1.2rem;
    color: #666;
}

.stats-list {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.stats-row {
    display: flex;
    align-items: center;
    gap: 15px;
    padding: 12px;
    background-color: #f8f9fa;
    border: 2px solid #ddd;
    border-radius: 10px;
}

.stats-thumbnail {
    width: 80px;
    height: 80px;
    object-fit: contain;
    flex-shrink: 0;
}

.stats-word-info {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.stats-word-name {
    font-size: 1.3rem;
    font-weight: 600;
    color: #333;
    text-transform: capitalize;
}

.stats-bar-container {
    width: 100%;
    height: 14px;
    background-color: #e0e0e0;
    border-radius: 7px;
    overflow: hidden;
}

.stats-bar {
    height: 100%;
    border-radius: 7px;
    transition: width 0.4s ease;
    min-width: 0;
}

.bar-green  { background-color: #4CAF50; }
.bar-orange { background-color: #FF9800; }
.bar-red    { background-color: #f44336; }
.bar-unplayed { background-color: #e0e0e0; width: 0; }

.stats-accuracy {
    font-size: 1.1rem;
    font-weight: 600;
    color: #555;
    min-width: 110px;
    text-align: right;
    flex-shrink: 0;
}

.btn-stats {
    font-size: 1.2rem;
    padding: 12px 35px;
    background-color: #2196F3;
    color: white;
    border: none;
    border-radius: 10px;
    cursor: pointer;
    font-weight: bold;
    transition: background-color 0.3s;
    margin-top: 10px;
}

@media (hover: hover) and (pointer: fine) {
    .btn-stats:hover {
        background-color: #1976D2;
    }
}

.btn-stats:active {
    transform: scale(0.98);
}

.btn-reset {
    font-size: 1.1rem;
    padding: 10px 30px;
    background-color: #f44336;
    color: white;
    border: none;
    border-radius: 10px;
    cursor: pointer;
    font-weight: bold;
    transition: background-color 0.3s;
}

@media (hover: hover) and (pointer: fine) {
    .btn-reset:hover {
        background-color: #d32f2f;
    }
}

.reset-confirm {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    justify-content: center;
    font-size: 1.1rem;
    color: #333;
}

.btn-confirm-yes {
    padding: 10px 20px;
    background-color: #f44336;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-weight: bold;
    font-size: 1rem;
}

.btn-confirm-no {
    padding: 10px 20px;
    background-color: #9e9e9e;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-weight: bold;
    font-size: 1rem;
}

Step 2: Add tablet-scale overrides for statistics screen

Inside the existing @media (min-width: 2500px) and (min-height: 1550px) block, append:

    .stats-screen {
        max-width: 2000px;
        gap: 35px;
        padding: 30px 0;
    }

    .stats-screen h1 {
        font-size: 4rem;
    }

    .stats-summary {
        font-size: 2rem;
    }

    .stats-list {
        gap: 20px;
    }

    .stats-row {
        gap: 25px;
        padding: 20px;
    }

    .stats-thumbnail {
        width: 140px;
        height: 140px;
    }

    .stats-word-name {
        font-size: 2.2rem;
    }

    .stats-bar-container {
        height: 22px;
        border-radius: 11px;
    }

    .stats-bar {
        border-radius: 11px;
    }

    .stats-accuracy {
        font-size: 2rem;
        min-width: 200px;
    }

    .btn-stats {
        font-size: 2.2rem;
        padding: 22px 65px;
    }

    .btn-reset {
        font-size: 2rem;
        padding: 18px 55px;
    }

    .reset-confirm {
        font-size: 2rem;
        gap: 20px;
    }

    .btn-confirm-yes, .btn-confirm-no {
        font-size: 1.8rem;
        padding: 18px 40px;
    }

Step 3: Verify it builds

cd MemoryGame && dotnet build

Expected: Build succeeded, 0 errors.

Step 4: Commit

git add MemoryGame/wwwroot/css/app.css
git commit -m "feat: add statistics screen CSS styles"

Task 5: Manual smoke test

Step 1: Run the app

cd MemoryGame && dotnet run

Open browser at the URL shown (typically http://localhost:5267).

Step 2: Verify the following flows

  • Play a full 10-round game
  • Results screen shows "Statistik anzeigen" button
  • Tapping it shows the statistics screen with all 20 words
  • Played words show accuracy % and colored progress bar
  • Unplayed words show "—" and are sorted to the bottom
  • "Zurücksetzen" shows inline confirmation; cancelling hides it
  • Confirming reset zeroes all counts and shows "—" for all words
  • "Zurück zum Start" returns to the start screen
  • Starting a new game and playing updates statistics correctly

Step 3: Commit any fixes found during testing, then push

git push -u origin feature/statistics-screen