Implement milestone 2 route navigation

This commit is contained in:
2026-05-04 21:23:45 +02:00
parent c13a2ce7c7
commit def2a3f680
21 changed files with 334 additions and 193 deletions

View File

@@ -9,6 +9,11 @@ namespace RpgRoller.Components.Pages;
[ExcludeFromCodeCoverage]
public partial class Workspace : IAsyncDisposable
{
protected override void OnParametersSet()
{
State.IsScreenMenuOpen = false;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
State.HasInteractiveRenderStarted = true;
@@ -100,6 +105,22 @@ public partial class Workspace : IAsyncDisposable
State.IsScreenMenuOpen = !State.IsScreenMenuOpen;
}
private Task NavigateToRouteAsync(string route)
{
State.IsScreenMenuOpen = false;
Navigation.NavigateTo(route);
return InvokeAsync(StateHasChanged);
}
private Task RedirectToPlayAsync()
{
if (IsPlayRoute)
return Task.CompletedTask;
Navigation.NavigateTo("/play");
return Task.CompletedTask;
}
private static bool IsStaticRenderInteropException(InvalidOperationException exception)
{
return exception.Message.Contains("statically rendered", StringComparison.OrdinalIgnoreCase);
@@ -114,22 +135,30 @@ public partial class Workspace : IAsyncDisposable
[Inject] private NavigationManager Navigation { get; set; } = null!;
[Parameter] public EventCallback<string?> LoggedOut { get; set; }
[Parameter] public WorkspaceRoute Route { get; set; } = WorkspaceRoute.Play;
private WorkspaceState State { get; } = new();
private bool HasSessionInitialized { get; set; }
private bool EnableCharacterControls { get; set; }
private bool EnableCustomRollComposer { 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 WorkspaceCampaignScopeCoordinator Scope => m_Scope ??= new(State, Feedback, JS, WorkspaceQuery,
Play.EnsureSelectedCharacterActiveAsync, Play.RefreshSelectedCharacterSheetAsync, Play.RefreshCampaignLogAsync,
Play.ResetCampaignLogDetailState, Play.ResetCampaignStateTracking, ClearAuthenticatedState,
() => 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, StartStateEventsCoreAsync,
private WorkspaceLiveStateController Live => m_Live ??= new(State, Feedback, () => IsPlayRoute, () => IsAdminRoute,
StartStateEventsCoreAsync,
StopStateEventsCoreAsync, Scope.RefreshCampaignRosterAsync, Play.RefreshSelectedCharacterSheetAsync,
Play.RefreshCampaignLogAsync, () => InvokeAsync(StateHasChanged));
private WorkspacePlayCoordinator Play => m_Play ??= new(State, Feedback, ApiClient, WorkspaceQuery,
private WorkspacePlayCoordinator Play => m_Play ??= new(State, Feedback, () => IsPlayRoute, ApiClient,
WorkspaceQuery,
CanEditCharacter, () => InvokeAsync(StateHasChanged));
private WorkspaceCampaignCoordinator Campaigns => m_Campaigns ??= new(State, Feedback, JS, ApiClient,
@@ -142,10 +171,10 @@ public partial class Workspace : IAsyncDisposable
private WorkspaceFeedbackService Feedback => m_Feedback ??= new(State, () => InvokeAsync(StateHasChanged));
private WorkspaceSessionCoordinator Session => m_Session ??= new(State, Feedback, JS, ApiClient, WorkspaceQuery,
() => IsAdminRoute, RedirectToPlayAsync,
Scope.ReloadCampaignsAsync, Scope.ReloadCharacterCampaignOptionsAsync, Scope.RefreshCampaignScopeAsync,
Live.SyncStateEventsAsync, Live.StopStateEventsAsync, EnsureAdminUsersLoadedAsync,
Play.ResetCampaignLogDetailState, () => InvokeAsync(StateHasChanged),
message => LoggedOut.InvokeAsync(message));
Play.ResetCampaignLogDetailState, message => LoggedOut.InvokeAsync(message));
private IReadOnlyList<AppHeaderMenuItem> HeaderMenuItems
{
@@ -156,14 +185,14 @@ public partial class Workspace : IAsyncDisposable
new()
{
Label = "Play",
IsActive = State.IsPlayScreen,
OnSelected = () => Session.SwitchScreenAsync("play")
IsActive = IsPlayRoute,
OnSelected = () => NavigateToRouteAsync("/play")
},
new()
{
Label = "Campaign Management",
IsActive = State.IsManagementScreen,
OnSelected = () => Session.SwitchScreenAsync("management")
IsActive = IsCampaignsRoute,
OnSelected = () => NavigateToRouteAsync("/campaigns")
}
};
@@ -172,8 +201,8 @@ public partial class Workspace : IAsyncDisposable
items.Add(new()
{
Label = "Admin",
IsActive = State.IsAdminScreen,
OnSelected = () => Session.SwitchScreenAsync(ScreenAdmin)
IsActive = IsAdminRoute,
OnSelected = () => NavigateToRouteAsync("/admin")
});
}
@@ -184,7 +213,6 @@ public partial class Workspace : IAsyncDisposable
private string AdminDatabaseDownloadUrl => Navigation.ToAbsoluteUri("api/admin/database").ToString();
private DotNetObjectReference<Workspace>? DotNetRef { get; set; }
private const string ScreenAdmin = "admin";
private WorkspaceAdminCoordinator? m_Admin;
private WorkspaceCampaignCoordinator? m_Campaigns;
private WorkspaceFeedbackService? m_Feedback;