570 lines
24 KiB
C#
570 lines
24 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using Microsoft.AspNetCore.Components;
|
|
using Microsoft.JSInterop;
|
|
using RpgRoller.Components.Pages.HomeControls;
|
|
using RpgRoller.Contracts;
|
|
using RpgRoller.Domain;
|
|
|
|
namespace RpgRoller.Components.Pages;
|
|
|
|
[ExcludeFromCodeCoverage]
|
|
public partial class Workspace : IAsyncDisposable
|
|
{
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
HasInteractiveRenderStarted = true;
|
|
if (!firstRender)
|
|
return;
|
|
|
|
await Session.InitializeAsync();
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
|
|
private Task RetryAfterHealthIssueAsync()
|
|
{
|
|
return Session.RetryAfterHealthIssueAsync();
|
|
}
|
|
|
|
private Task LoadKnownUsernamesAsync()
|
|
{
|
|
return Session.LoadKnownUsernamesAsync();
|
|
}
|
|
|
|
private async Task ReloadCampaignsAsync(Guid? preferredCampaignId)
|
|
{
|
|
var campaigns = await WorkspaceQuery.GetCampaignsAsync();
|
|
Campaigns = campaigns.OrderBy(c => c.Name, StringComparer.OrdinalIgnoreCase).ToList();
|
|
|
|
if (Campaigns.Count == 0)
|
|
{
|
|
SelectedCampaignId = null;
|
|
await JS.InvokeVoidAsync("rpgRollerApi.setSessionValue", CampaignSessionKey, null);
|
|
return;
|
|
}
|
|
|
|
var campaignIds = Campaigns.Select(c => c.Id).ToHashSet();
|
|
if (preferredCampaignId.HasValue && campaignIds.Contains(preferredCampaignId.Value))
|
|
SelectedCampaignId = preferredCampaignId.Value;
|
|
else if (!SelectedCampaignId.HasValue || !campaignIds.Contains(SelectedCampaignId.Value))
|
|
SelectedCampaignId = Campaigns[0].Id;
|
|
|
|
await JS.InvokeVoidAsync("rpgRollerApi.setSessionValue", CampaignSessionKey, SelectedCampaignId?.ToString());
|
|
}
|
|
|
|
private async Task ReloadCharacterCampaignOptionsAsync()
|
|
{
|
|
var campaignOptions = await WorkspaceQuery.GetCharacterCampaignOptionsAsync();
|
|
CharacterCampaignOptions = campaignOptions.OrderBy(campaign => campaign.Name, StringComparer.OrdinalIgnoreCase).ToList();
|
|
}
|
|
|
|
private async Task RefreshCampaignRosterAsync()
|
|
{
|
|
if (!SelectedCampaignId.HasValue)
|
|
{
|
|
SelectedCampaign = null;
|
|
SelectedCharacterId = null;
|
|
return;
|
|
}
|
|
|
|
SelectedCampaign = await WorkspaceQuery.GetCampaignAsync(SelectedCampaignId.Value);
|
|
SyncSelectedCharacter();
|
|
|
|
if (IsPlayScreen && PlaySelectedCharacterId.HasValue && SelectedCharacterId != PlaySelectedCharacterId)
|
|
SelectedCharacterId = PlaySelectedCharacterId;
|
|
|
|
await EnsureSelectedCharacterActiveAsync();
|
|
}
|
|
|
|
private Task RefreshCampaignLogAsync(Guid? afterRollId = null) => Play.RefreshCampaignLogAsync(afterRollId);
|
|
|
|
private async Task RefreshCampaignScopeAsync()
|
|
{
|
|
if (!SelectedCampaignId.HasValue)
|
|
{
|
|
SelectedCampaign = null;
|
|
SelectedCharacterSkills = [];
|
|
SelectedCharacterSkillGroups = [];
|
|
CampaignLog = [];
|
|
SelectedCharacterId = null;
|
|
ConnectionState = "offline";
|
|
CurrentCampaignState = null;
|
|
CampaignLogCursor = null;
|
|
ResetCampaignLogDetailState();
|
|
return;
|
|
}
|
|
|
|
IsCampaignDataLoading = true;
|
|
try
|
|
{
|
|
await RefreshCampaignRosterAsync();
|
|
await RefreshSelectedCharacterSheetAsync();
|
|
await RefreshCampaignLogAsync();
|
|
ResetCampaignStateTracking();
|
|
}
|
|
catch (ApiRequestException ex) when (ex.StatusCode == 401)
|
|
{
|
|
ClearAuthenticatedState();
|
|
await StopStateEventsAsync();
|
|
await LoggedOut.InvokeAsync("Session expired. Please log in again.");
|
|
}
|
|
catch (ApiRequestException ex)
|
|
{
|
|
SetStatus(ex.Message, true);
|
|
}
|
|
finally
|
|
{
|
|
IsCampaignDataLoading = false;
|
|
}
|
|
}
|
|
|
|
private Task LogoutAsync() => Session.LogoutAsync();
|
|
|
|
private Task SwitchScreenAsync(string screen) => Session.SwitchScreenAsync(screen);
|
|
|
|
private Task SwitchToPlayAsync()
|
|
{
|
|
return SwitchScreenAsync("play");
|
|
}
|
|
|
|
private Task SwitchToManagementAsync()
|
|
{
|
|
return SwitchScreenAsync("management");
|
|
}
|
|
|
|
private Task SwitchToAdminAsync()
|
|
{
|
|
return SwitchScreenAsync(ScreenAdmin);
|
|
}
|
|
|
|
private Task EnsureAdminUsersLoadedAsync() => Admin.EnsureAdminUsersLoadedAsync();
|
|
|
|
private Task ToggleAdminRoleAsync(AdminUserSummary user) => Admin.ToggleAdminRoleAsync(user);
|
|
|
|
private Task DeleteUserAsync(AdminUserSummary user) => Admin.DeleteUserAsync(user);
|
|
|
|
private async Task SetMobilePanelAsync(string panel)
|
|
{
|
|
MobilePanel = string.Equals(panel, "log", StringComparison.OrdinalIgnoreCase) ? "log" : "character";
|
|
await JS.InvokeVoidAsync("rpgRollerApi.setSessionValue", MobilePanelSessionKey, MobilePanel);
|
|
}
|
|
|
|
private Task SetMobilePanelCharacterAsync()
|
|
{
|
|
return SetMobilePanelAsync("character");
|
|
}
|
|
|
|
private Task SetMobilePanelLogAsync()
|
|
{
|
|
return SetMobilePanelAsync("log");
|
|
}
|
|
|
|
private Task OnCampaignSelectionChangedAsync(ChangeEventArgs args) => CampaignsFlow.OnCampaignSelectionChangedAsync(args);
|
|
|
|
private Task OnCampaignCreatedAsync(Guid campaignId) => CampaignsFlow.OnCampaignCreatedAsync(campaignId);
|
|
|
|
private void OpenCreateCharacterModal() => CampaignsFlow.OpenCreateCharacterModal();
|
|
|
|
private Task OpenEditCharacterModal(CharacterSummary character) => CampaignsFlow.OpenEditCharacterModal(character);
|
|
|
|
private void CloseCharacterModals() => CampaignsFlow.CloseCharacterModals();
|
|
|
|
private Task OnCharacterCreatedAsync(Guid? campaignId) => CampaignsFlow.OnCharacterCreatedAsync(campaignId);
|
|
|
|
private Task OnCharacterUpdatedAsync(Guid? campaignId) => CampaignsFlow.OnCharacterUpdatedAsync(campaignId);
|
|
|
|
private Task DeleteSelectedCampaignAsync() => CampaignsFlow.DeleteSelectedCampaignAsync();
|
|
|
|
private Task DeleteCharacterAsync(CharacterSummary character) => CampaignsFlow.DeleteCharacterAsync(character);
|
|
|
|
private Task SelectCharacterAsync(Guid characterId) => Play.SelectCharacterAsync(characterId);
|
|
|
|
private bool CanEditCharacter(CharacterSummary character) => CampaignsFlow.CanEditCharacter(character);
|
|
|
|
private bool CanDeleteCharacter(CharacterSummary character) => CampaignsFlow.CanDeleteCharacter(character);
|
|
|
|
private Task EnsureSelectedCharacterActiveAsync() => Play.EnsureSelectedCharacterActiveAsync();
|
|
|
|
private Task RefreshSelectedCharacterSheetAsync() => Play.RefreshSelectedCharacterSheetAsync();
|
|
|
|
private Task ToggleRollDetailAsync(Guid rollId) => Play.ToggleRollDetailAsync(rollId);
|
|
|
|
private Task OnSkillCreatedAsync(Guid id) => Play.OnSkillCreatedAsync(id);
|
|
|
|
private Task OnSkillUpdatedAsync(Guid id) => Play.OnSkillUpdatedAsync(id);
|
|
|
|
private Task OnSkillGroupCreatedAsync(Guid id) => Play.OnSkillGroupCreatedAsync(id);
|
|
|
|
private Task OnSkillGroupUpdatedAsync(Guid id) => Play.OnSkillGroupUpdatedAsync(id);
|
|
|
|
private Task OnSkillDeletedAsync(Guid id) => Play.OnSkillDeletedAsync(id);
|
|
|
|
private Task OnSkillGroupDeletedAsync(Guid id) => Play.OnSkillGroupDeletedAsync(id);
|
|
|
|
private Task OnCharacterPanelErrorAsync(string message) => Play.OnCharacterPanelErrorAsync(message);
|
|
|
|
private Task OnCampaignLogPanelErrorAsync(string message) => Play.OnCampaignLogPanelErrorAsync(message);
|
|
|
|
private Task RollSkillAsync(Guid skillId) => Play.RollSkillAsync(skillId);
|
|
|
|
private Task OnCustomRollCreatedAsync(RollResult roll) => Play.OnCustomRollCreatedAsync(roll);
|
|
|
|
private Task OnRollVisibilityChanged(string visibility) => Session.OnRollVisibilityChangedAsync(visibility);
|
|
|
|
private bool CanEditSkill(CharacterSheetSkill skill) => Play.CanEditSkill(skill);
|
|
|
|
[JSInvokable]
|
|
public async Task OnStateEventReceived(CampaignStateSnapshot state)
|
|
{
|
|
if (StateRefreshInProgress)
|
|
return;
|
|
|
|
if (!SelectedCampaignId.HasValue || state.CampaignId != SelectedCampaignId.Value)
|
|
return;
|
|
|
|
StateRefreshInProgress = true;
|
|
try
|
|
{
|
|
if (CurrentCampaignState is null)
|
|
{
|
|
CurrentCampaignState = state;
|
|
return;
|
|
}
|
|
|
|
var previousState = CurrentCampaignState;
|
|
var previousSelectedCharacterId = SelectedCharacterId;
|
|
var previousSelectedCharacterVersion = GetCharacterVersion(previousState, previousSelectedCharacterId);
|
|
var rosterChanged = state.RosterVersion != previousState.RosterVersion;
|
|
var logChanged = IsPlayScreen && state.LogVersion != previousState.LogVersion;
|
|
|
|
if (rosterChanged)
|
|
await RefreshCampaignRosterAsync();
|
|
|
|
var selectedCharacterChanged = previousSelectedCharacterId != SelectedCharacterId;
|
|
var selectedCharacterVersionChanged = IsPlayScreen &&
|
|
!selectedCharacterChanged &&
|
|
GetCharacterVersion(state, SelectedCharacterId) != previousSelectedCharacterVersion;
|
|
|
|
if (IsPlayScreen && (selectedCharacterChanged || selectedCharacterVersionChanged))
|
|
await RefreshSelectedCharacterSheetAsync();
|
|
|
|
if (logChanged)
|
|
await RefreshCampaignLogAsync(CampaignLogCursor);
|
|
|
|
CurrentCampaignState = state;
|
|
}
|
|
finally
|
|
{
|
|
StateRefreshInProgress = false;
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
}
|
|
|
|
[JSInvokable]
|
|
public Task OnConnectionStateChanged(string state)
|
|
{
|
|
ConnectionState = state switch
|
|
{
|
|
"connected" => "connected",
|
|
"reconnecting" => "reconnecting",
|
|
_ => "offline"
|
|
};
|
|
|
|
if (ConnectionState == "reconnecting")
|
|
Announce("Reconnecting to live updates.");
|
|
|
|
if (ConnectionState == "offline")
|
|
Announce("Live updates offline. Use manual refresh.");
|
|
|
|
return InvokeAsync(StateHasChanged);
|
|
}
|
|
|
|
private async Task SyncStateEventsAsync()
|
|
{
|
|
if (User is null || !SelectedCampaignId.HasValue || IsAdminScreen)
|
|
{
|
|
await StopStateEventsAsync();
|
|
ConnectionState = "offline";
|
|
return;
|
|
}
|
|
|
|
DotNetRef ??= DotNetObjectReference.Create(this);
|
|
await JS.InvokeVoidAsync("rpgRollerApi.startStateEvents", SelectedCampaignId.Value.ToString(), DotNetRef);
|
|
ConnectionState = "reconnecting";
|
|
}
|
|
|
|
private async Task StopStateEventsAsync()
|
|
{
|
|
if (!HasInteractiveRenderStarted)
|
|
return;
|
|
|
|
try
|
|
{
|
|
await JS.InvokeVoidAsync("rpgRollerApi.stopStateEvents");
|
|
}
|
|
catch (JSDisconnectedException)
|
|
{
|
|
}
|
|
catch (InvalidOperationException ex) when (IsStaticRenderInteropException(ex))
|
|
{
|
|
}
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
await StopStateEventsAsync();
|
|
DotNetRef?.Dispose();
|
|
}
|
|
|
|
private static bool IsStaticRenderInteropException(InvalidOperationException exception)
|
|
{
|
|
return exception.Message.Contains("statically rendered", StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
private void SyncSelectedCharacter()
|
|
{
|
|
if (SelectedCampaign is null || SelectedCampaign.Characters.Length == 0)
|
|
{
|
|
SelectedCharacterId = null;
|
|
return;
|
|
}
|
|
|
|
var candidateIds = SelectedCampaign.Characters.Select(c => c.Id).ToHashSet();
|
|
if (SelectedCharacterId.HasValue && candidateIds.Contains(SelectedCharacterId.Value))
|
|
return;
|
|
|
|
if (ActiveCharacterId.HasValue && candidateIds.Contains(ActiveCharacterId.Value))
|
|
{
|
|
SelectedCharacterId = ActiveCharacterId;
|
|
return;
|
|
}
|
|
|
|
SelectedCharacterId = SelectedCampaign.Characters[0].Id;
|
|
}
|
|
|
|
private string OwnerLabel(Guid ownerUserId)
|
|
{
|
|
if (User is not null && ownerUserId == User.Id)
|
|
return "You";
|
|
|
|
if (SelectedCampaign is null)
|
|
return "Unknown owner";
|
|
|
|
if (ownerUserId == SelectedCampaign.Gm.Id)
|
|
return $"{SelectedCampaign.Gm.DisplayName} (GM)";
|
|
|
|
var ownerDisplayName = SelectedCampaign.Characters
|
|
.Where(character => character.OwnerUserId == ownerUserId)
|
|
.Select(character => character.OwnerDisplayName)
|
|
.FirstOrDefault(displayName => !string.IsNullOrWhiteSpace(displayName));
|
|
|
|
return string.IsNullOrWhiteSpace(ownerDisplayName) ? "Unknown owner" : ownerDisplayName;
|
|
}
|
|
|
|
private string SkillDefinitionLabel(CharacterSheetSkill skill)
|
|
{
|
|
if (!string.Equals(SelectedCampaign?.RulesetId, "d6", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
if (string.Equals(SelectedCampaign?.RulesetId, RulesetFormHelpers.RulesetIds.Rolemaster, StringComparison.OrdinalIgnoreCase))
|
|
return RulesetFormHelpers.DescribeRolemasterExpression(skill.DiceRollDefinition, skill.FumbleRange);
|
|
|
|
return skill.DiceRollDefinition;
|
|
}
|
|
|
|
var fumbleLabel = skill.AllowFumble ? "fumble on" : "fumble off";
|
|
return $"{skill.DiceRollDefinition}, wild {skill.WildDice}, {fumbleLabel}";
|
|
}
|
|
|
|
private CampaignRollDetail? ResolveRollDetail(Guid rollId) => Play.ResolveRollDetail(rollId);
|
|
|
|
private bool IsRollDetailLoading(Guid rollId) => Play.IsRollDetailLoading(rollId);
|
|
|
|
private string? GetRollDetailError(Guid rollId) => Play.GetRollDetailError(rollId);
|
|
|
|
private void ResetCampaignLogDetailState() => Play.ResetCampaignLogDetailState();
|
|
|
|
private void ClearAuthenticatedState() => Session.ClearAuthenticatedState();
|
|
|
|
private void SetStatus(string message, bool isError)
|
|
{
|
|
Feedback.SetStatus(message, isError);
|
|
}
|
|
|
|
private void Announce(string message)
|
|
{
|
|
Feedback.Announce(message);
|
|
}
|
|
|
|
private void ToggleScreenMenu()
|
|
{
|
|
IsScreenMenuOpen = !IsScreenMenuOpen;
|
|
}
|
|
|
|
private void ResetCampaignStateTracking() => Play.ResetCampaignStateTracking();
|
|
|
|
private static long GetCharacterVersion(CampaignStateSnapshot snapshot, Guid? characterId)
|
|
{
|
|
if (!characterId.HasValue)
|
|
return 0;
|
|
|
|
return snapshot.CharacterVersions
|
|
.FirstOrDefault(version => version.CharacterId == characterId.Value)
|
|
?.Version ?? 0;
|
|
}
|
|
|
|
[Inject]
|
|
private IJSRuntime JS { get; set; } = null!;
|
|
|
|
[Inject]
|
|
private RpgRollerApiClient ApiClient { get; set; } = null!;
|
|
|
|
[Inject]
|
|
private WorkspaceQueryService WorkspaceQuery { get; set; } = null!;
|
|
|
|
[Inject]
|
|
private NavigationManager Navigation { get; set; } = null!;
|
|
|
|
private WorkspaceState State { get; } = new();
|
|
|
|
private UserSummary? User { get => State.User; set => State.User = value; }
|
|
private Guid? ActiveCharacterId { get => State.ActiveCharacterId; set => State.ActiveCharacterId = value; }
|
|
private Guid? SelectedCampaignId { get => State.SelectedCampaignId; set => State.SelectedCampaignId = value; }
|
|
private CampaignRoster? SelectedCampaign { get => State.SelectedCampaign; set => State.SelectedCampaign = value; }
|
|
private List<CampaignSummary> Campaigns { get => State.Campaigns; set => State.Campaigns = value; }
|
|
private List<CampaignOption> CharacterCampaignOptions { get => State.CharacterCampaignOptions; set => State.CharacterCampaignOptions = value; }
|
|
private List<CharacterSheetSkill> SelectedCharacterSkills { get => State.SelectedCharacterSkills; set => State.SelectedCharacterSkills = value; }
|
|
private List<CharacterSheetSkillGroup> SelectedCharacterSkillGroups { get => State.SelectedCharacterSkillGroups; set => State.SelectedCharacterSkillGroups = value; }
|
|
private List<CampaignLogListEntry> CampaignLog { get => State.CampaignLog; set => State.CampaignLog = value; }
|
|
private List<RulesetDefinition> Rulesets { get => State.Rulesets; set => State.Rulesets = value; }
|
|
private List<AdminUserSummary> AdminUsers { get => State.AdminUsers; set => State.AdminUsers = value; }
|
|
private Guid? SelectedCharacterId { get => State.SelectedCharacterId; set => State.SelectedCharacterId = value; }
|
|
private RollResult? LastRoll { get => State.LastRoll; set => State.LastRoll = value; }
|
|
private List<string> KnownUsernames { get => State.KnownUsernames; set => State.KnownUsernames = value; }
|
|
private string RollVisibility { get => State.RollVisibility; set => State.RollVisibility = value; }
|
|
|
|
private bool IsMutating { get => State.IsMutating; set => State.IsMutating = value; }
|
|
private bool IsCampaignDataLoading { get => State.IsCampaignDataLoading; set => State.IsCampaignDataLoading = value; }
|
|
private bool IsAdminDataLoading { get => State.IsAdminDataLoading; set => State.IsAdminDataLoading = value; }
|
|
private bool HasLoadedAdminUsers { get => State.HasLoadedAdminUsers; set => State.HasLoadedAdminUsers = value; }
|
|
private bool HasHealthIssue { get => State.HasHealthIssue; set => State.HasHealthIssue = value; }
|
|
private string HealthIssueMessage { get => State.HealthIssueMessage; set => State.HealthIssueMessage = value; }
|
|
private List<WorkspaceToast> Toasts => State.Toasts;
|
|
private string CurrentScreen { get => State.CurrentScreen; set => State.CurrentScreen = value; }
|
|
private string MobilePanel { get => State.MobilePanel; set => State.MobilePanel = value; }
|
|
private string ConnectionState { get => State.ConnectionState; set => State.ConnectionState = value; }
|
|
private string LiveAnnouncement { get => State.LiveAnnouncement; set => State.LiveAnnouncement = value; }
|
|
private bool IsScreenMenuOpen { get => State.IsScreenMenuOpen; set => State.IsScreenMenuOpen = value; }
|
|
|
|
private bool ShowCreateCharacterModal { get => State.ShowCreateCharacterModal; set => State.ShowCreateCharacterModal = value; }
|
|
private bool ShowEditCharacterModal { get => State.ShowEditCharacterModal; set => State.ShowEditCharacterModal = value; }
|
|
private bool CanEditCharacterOwner { get => State.CanEditCharacterOwner; set => State.CanEditCharacterOwner = value; }
|
|
private Guid? EditingCharacterId { get => State.EditingCharacterId; set => State.EditingCharacterId = value; }
|
|
private CharacterFormModel CreateCharacterInitialModel { get => State.CreateCharacterInitialModel; set => State.CreateCharacterInitialModel = value; }
|
|
private CharacterFormModel EditCharacterInitialModel { get => State.EditCharacterInitialModel; set => State.EditCharacterInitialModel = value; }
|
|
private int CreateCharacterFormVersion { get => State.CreateCharacterFormVersion; set => State.CreateCharacterFormVersion = value; }
|
|
private int EditCharacterFormVersion { get => State.EditCharacterFormVersion; set => State.EditCharacterFormVersion = value; }
|
|
private bool StateRefreshInProgress { get => State.StateRefreshInProgress; set => State.StateRefreshInProgress = value; }
|
|
private bool HasInteractiveRenderStarted { get => State.HasInteractiveRenderStarted; set => State.HasInteractiveRenderStarted = value; }
|
|
private DotNetObjectReference<Workspace>? DotNetRef { get; set; }
|
|
private CampaignStateSnapshot? CurrentCampaignState { get => State.CurrentCampaignState; set => State.CurrentCampaignState = value; }
|
|
private Guid? CampaignLogCursor { get => State.CampaignLogCursor; set => State.CampaignLogCursor = value; }
|
|
private Guid? ExpandedCampaignLogRollId { get => State.ExpandedCampaignLogRollId; set => State.ExpandedCampaignLogRollId = value; }
|
|
private Guid? FreshCampaignLogRollId { get => State.FreshCampaignLogRollId; set => State.FreshCampaignLogRollId = value; }
|
|
private Dictionary<Guid, CampaignRollDetail> CampaignLogDetails => State.CampaignLogDetails;
|
|
private HashSet<Guid> CampaignLogDetailsLoading => State.CampaignLogDetailsLoading;
|
|
private Dictionary<Guid, string> CampaignLogDetailErrors => State.CampaignLogDetailErrors;
|
|
|
|
[Parameter]
|
|
public EventCallback<string?> LoggedOut { get; set; }
|
|
|
|
private string? SelectedCampaignName => State.SelectedCampaignName;
|
|
private CharacterSummary? SelectedCharacter => State.SelectedCharacter;
|
|
private CampaignRoster? PlaySelectedCampaign => State.PlaySelectedCampaign;
|
|
private CharacterSummary? PlaySelectedCharacter => State.PlaySelectedCharacter;
|
|
private Guid? PlaySelectedCharacterId => State.PlaySelectedCharacterId;
|
|
private List<CharacterSheetSkill> PlaySelectedCharacterSkills => State.PlaySelectedCharacterSkills;
|
|
private List<CharacterSheetSkillGroup> PlaySelectedCharacterSkillGroups => State.PlaySelectedCharacterSkillGroups;
|
|
private List<CampaignLogListEntry> PlayVisibleCampaignLog => State.PlayVisibleCampaignLog;
|
|
private bool IsCurrentUserGm => State.IsCurrentUserGm;
|
|
private bool IsCurrentUserAdmin => State.IsCurrentUserAdmin;
|
|
private bool CanDeleteSelectedCampaign => State.CanDeleteSelectedCampaign;
|
|
private bool IsSelectedCampaignD6 => State.IsSelectedCampaignD6;
|
|
|
|
private bool IsPlayScreen => State.IsPlayScreen;
|
|
private bool IsManagementScreen => State.IsManagementScreen;
|
|
private bool IsAdminScreen => State.IsAdminScreen;
|
|
private WorkspacePlayCoordinator Play => m_Play ??= new(
|
|
State,
|
|
Feedback,
|
|
ApiClient,
|
|
WorkspaceQuery,
|
|
CanEditCharacter,
|
|
() => InvokeAsync(StateHasChanged));
|
|
private WorkspaceCampaignCoordinator CampaignsFlow => m_CampaignsFlow ??= new(
|
|
State,
|
|
Feedback,
|
|
JS,
|
|
ApiClient,
|
|
LoadKnownUsernamesAsync,
|
|
ReloadCampaignsAsync,
|
|
ReloadCharacterCampaignOptionsAsync,
|
|
RefreshCampaignScopeAsync,
|
|
SyncStateEventsAsync);
|
|
private WorkspaceAdminCoordinator Admin => m_Admin ??= new(
|
|
State,
|
|
Feedback,
|
|
JS,
|
|
ApiClient,
|
|
WorkspaceQuery,
|
|
ClearAuthenticatedState,
|
|
StopStateEventsAsync,
|
|
message => LoggedOut.InvokeAsync(message));
|
|
private WorkspaceFeedbackService Feedback => m_Feedback ??= new(State, () => InvokeAsync(StateHasChanged));
|
|
private WorkspaceSessionCoordinator Session => m_Session ??= new(
|
|
State,
|
|
Feedback,
|
|
JS,
|
|
ApiClient,
|
|
WorkspaceQuery,
|
|
ReloadCampaignsAsync,
|
|
ReloadCharacterCampaignOptionsAsync,
|
|
RefreshCampaignScopeAsync,
|
|
SyncStateEventsAsync,
|
|
StopStateEventsAsync,
|
|
EnsureAdminUsersLoadedAsync,
|
|
ResetCampaignLogDetailState,
|
|
() => InvokeAsync(StateHasChanged),
|
|
message => LoggedOut.InvokeAsync(message));
|
|
private IReadOnlyList<AppHeaderMenuItem> HeaderMenuItems
|
|
{
|
|
get
|
|
{
|
|
var items = new List<AppHeaderMenuItem>
|
|
{
|
|
new() { Label = "Play", IsActive = IsPlayScreen, OnSelected = SwitchToPlayAsync },
|
|
new() { Label = "Campaign Management", IsActive = IsManagementScreen, OnSelected = SwitchToManagementAsync }
|
|
};
|
|
|
|
if (IsCurrentUserAdmin)
|
|
items.Add(new AppHeaderMenuItem { Label = "Admin", IsActive = IsAdminScreen, OnSelected = SwitchToAdminAsync });
|
|
|
|
return items;
|
|
}
|
|
}
|
|
|
|
private string ConnectionStateLabel => State.ConnectionStateLabel;
|
|
private string ConnectionStateCssClass => State.ConnectionStateCssClass;
|
|
private string AppCssClass => State.AppCssClass;
|
|
private string AdminDatabaseDownloadUrl => Navigation.ToAbsoluteUri("api/admin/database").ToString();
|
|
|
|
private const string ScreenAdmin = "admin";
|
|
private const string CampaignSessionKey = "campaign";
|
|
private const string MobilePanelSessionKey = "play-panel";
|
|
private const int CampaignLogWindowSize = 25;
|
|
|
|
private WorkspacePlayCoordinator? m_Play;
|
|
private WorkspaceCampaignCoordinator? m_CampaignsFlow;
|
|
private WorkspaceAdminCoordinator? m_Admin;
|
|
private WorkspaceFeedbackService? m_Feedback;
|
|
private WorkspaceSessionCoordinator? m_Session;
|
|
}
|