223 lines
7.7 KiB
C#
223 lines
7.7 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using Microsoft.AspNetCore.Components;
|
|
using Microsoft.JSInterop;
|
|
using RpgRoller.Components.Pages.HomeControls;
|
|
using RpgRoller.Contracts;
|
|
|
|
namespace RpgRoller.Components.Pages;
|
|
|
|
[ExcludeFromCodeCoverage]
|
|
public partial class Workspace : IAsyncDisposable
|
|
{
|
|
protected override void OnParametersSet()
|
|
{
|
|
State.IsScreenMenuOpen = false;
|
|
}
|
|
|
|
[JSInvokable]
|
|
public Task OnStateEventReceived(CampaignStateSnapshot state)
|
|
{
|
|
return Live.OnStateEventReceivedAsync(state);
|
|
}
|
|
|
|
[JSInvokable]
|
|
public Task OnConnectionStateChanged(string state)
|
|
{
|
|
return Live.OnConnectionStateChangedAsync(state);
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
await StopStateEventsAsync();
|
|
DotNetRef?.Dispose();
|
|
}
|
|
|
|
private bool CanEditCharacter(CharacterSummary character)
|
|
{
|
|
return Campaigns.CanEditCharacter(character);
|
|
}
|
|
|
|
private void ClearAuthenticatedState()
|
|
{
|
|
Session.ClearAuthenticatedState();
|
|
}
|
|
|
|
private Task EnsureAdminUsersLoadedAsync()
|
|
{
|
|
return Admin.EnsureAdminUsersLoadedAsync();
|
|
}
|
|
|
|
private Task StopStateEventsAsync()
|
|
{
|
|
return Live.StopStateEventsAsync();
|
|
}
|
|
|
|
private async Task StartStateEventsCoreAsync(Guid campaignId)
|
|
{
|
|
DotNetRef ??= DotNetObjectReference.Create(this);
|
|
await JS.InvokeVoidAsync("rpgRollerApi.startStateEvents", campaignId.ToString(), DotNetRef);
|
|
}
|
|
|
|
private async Task StopStateEventsCoreAsync()
|
|
{
|
|
try
|
|
{
|
|
await JS.InvokeVoidAsync("rpgRollerApi.stopStateEvents");
|
|
}
|
|
catch (JSDisconnectedException)
|
|
{
|
|
}
|
|
catch (InvalidOperationException ex) when (IsStaticRenderInteropException(ex))
|
|
{
|
|
}
|
|
}
|
|
|
|
private void ToggleScreenMenu()
|
|
{
|
|
State.IsScreenMenuOpen = !State.IsScreenMenuOpen;
|
|
}
|
|
|
|
private Task NavigateToRouteAsync(string route)
|
|
{
|
|
State.IsScreenMenuOpen = false;
|
|
Navigation.NavigateTo(route, forceLoad: true);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private Task RedirectToPlayAsync()
|
|
{
|
|
if (IsPlayRoute)
|
|
return Task.CompletedTask;
|
|
|
|
Navigation.NavigateTo("/play", forceLoad: true);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private Task RequestRefreshAsync()
|
|
{
|
|
return InvokeAsync(StateHasChanged);
|
|
}
|
|
|
|
private Task InitializeRouteAsync()
|
|
{
|
|
return InitializationTask ??= InitializeRouteCoreAsync();
|
|
}
|
|
|
|
private async Task InitializeRouteCoreAsync()
|
|
{
|
|
if (HasSessionInitialized)
|
|
return;
|
|
|
|
State.HasInteractiveRenderStarted = true;
|
|
await Session.InitializeAsync();
|
|
HasSessionInitialized = true;
|
|
await RequestRefreshAsync();
|
|
}
|
|
|
|
private static bool IsStaticRenderInteropException(InvalidOperationException exception)
|
|
{
|
|
return exception.Message.Contains("statically rendered", StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[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!;
|
|
|
|
[Parameter] public EventCallback<string?> LoggedOut { get; set; }
|
|
[Parameter] public WorkspaceRoute Route { get; set; } = WorkspaceRoute.Play;
|
|
[Parameter] public RenderFragment<WorkspacePageContext>? ChildContent { get; set; }
|
|
|
|
private WorkspaceState State { get; } = new();
|
|
private bool HasSessionInitialized { get; set; }
|
|
private bool IsPlayRoute => Route == WorkspaceRoute.Play;
|
|
private bool IsCampaignsRoute => Route == WorkspaceRoute.Campaigns;
|
|
private bool IsAdminRoute => Route == WorkspaceRoute.Admin;
|
|
private string AppCssClass => IsPlayRoute ? "rr-app app-play" : "rr-app";
|
|
private bool ShowCampaignInHeader => !IsAdminRoute;
|
|
private bool ShowConnectionStateInHeader => IsPlayRoute;
|
|
|
|
private WorkspacePageContext PageContext => new(State, Play, Campaigns, Admin, Scope, Session,
|
|
InitializeRouteAsync, HasSessionInitialized, RequestRefreshAsync, AdminDatabaseDownloadUrl, HeaderMenuItems,
|
|
IsPlayRoute, IsCampaignsRoute, IsAdminRoute);
|
|
|
|
private WorkspaceCampaignScopeCoordinator Scope => m_Scope ??= new(State, Feedback, JS, WorkspaceQuery,
|
|
() => IsPlayRoute, Play.EnsureSelectedCharacterActiveAsync, Play.RefreshSelectedCharacterSheetAsync,
|
|
Play.RefreshCampaignLogAsync, Play.ResetCampaignLogDetailState, Play.ResetCampaignStateTracking,
|
|
ClearAuthenticatedState,
|
|
StopStateEventsAsync, message => LoggedOut.InvokeAsync(message));
|
|
|
|
private WorkspaceLiveStateController Live => m_Live ??=
|
|
new(State, Feedback, () => IsPlayRoute, () => IsAdminRoute, StartStateEventsCoreAsync,
|
|
StopStateEventsCoreAsync, Scope.RefreshCampaignRosterAsync, Play.RefreshSelectedCharacterSheetAsync,
|
|
Play.RefreshCampaignLogAsync, RequestRefreshAsync);
|
|
|
|
private WorkspacePlayCoordinator Play => m_Play ??= new(State, Feedback, () => IsPlayRoute, ApiClient,
|
|
WorkspaceQuery,
|
|
CanEditCharacter, RequestRefreshAsync);
|
|
|
|
private WorkspaceCampaignCoordinator Campaigns => m_Campaigns ??= new(State, Feedback, JS, ApiClient,
|
|
Session.LoadKnownUsernamesAsync, Scope.ReloadCampaignsAsync, Scope.ReloadCharacterCampaignOptionsAsync,
|
|
Scope.RefreshCampaignScopeAsync, Live.SyncStateEventsAsync, RequestRefreshAsync);
|
|
|
|
private WorkspaceAdminCoordinator Admin => m_Admin ??= new(State, Feedback, JS, ApiClient, WorkspaceQuery,
|
|
ClearAuthenticatedState, StopStateEventsAsync, message => LoggedOut.InvokeAsync(message));
|
|
|
|
private WorkspaceFeedbackService Feedback => m_Feedback ??= new(State, RequestRefreshAsync);
|
|
|
|
private WorkspaceSessionCoordinator Session => m_Session ??= new(State, Feedback, JS, ApiClient, WorkspaceQuery,
|
|
() => IsAdminRoute, RedirectToPlayAsync,
|
|
Scope.ReloadCampaignsAsync, Scope.ReloadCharacterCampaignOptionsAsync, Scope.RefreshCampaignScopeAsync,
|
|
RequestRefreshAsync, Live.SyncStateEventsAsync, Live.StopStateEventsAsync, EnsureAdminUsersLoadedAsync,
|
|
Play.ResetCampaignLogDetailState, message => LoggedOut.InvokeAsync(message));
|
|
|
|
private IReadOnlyList<AppHeaderMenuItem> HeaderMenuItems
|
|
{
|
|
get
|
|
{
|
|
var items = new List<AppHeaderMenuItem>
|
|
{
|
|
new()
|
|
{
|
|
Label = "Play",
|
|
IsActive = IsPlayRoute,
|
|
OnSelected = () => NavigateToRouteAsync("/play")
|
|
},
|
|
new()
|
|
{
|
|
Label = "Campaign Management",
|
|
IsActive = IsCampaignsRoute,
|
|
OnSelected = () => NavigateToRouteAsync("/campaigns")
|
|
}
|
|
};
|
|
|
|
if (State.IsCurrentUserAdmin)
|
|
{
|
|
items.Add(new()
|
|
{
|
|
Label = "Admin",
|
|
IsActive = IsAdminRoute,
|
|
OnSelected = () => NavigateToRouteAsync("/admin")
|
|
});
|
|
}
|
|
|
|
return items;
|
|
}
|
|
}
|
|
|
|
private string AdminDatabaseDownloadUrl => Navigation.ToAbsoluteUri("api/admin/database").ToString();
|
|
private DotNetObjectReference<Workspace>? DotNetRef { get; set; }
|
|
|
|
private WorkspaceAdminCoordinator? m_Admin;
|
|
private WorkspaceCampaignCoordinator? m_Campaigns;
|
|
private WorkspaceFeedbackService? m_Feedback;
|
|
private WorkspaceLiveStateController? m_Live;
|
|
private WorkspacePlayCoordinator? m_Play;
|
|
|
|
private WorkspaceCampaignScopeCoordinator? m_Scope;
|
|
private WorkspaceSessionCoordinator? m_Session;
|
|
private Task? InitializationTask { get; set; }
|
|
} |