< Summary

Information
Class: Chronicis.Client.Services.AppContextService
Assembly: Chronicis.Client
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Client/Services/AppContextService.cs
Line coverage
94%
Covered lines: 73
Uncovered lines: 4
Coverable lines: 77
Total lines: 171
Line coverage: 94.8%
Branch coverage
91%
Covered branches: 31
Total branches: 34
Branch coverage: 91.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_CurrentWorldId()100%11100%
get_CurrentCampaignId()100%11100%
get_CurrentWorld()100%11100%
get_CurrentCampaign()100%11100%
get_Worlds()100%11100%
get_IsInitialized()100%11100%
.ctor(...)100%11100%
InitializeAsync()87.5%171684.61%
SelectWorldAsync()100%1010100%
SelectCampaignAsync()100%66100%
RefreshCurrentWorldAsync()87.5%88100%
RefreshWorldsAsync()100%22100%

File(s)

/home/runner/work/chronicis/chronicis/src/Chronicis.Client/Services/AppContextService.cs

#LineLine coverage
 1using Blazored.LocalStorage;
 2using Chronicis.Shared.DTOs;
 3
 4namespace Chronicis.Client.Services;
 5
 6/// <summary>
 7/// Service for managing application context (current World/Campaign)
 8/// </summary>
 9public class AppContextService : IAppContextService
 10{
 11    private readonly IWorldApiService _worldApi;
 12    private readonly ILocalStorageService _localStorage;
 13    private readonly ILogger<AppContextService> _logger;
 14
 15    private const string WorldIdKey = "chronicis_current_world_id";
 16    private const string CampaignIdKey = "chronicis_current_campaign_id";
 17
 2918    public Guid? CurrentWorldId { get; private set; }
 2719    public Guid? CurrentCampaignId { get; private set; }
 3520    public WorldDetailDto? CurrentWorld { get; private set; }
 2221    public CampaignDto? CurrentCampaign { get; private set; }
 4022    public List<WorldDto> Worlds { get; private set; } = new();
 1523    public bool IsInitialized { get; private set; }
 24
 25    public event Action? OnContextChanged;
 26
 1827    public AppContextService(
 1828        IWorldApiService worldApi,
 1829        ILocalStorageService localStorage,
 1830        ILogger<AppContextService> logger)
 31    {
 1832        _worldApi = worldApi;
 1833        _localStorage = localStorage;
 1834        _logger = logger;
 1835    }
 36
 37    public async Task InitializeAsync()
 38    {
 739        if (IsInitialized)
 140            return;
 41
 642        _logger.LogDebug("Initializing app context");
 43
 44        // Load all worlds
 645        Worlds = await _worldApi.GetWorldsAsync();
 46
 647        if (Worlds.Count == 0)
 48        {
 149            _logger.LogWarning("No worlds found for user");
 150            IsInitialized = true;
 151            return;
 52        }
 53
 54        // Try to restore saved selection
 555        Guid? savedWorldId = null;
 556        Guid? savedCampaignId = null;
 57
 58        try
 59        {
 560            var savedWorldIdStr = await _localStorage.GetItemAsStringAsync(WorldIdKey);
 561            var savedCampaignIdStr = await _localStorage.GetItemAsStringAsync(CampaignIdKey);
 62
 563            if (!string.IsNullOrEmpty(savedWorldIdStr) && Guid.TryParse(savedWorldIdStr.Trim('"'), out var parsedWorldId
 264                savedWorldId = parsedWorldId;
 65
 566            if (!string.IsNullOrEmpty(savedCampaignIdStr) && Guid.TryParse(savedCampaignIdStr.Trim('"'), out var parsedC
 067                savedCampaignId = parsedCampaignId;
 568        }
 069        catch (Exception ex)
 70        {
 071            _logger.LogWarning(ex, "Failed to read saved context from localStorage");
 072        }
 73
 74        // Validate saved world exists
 875        if (savedWorldId.HasValue && Worlds.Any(w => w.Id == savedWorldId.Value))
 76        {
 177            await SelectWorldAsync(savedWorldId.Value, savedCampaignId);
 78        }
 79        else
 80        {
 81            // Default to first world
 482            await SelectWorldAsync(Worlds[0].Id);
 83        }
 84
 585        IsInitialized = true;
 586        _logger.LogDebug("App context initialized. World: {WorldId}, Campaign: {CampaignId}",
 587            CurrentWorldId, CurrentCampaignId);
 788    }
 89
 90    public async Task SelectWorldAsync(Guid worldId, Guid? campaignId = null)
 91    {
 1592        _logger.LogDebug("Selecting world {WorldId}", worldId);
 93
 94        // Load world details
 1595        var world = await _worldApi.GetWorldAsync(worldId);
 1596        if (world == null)
 97        {
 298            _logger.LogWarning("Failed to load world {WorldId}", worldId);
 299            return;
 100        }
 101
 13102        CurrentWorldId = worldId;
 13103        CurrentWorld = world;
 104
 105        // Save to localStorage
 13106        await _localStorage.SetItemAsStringAsync(WorldIdKey, worldId.ToString());
 107
 108        // Select campaign
 17109        if (campaignId.HasValue && world.Campaigns.Any(c => c.Id == campaignId.Value))
 110        {
 3111            await SelectCampaignAsync(campaignId.Value);
 112        }
 10113        else if (world.Campaigns.Count > 0)
 114        {
 115            // Default to first campaign if available
 3116            await SelectCampaignAsync(world.Campaigns[0].Id);
 117        }
 118        else
 119        {
 7120            await SelectCampaignAsync(null);
 121        }
 122
 13123        OnContextChanged?.Invoke();
 15124    }
 125
 126    public async Task SelectCampaignAsync(Guid? campaignId)
 127    {
 16128        _logger.LogDebug("Selecting campaign {CampaignId}", campaignId);
 129
 16130        CurrentCampaignId = campaignId;
 131
 16132        if (campaignId.HasValue && CurrentWorld != null)
 133        {
 17134            CurrentCampaign = CurrentWorld.Campaigns.FirstOrDefault(c => c.Id == campaignId.Value);
 8135            await _localStorage.SetItemAsStringAsync(CampaignIdKey, campaignId.Value.ToString());
 136        }
 137        else
 138        {
 8139            CurrentCampaign = null;
 8140            await _localStorage.RemoveItemAsync(CampaignIdKey);
 141        }
 142
 16143        OnContextChanged?.Invoke();
 16144    }
 145
 146    public async Task RefreshCurrentWorldAsync()
 147    {
 3148        if (!CurrentWorldId.HasValue)
 1149            return;
 150
 2151        var world = await _worldApi.GetWorldAsync(CurrentWorldId.Value);
 2152        if (world != null)
 153        {
 2154            CurrentWorld = world;
 155
 156            // Update campaign reference if still valid
 2157            if (CurrentCampaignId.HasValue)
 158            {
 1159                CurrentCampaign = world.Campaigns.FirstOrDefault(c => c.Id == CurrentCampaignId.Value);
 160            }
 161
 2162            OnContextChanged?.Invoke();
 163        }
 3164    }
 165
 166    public async Task RefreshWorldsAsync()
 167    {
 2168        Worlds = await _worldApi.GetWorldsAsync();
 2169        OnContextChanged?.Invoke();
 2170    }
 171}