Improve campaign log roll cards

This commit is contained in:
2026-04-03 22:58:55 +02:00
parent 9581442cab
commit b26d58cea4
12 changed files with 353 additions and 36 deletions

View File

@@ -181,7 +181,9 @@ public partial class Workspace : IAsyncDisposable
return;
}
var previousLogCount = CampaignLog.Count;
var page = await WorkspaceQuery.GetCampaignLogPageAsync(SelectedCampaignId.Value, afterRollId, CampaignLogWindowSize);
Guid? newestRollId = null;
if (!afterRollId.HasValue || page.ResetRequired)
{
CampaignLog = page.Entries.ToList();
@@ -193,8 +195,32 @@ public partial class Workspace : IAsyncDisposable
CampaignLog = CampaignLog.TakeLast(CampaignLogWindowSize).ToList();
}
var shouldAutoExpandNewest = afterRollId.HasValue && page.Entries.Length > 0;
if (!shouldAutoExpandNewest &&
!afterRollId.HasValue &&
CurrentCampaignState is not null &&
previousLogCount == 0 &&
page.Entries.Length > 0)
{
shouldAutoExpandNewest = true;
}
if (shouldAutoExpandNewest)
{
newestRollId = page.Entries[^1].RollId;
ExpandedCampaignLogRollId = newestRollId;
FreshCampaignLogRollId = newestRollId;
}
else if (!afterRollId.HasValue)
{
FreshCampaignLogRollId = null;
}
CampaignLogCursor = page.Cursor ?? afterRollId;
TrimCampaignLogDetails();
if (newestRollId.HasValue)
await EnsureRollDetailLoadedAsync(newestRollId.Value);
}
private async Task RefreshCampaignScopeAsync()
@@ -622,28 +648,14 @@ public partial class Workspace : IAsyncDisposable
if (ExpandedCampaignLogRollId == rollId)
{
ExpandedCampaignLogRollId = null;
if (FreshCampaignLogRollId == rollId)
FreshCampaignLogRollId = null;
return;
}
ExpandedCampaignLogRollId = rollId;
CampaignLogDetailErrors.Remove(rollId);
if (CampaignLogDetails.ContainsKey(rollId) || CampaignLogDetailsLoading.Contains(rollId))
return;
CampaignLogDetailsLoading.Add(rollId);
try
{
CampaignLogDetails[rollId] = await WorkspaceQuery.GetRollDetailAsync(rollId);
}
catch (ApiRequestException ex)
{
CampaignLogDetailErrors[rollId] = ex.Message;
}
finally
{
CampaignLogDetailsLoading.Remove(rollId);
await InvokeAsync(StateHasChanged);
}
FreshCampaignLogRollId = null;
await EnsureRollDetailLoadedAsync(rollId);
}
private async Task OnSkillCreatedAsync(Guid _)
@@ -706,8 +718,11 @@ public partial class Workspace : IAsyncDisposable
try
{
LastRoll = await ApiClient.RequestAsync<RollResult>("POST", $"/api/skills/{skillId}/roll", new RollSkillRequest(RollVisibility));
CampaignLogDetails[LastRoll.RollId] = ToCampaignRollDetail(LastRoll);
CampaignLogDetailErrors.Remove(LastRoll.RollId);
await RefreshCampaignLogAsync(CampaignLogCursor);
PromoteFreshRoll(LastRoll.RollId);
ResetCampaignStateTracking();
SetStatus("Roll recorded.", false);
Announce("Roll result updated.");
@@ -949,6 +964,7 @@ public partial class Workspace : IAsyncDisposable
private void ResetCampaignLogDetailState()
{
ExpandedCampaignLogRollId = null;
FreshCampaignLogRollId = null;
CampaignLogDetails.Clear();
CampaignLogDetailsLoading.Clear();
CampaignLogDetailErrors.Clear();
@@ -969,6 +985,45 @@ public partial class Workspace : IAsyncDisposable
if (ExpandedCampaignLogRollId.HasValue && !visibleRollIds.Contains(ExpandedCampaignLogRollId.Value))
ExpandedCampaignLogRollId = null;
if (FreshCampaignLogRollId.HasValue && !visibleRollIds.Contains(FreshCampaignLogRollId.Value))
FreshCampaignLogRollId = null;
}
private async Task EnsureRollDetailLoadedAsync(Guid rollId)
{
CampaignLogDetailErrors.Remove(rollId);
if (CampaignLogDetails.ContainsKey(rollId) || CampaignLogDetailsLoading.Contains(rollId))
return;
CampaignLogDetailsLoading.Add(rollId);
try
{
CampaignLogDetails[rollId] = await WorkspaceQuery.GetRollDetailAsync(rollId);
}
catch (ApiRequestException ex)
{
CampaignLogDetailErrors[rollId] = ex.Message;
}
finally
{
CampaignLogDetailsLoading.Remove(rollId);
await InvokeAsync(StateHasChanged);
}
}
private static CampaignRollDetail ToCampaignRollDetail(RollResult roll)
{
return new CampaignRollDetail(roll.RollId, roll.Breakdown, roll.Dice.ToArray());
}
private void PromoteFreshRoll(Guid rollId)
{
if (!CampaignLog.Any(entry => entry.RollId == rollId))
return;
ExpandedCampaignLogRollId = rollId;
FreshCampaignLogRollId = rollId;
}
private void ClearAuthenticatedState()
@@ -1109,6 +1164,7 @@ public partial class Workspace : IAsyncDisposable
private CampaignStateSnapshot? CurrentCampaignState { get; set; }
private Guid? CampaignLogCursor { get; set; }
private Guid? ExpandedCampaignLogRollId { get; set; }
private Guid? FreshCampaignLogRollId { get; set; }
private Dictionary<Guid, CampaignRollDetail> CampaignLogDetails { get; } = [];
private HashSet<Guid> CampaignLogDetailsLoading { get; } = [];
private Dictionary<Guid, string> CampaignLogDetailErrors { get; } = [];