Add targeted workspace live refresh
This commit is contained in:
@@ -153,6 +153,35 @@ public partial class Workspace : IAsyncDisposable
|
||||
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 async Task RefreshCampaignLogAsync()
|
||||
{
|
||||
if (!SelectedCampaignId.HasValue || !IsPlayScreen)
|
||||
{
|
||||
CampaignLog = [];
|
||||
return;
|
||||
}
|
||||
|
||||
CampaignLog = (await WorkspaceQuery.GetCampaignLogAsync(SelectedCampaignId.Value)).ToList();
|
||||
}
|
||||
|
||||
private async Task RefreshCampaignScopeAsync()
|
||||
{
|
||||
if (!SelectedCampaignId.HasValue)
|
||||
@@ -163,26 +192,17 @@ public partial class Workspace : IAsyncDisposable
|
||||
CampaignLog = [];
|
||||
SelectedCharacterId = null;
|
||||
ConnectionState = "offline";
|
||||
CurrentCampaignState = null;
|
||||
return;
|
||||
}
|
||||
|
||||
IsCampaignDataLoading = true;
|
||||
try
|
||||
{
|
||||
var campaignId = SelectedCampaignId.Value;
|
||||
SelectedCampaign = await WorkspaceQuery.GetCampaignAsync(campaignId);
|
||||
SyncSelectedCharacter();
|
||||
|
||||
if (IsPlayScreen && PlaySelectedCharacterId.HasValue && SelectedCharacterId != PlaySelectedCharacterId)
|
||||
SelectedCharacterId = PlaySelectedCharacterId;
|
||||
|
||||
await RefreshCampaignRosterAsync();
|
||||
await RefreshSelectedCharacterSheetAsync();
|
||||
|
||||
CampaignLog = IsPlayScreen
|
||||
? (await WorkspaceQuery.GetCampaignLogAsync(campaignId)).ToList()
|
||||
: [];
|
||||
|
||||
await EnsureSelectedCharacterActiveAsync();
|
||||
await RefreshCampaignLogAsync();
|
||||
ResetCampaignStateTracking();
|
||||
}
|
||||
catch (ApiRequestException ex) when (ex.StatusCode == 401)
|
||||
{
|
||||
@@ -582,37 +602,43 @@ public partial class Workspace : IAsyncDisposable
|
||||
|
||||
private async Task OnSkillCreatedAsync(Guid _)
|
||||
{
|
||||
await RefreshCampaignScopeAsync();
|
||||
await RefreshSelectedCharacterSheetAsync();
|
||||
ResetCampaignStateTracking();
|
||||
SetStatus("Skill created.", false);
|
||||
}
|
||||
|
||||
private async Task OnSkillUpdatedAsync(Guid _)
|
||||
{
|
||||
await RefreshCampaignScopeAsync();
|
||||
await RefreshSelectedCharacterSheetAsync();
|
||||
ResetCampaignStateTracking();
|
||||
SetStatus("Skill updated.", false);
|
||||
}
|
||||
|
||||
private async Task OnSkillGroupCreatedAsync(Guid _)
|
||||
{
|
||||
await RefreshCampaignScopeAsync();
|
||||
await RefreshSelectedCharacterSheetAsync();
|
||||
ResetCampaignStateTracking();
|
||||
SetStatus("Skill group created.", false);
|
||||
}
|
||||
|
||||
private async Task OnSkillGroupUpdatedAsync(Guid _)
|
||||
{
|
||||
await RefreshCampaignScopeAsync();
|
||||
await RefreshSelectedCharacterSheetAsync();
|
||||
ResetCampaignStateTracking();
|
||||
SetStatus("Skill group updated.", false);
|
||||
}
|
||||
|
||||
private async Task OnSkillDeletedAsync(Guid _)
|
||||
{
|
||||
await RefreshCampaignScopeAsync();
|
||||
await RefreshSelectedCharacterSheetAsync();
|
||||
ResetCampaignStateTracking();
|
||||
SetStatus("Skill deleted.", false);
|
||||
}
|
||||
|
||||
private async Task OnSkillGroupDeletedAsync(Guid _)
|
||||
{
|
||||
await RefreshCampaignScopeAsync();
|
||||
await RefreshSelectedCharacterSheetAsync();
|
||||
ResetCampaignStateTracking();
|
||||
SetStatus("Skill group deleted.", false);
|
||||
}
|
||||
|
||||
@@ -635,7 +661,8 @@ public partial class Workspace : IAsyncDisposable
|
||||
{
|
||||
LastRoll = await ApiClient.RequestAsync<RollResult>("POST", $"/api/skills/{skillId}/roll", new RollSkillRequest(RollVisibility));
|
||||
|
||||
await RefreshCampaignScopeAsync();
|
||||
await RefreshCampaignLogAsync();
|
||||
ResetCampaignStateTracking();
|
||||
SetStatus("Roll recorded.", false);
|
||||
Announce("Roll result updated.");
|
||||
}
|
||||
@@ -698,15 +725,44 @@ public partial class Workspace : IAsyncDisposable
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
public async Task OnStateEventReceived(long _)
|
||||
public async Task OnStateEventReceived(CampaignStateSnapshot state)
|
||||
{
|
||||
if (StateRefreshInProgress)
|
||||
return;
|
||||
|
||||
if (!SelectedCampaignId.HasValue || state.CampaignId != SelectedCampaignId.Value)
|
||||
return;
|
||||
|
||||
StateRefreshInProgress = true;
|
||||
try
|
||||
{
|
||||
await RefreshCampaignScopeAsync();
|
||||
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();
|
||||
|
||||
CurrentCampaignState = state;
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -935,6 +991,21 @@ public partial class Workspace : IAsyncDisposable
|
||||
IsScreenMenuOpen = !IsScreenMenuOpen;
|
||||
}
|
||||
|
||||
private void ResetCampaignStateTracking()
|
||||
{
|
||||
CurrentCampaignState = null;
|
||||
}
|
||||
|
||||
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!;
|
||||
|
||||
@@ -987,6 +1058,7 @@ public partial class Workspace : IAsyncDisposable
|
||||
private bool StateRefreshInProgress { get; set; }
|
||||
private bool HasInteractiveRenderStarted { get; set; }
|
||||
private DotNetObjectReference<Workspace>? DotNetRef { get; set; }
|
||||
private CampaignStateSnapshot? CurrentCampaignState { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<string?> LoggedOut { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user