Split campaign log summary from detail
This commit is contained in:
@@ -177,6 +177,7 @@ public partial class Workspace : IAsyncDisposable
|
||||
{
|
||||
CampaignLog = [];
|
||||
CampaignLogCursor = null;
|
||||
ResetCampaignLogDetailState();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -185,7 +186,7 @@ public partial class Workspace : IAsyncDisposable
|
||||
{
|
||||
CampaignLog = page.Entries.ToList();
|
||||
}
|
||||
else if (page.Entries.Count > 0)
|
||||
else if (page.Entries.Length > 0)
|
||||
{
|
||||
CampaignLog.AddRange(page.Entries);
|
||||
if (CampaignLog.Count > CampaignLogWindowSize)
|
||||
@@ -193,6 +194,7 @@ public partial class Workspace : IAsyncDisposable
|
||||
}
|
||||
|
||||
CampaignLogCursor = page.Cursor ?? afterRollId;
|
||||
TrimCampaignLogDetails();
|
||||
}
|
||||
|
||||
private async Task RefreshCampaignScopeAsync()
|
||||
@@ -207,6 +209,7 @@ public partial class Workspace : IAsyncDisposable
|
||||
ConnectionState = "offline";
|
||||
CurrentCampaignState = null;
|
||||
CampaignLogCursor = null;
|
||||
ResetCampaignLogDetailState();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -614,6 +617,35 @@ public partial class Workspace : IAsyncDisposable
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private async Task ToggleRollDetailAsync(Guid rollId)
|
||||
{
|
||||
if (ExpandedCampaignLogRollId == rollId)
|
||||
{
|
||||
ExpandedCampaignLogRollId = 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);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSkillCreatedAsync(Guid _)
|
||||
{
|
||||
await RefreshSelectedCharacterSheetAsync();
|
||||
@@ -729,13 +761,12 @@ public partial class Workspace : IAsyncDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanEditSkill(SkillSummary skill)
|
||||
private bool CanEditSkill(CharacterSheetSkill skill)
|
||||
{
|
||||
if (SelectedCampaign is null)
|
||||
if (SelectedCharacter is null)
|
||||
return false;
|
||||
|
||||
var character = SelectedCampaign.Characters.FirstOrDefault(c => c.Id == skill.CharacterId);
|
||||
return character is not null && CanEditCharacter(character);
|
||||
return CanEditCharacter(SelectedCharacter);
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
@@ -848,7 +879,7 @@ public partial class Workspace : IAsyncDisposable
|
||||
|
||||
private void SyncSelectedCharacter()
|
||||
{
|
||||
if (SelectedCampaign is null || SelectedCampaign.Characters.Count == 0)
|
||||
if (SelectedCampaign is null || SelectedCampaign.Characters.Length == 0)
|
||||
{
|
||||
SelectedCharacterId = null;
|
||||
return;
|
||||
@@ -886,7 +917,7 @@ public partial class Workspace : IAsyncDisposable
|
||||
return string.IsNullOrWhiteSpace(ownerDisplayName) ? "Unknown owner" : ownerDisplayName;
|
||||
}
|
||||
|
||||
private string SkillDefinitionLabel(SkillSummary skill)
|
||||
private string SkillDefinitionLabel(CharacterSheetSkill skill)
|
||||
{
|
||||
if (!string.Equals(SelectedCampaign?.RulesetId, "d6", StringComparison.OrdinalIgnoreCase))
|
||||
return skill.DiceRollDefinition;
|
||||
@@ -895,48 +926,44 @@ public partial class Workspace : IAsyncDisposable
|
||||
return $"{skill.DiceRollDefinition}, wild {skill.WildDice}, {fumbleLabel}";
|
||||
}
|
||||
|
||||
private string RollerLabel(CampaignLogEntry entry)
|
||||
private CampaignRollDetail? ResolveRollDetail(Guid rollId)
|
||||
{
|
||||
if (User is not null && entry.RollerUserId == User.Id)
|
||||
return "You";
|
||||
|
||||
if (SelectedCampaign is not null && entry.RollerUserId == SelectedCampaign.Gm.Id)
|
||||
return "GM";
|
||||
|
||||
return entry.RollerDisplayName;
|
||||
return CampaignLogDetails.GetValueOrDefault(rollId);
|
||||
}
|
||||
|
||||
private string VisibilityLabel(CampaignLogEntry entry)
|
||||
private bool IsRollDetailLoading(Guid rollId)
|
||||
{
|
||||
if (!string.Equals(entry.Visibility, "private", StringComparison.OrdinalIgnoreCase))
|
||||
return "Public";
|
||||
|
||||
if (User is not null && entry.RollerUserId == User.Id)
|
||||
return "Private (you)";
|
||||
|
||||
return IsCurrentUserGm ? "Private (GM view)" : "Private";
|
||||
return CampaignLogDetailsLoading.Contains(rollId);
|
||||
}
|
||||
|
||||
private string VisibilityBadgeCssClass(CampaignLogEntry entry)
|
||||
private string? GetRollDetailError(Guid rollId)
|
||||
{
|
||||
if (!string.Equals(entry.Visibility, "private", StringComparison.OrdinalIgnoreCase))
|
||||
return "public";
|
||||
|
||||
if (User is not null && entry.RollerUserId == User.Id)
|
||||
return "private-self";
|
||||
|
||||
return IsCurrentUserGm ? "private-gm" : "private-generic";
|
||||
return CampaignLogDetailErrors.GetValueOrDefault(rollId);
|
||||
}
|
||||
|
||||
private string LogEntryCssClass(CampaignLogEntry entry)
|
||||
private void ResetCampaignLogDetailState()
|
||||
{
|
||||
if (!string.Equals(entry.Visibility, "private", StringComparison.OrdinalIgnoreCase))
|
||||
return "public";
|
||||
ExpandedCampaignLogRollId = null;
|
||||
CampaignLogDetails.Clear();
|
||||
CampaignLogDetailsLoading.Clear();
|
||||
CampaignLogDetailErrors.Clear();
|
||||
}
|
||||
|
||||
if (User is not null && entry.RollerUserId == User.Id)
|
||||
return "private-self";
|
||||
private void TrimCampaignLogDetails()
|
||||
{
|
||||
var visibleRollIds = CampaignLog.Select(entry => entry.RollId).ToHashSet();
|
||||
|
||||
return IsCurrentUserGm ? "private-gm" : "private-generic";
|
||||
foreach (var rollId in CampaignLogDetails.Keys.Where(rollId => !visibleRollIds.Contains(rollId)).ToArray())
|
||||
CampaignLogDetails.Remove(rollId);
|
||||
|
||||
foreach (var rollId in CampaignLogDetailsLoading.Where(rollId => !visibleRollIds.Contains(rollId)).ToArray())
|
||||
CampaignLogDetailsLoading.Remove(rollId);
|
||||
|
||||
foreach (var rollId in CampaignLogDetailErrors.Keys.Where(rollId => !visibleRollIds.Contains(rollId)).ToArray())
|
||||
CampaignLogDetailErrors.Remove(rollId);
|
||||
|
||||
if (ExpandedCampaignLogRollId.HasValue && !visibleRollIds.Contains(ExpandedCampaignLogRollId.Value))
|
||||
ExpandedCampaignLogRollId = null;
|
||||
}
|
||||
|
||||
private void ClearAuthenticatedState()
|
||||
@@ -951,6 +978,7 @@ public partial class Workspace : IAsyncDisposable
|
||||
SelectedCharacterSkillGroups = [];
|
||||
CampaignLog = [];
|
||||
CampaignLogCursor = null;
|
||||
ResetCampaignLogDetailState();
|
||||
SelectedCharacterId = null;
|
||||
LastRoll = null;
|
||||
KnownUsernames = [];
|
||||
@@ -1039,9 +1067,9 @@ public partial class Workspace : IAsyncDisposable
|
||||
private CampaignRoster? SelectedCampaign { get; set; }
|
||||
private List<CampaignSummary> Campaigns { get; set; } = [];
|
||||
private List<CampaignOption> CharacterCampaignOptions { get; set; } = [];
|
||||
private List<SkillSummary> SelectedCharacterSkills { get; set; } = [];
|
||||
private List<SkillGroupSummary> SelectedCharacterSkillGroups { get; set; } = [];
|
||||
private List<CampaignLogEntry> CampaignLog { get; set; } = [];
|
||||
private List<CharacterSheetSkill> SelectedCharacterSkills { get; set; } = [];
|
||||
private List<CharacterSheetSkillGroup> SelectedCharacterSkillGroups { get; set; } = [];
|
||||
private List<CampaignLogListEntry> CampaignLog { get; set; } = [];
|
||||
private List<RulesetDefinition> Rulesets { get; set; } = [];
|
||||
private List<AdminUserSummary> AdminUsers { get; set; } = [];
|
||||
private Guid? SelectedCharacterId { get; set; }
|
||||
@@ -1075,6 +1103,10 @@ public partial class Workspace : IAsyncDisposable
|
||||
private DotNetObjectReference<Workspace>? DotNetRef { get; set; }
|
||||
private CampaignStateSnapshot? CurrentCampaignState { get; set; }
|
||||
private Guid? CampaignLogCursor { get; set; }
|
||||
private Guid? ExpandedCampaignLogRollId { get; set; }
|
||||
private Dictionary<Guid, CampaignRollDetail> CampaignLogDetails { get; } = [];
|
||||
private HashSet<Guid> CampaignLogDetailsLoading { get; } = [];
|
||||
private Dictionary<Guid, string> CampaignLogDetailErrors { get; } = [];
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<string?> LoggedOut { get; set; }
|
||||
@@ -1103,7 +1135,7 @@ public partial class Workspace : IAsyncDisposable
|
||||
SelectedCampaign.Name,
|
||||
SelectedCampaign.RulesetId,
|
||||
SelectedCampaign.Gm,
|
||||
ownedCharacters);
|
||||
ownedCharacters.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1111,43 +1143,37 @@ public partial class Workspace : IAsyncDisposable
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PlaySelectedCampaign is null || PlaySelectedCampaign.Characters.Count == 0)
|
||||
var playSelectedCampaign = PlaySelectedCampaign;
|
||||
if (playSelectedCampaign is null || playSelectedCampaign.Characters.Length == 0)
|
||||
return null;
|
||||
|
||||
if (SelectedCharacterId.HasValue)
|
||||
{
|
||||
var selectedCharacter = PlaySelectedCampaign.Characters.FirstOrDefault(character => character.Id == SelectedCharacterId.Value);
|
||||
var selectedCharacter = playSelectedCampaign.Characters.FirstOrDefault(character => character.Id == SelectedCharacterId.Value);
|
||||
if (selectedCharacter is not null)
|
||||
return selectedCharacter;
|
||||
}
|
||||
|
||||
if (ActiveCharacterId.HasValue)
|
||||
{
|
||||
var activeCharacter = PlaySelectedCampaign.Characters.FirstOrDefault(character => character.Id == ActiveCharacterId.Value);
|
||||
var activeCharacter = playSelectedCampaign.Characters.FirstOrDefault(character => character.Id == ActiveCharacterId.Value);
|
||||
if (activeCharacter is not null)
|
||||
return activeCharacter;
|
||||
}
|
||||
|
||||
return PlaySelectedCampaign.Characters[0];
|
||||
return playSelectedCampaign.Characters[0];
|
||||
}
|
||||
}
|
||||
|
||||
private Guid? PlaySelectedCharacterId => PlaySelectedCharacter?.Id;
|
||||
|
||||
private List<SkillSummary> PlaySelectedCharacterSkills =>
|
||||
private List<CharacterSheetSkill> PlaySelectedCharacterSkills =>
|
||||
PlaySelectedCampaign is null || !PlaySelectedCharacterId.HasValue ? [] : SelectedCharacterSkills;
|
||||
|
||||
private List<SkillGroupSummary> PlaySelectedCharacterSkillGroups =>
|
||||
private List<CharacterSheetSkillGroup> PlaySelectedCharacterSkillGroups =>
|
||||
PlaySelectedCampaign is null || !PlaySelectedCharacterId.HasValue ? [] : SelectedCharacterSkillGroups;
|
||||
|
||||
private List<CampaignLogEntry> PlayVisibleCampaignLog =>
|
||||
User is null
|
||||
? CampaignLog.Where(entry => !string.Equals(entry.Visibility, "private", StringComparison.OrdinalIgnoreCase)).ToList()
|
||||
: CampaignLog
|
||||
.Where(entry =>
|
||||
!string.Equals(entry.Visibility, "private", StringComparison.OrdinalIgnoreCase) ||
|
||||
entry.RollerUserId == User.Id)
|
||||
.ToList();
|
||||
private List<CampaignLogListEntry> PlayVisibleCampaignLog => CampaignLog;
|
||||
|
||||
private bool IsCurrentUserGm =>
|
||||
SelectedCampaign is not null && User is not null && SelectedCampaign.Gm.Id == User.Id;
|
||||
@@ -1210,7 +1236,7 @@ public partial class Workspace : IAsyncDisposable
|
||||
private const string CampaignSessionKey = "campaign";
|
||||
private const string MobilePanelSessionKey = "play-panel";
|
||||
private const string RollVisibilitySessionKey = "roll-visibility";
|
||||
private const int CampaignLogWindowSize = 100;
|
||||
private const int CampaignLogWindowSize = 50;
|
||||
private const int ToastDurationMs = 3200;
|
||||
|
||||
private sealed record WorkspaceToast(Guid Id, string Message, bool IsError);
|
||||
|
||||
Reference in New Issue
Block a user