Add dashboard next-step transition flow
This commit is contained in:
parent
7e43c6eb66
commit
6a95e0a170
3 changed files with 163 additions and 1 deletions
|
|
@ -294,6 +294,16 @@ FHyperTwistTrainingRunStepResult UHyperTwistCoachDashboardWidget::SubmitSyntheti
|
|||
return SubmitTrainingAttempt(Attempt, TimeMs);
|
||||
}
|
||||
|
||||
bool UHyperTwistCoachDashboardWidget::ContinueCurrentRunFlow()
|
||||
{
|
||||
const bool bSucceeded = StartLiveAttemptTimer();
|
||||
if (!bSucceeded)
|
||||
{
|
||||
UpdateDashboardPresentation();
|
||||
}
|
||||
return bSucceeded;
|
||||
}
|
||||
|
||||
bool UHyperTwistCoachDashboardWidget::StartLiveAttemptTimer()
|
||||
{
|
||||
if (!CachedRunState.Session.IsStructurallyValid() || !CachedRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
|
||||
|
|
@ -483,6 +493,11 @@ void UHyperTwistCoachDashboardWidget::HandleCompleteRunClicked()
|
|||
UpdateDashboardPresentation();
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::HandleContinueRunClicked()
|
||||
{
|
||||
ContinueCurrentRunFlow();
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::HandleClearRunClicked()
|
||||
{
|
||||
ClearActiveTrainingRun();
|
||||
|
|
@ -706,6 +721,18 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
|
|||
TEXT("CoachCurrentCaseNotation"),
|
||||
2
|
||||
);
|
||||
TransitionHeaderTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
|
||||
WidgetTree,
|
||||
RootLayout,
|
||||
TEXT("CoachTransitionHeader"),
|
||||
2
|
||||
);
|
||||
TransitionStatusTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
|
||||
WidgetTree,
|
||||
RootLayout,
|
||||
TEXT("CoachTransitionStatus"),
|
||||
2
|
||||
);
|
||||
AttemptControlHeaderTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
|
||||
WidgetTree,
|
||||
RootLayout,
|
||||
|
|
@ -1005,6 +1032,17 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
|
|||
);
|
||||
CompleteRunButtonLabel = CompleteRunLabelRaw;
|
||||
|
||||
UTextBlock* ContinueRunLabelRaw = nullptr;
|
||||
ContinueRunButton = HyperTwistCoachDashboardWidgetInternal::AddButton(
|
||||
WidgetTree,
|
||||
RunControlRow,
|
||||
TEXT("ContinueRunButton"),
|
||||
TEXT("ContinueRunButtonLabel"),
|
||||
TEXT("Continue Run"),
|
||||
ContinueRunLabelRaw
|
||||
);
|
||||
ContinueRunButtonLabel = ContinueRunLabelRaw;
|
||||
|
||||
UTextBlock* ClearRunLabelRaw = nullptr;
|
||||
ClearRunButton = HyperTwistCoachDashboardWidgetInternal::AddButton(
|
||||
WidgetTree,
|
||||
|
|
@ -1126,6 +1164,10 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
|
|||
{
|
||||
CompleteRunButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleCompleteRunClicked);
|
||||
}
|
||||
if (ContinueRunButton != nullptr)
|
||||
{
|
||||
ContinueRunButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleContinueRunClicked);
|
||||
}
|
||||
if (ClearRunButton != nullptr)
|
||||
{
|
||||
ClearRunButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleClearRunClicked);
|
||||
|
|
@ -1328,6 +1370,83 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
}
|
||||
LastAttemptPhaseSummary = FString::Join(PhaseParts, TEXT(" | "));
|
||||
}
|
||||
const bool bHasSessionScopedLastStep = !LastStepResult.SessionSummary.TrainingSessionId.IsEmpty()
|
||||
&& LastStepResult.SessionSummary.TrainingSessionId == CachedRunState.Session.TrainingSessionId;
|
||||
const bool bLastStepCompletedRun = bHasSessionScopedLastStep
|
||||
&& (LastStepResult.AttemptResolution.UpdatedSession.SessionState
|
||||
== EHyperTwistTrainingSessionState::Completed
|
||||
|| LastStepResult.AttemptResolution.UpdatedSession.SessionState
|
||||
== EHyperTwistTrainingSessionState::Aborted);
|
||||
const bool bHasNextCaseFromLastStep = bHasSessionScopedLastStep
|
||||
&& LastStepResult.AttemptResolution.NextCaseSelection.IsStructurallyValid();
|
||||
const bool bCanContinueCurrentRun = !bHasLiveAttemptTimer
|
||||
&& bHasRunnableCurrentCase
|
||||
&& !bLastStepCompletedRun;
|
||||
FString TransitionStatusLine;
|
||||
if (bLiveInspectionPhase)
|
||||
{
|
||||
TransitionStatusLine = FString::Printf(
|
||||
TEXT("Transition: inspection is live on case %s. Click Start Solve when ready, or cancel the timer."),
|
||||
*ActiveCaseId
|
||||
);
|
||||
}
|
||||
else if (bLiveSolvePhase)
|
||||
{
|
||||
TransitionStatusLine = FString::Printf(
|
||||
TEXT("Transition: solve is live on case %s. Capture splits if needed, then stop with the final result."),
|
||||
*ActiveCaseId
|
||||
);
|
||||
}
|
||||
else if (bLastStepCompletedRun)
|
||||
{
|
||||
TransitionStatusLine = FString::Printf(
|
||||
TEXT("Transition: run completed after case %s. Clear the finished run or launch the next queued coaching item."),
|
||||
LastStepResult.SessionSummary.LastCaseId.IsEmpty() ? TEXT("n/a") : *LastStepResult.SessionSummary.LastCaseId
|
||||
);
|
||||
}
|
||||
else if (bCanContinueCurrentRun)
|
||||
{
|
||||
const FHyperTwistTrainingCase& TransitionCase = CachedRunState.CurrentSelection.TrainingCase;
|
||||
const FString TransitionPrompt = TransitionCase.PromptLabel.IsEmpty()
|
||||
? ActiveCaseId
|
||||
: TransitionCase.PromptLabel;
|
||||
if (bHasNextCaseFromLastStep)
|
||||
{
|
||||
TransitionStatusLine = FString::Printf(
|
||||
TEXT("Transition: next case loaded after the last attempt. Continue the run to begin %s."),
|
||||
*TransitionPrompt
|
||||
);
|
||||
}
|
||||
else if (CachedRunSummary.AttemptCount > 0)
|
||||
{
|
||||
TransitionStatusLine = FString::Printf(
|
||||
TEXT("Transition: the current run is ready for another attempt on %s."),
|
||||
*TransitionPrompt
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
TransitionStatusLine = FString::Printf(
|
||||
TEXT("Transition: the run is staged on %s. Start the first timed attempt when ready."),
|
||||
*TransitionPrompt
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (bHasActiveRun)
|
||||
{
|
||||
TransitionStatusLine =
|
||||
TEXT("Transition: this run has no runnable current case. Complete, clear, or relaunch from coach guidance.");
|
||||
}
|
||||
else
|
||||
{
|
||||
TransitionStatusLine =
|
||||
TEXT("Transition: no run is active. Start recommended, follow-up, or queued coaching work from this screen.");
|
||||
}
|
||||
const FString ContinueRunLabel = bHasLiveAttemptTimer
|
||||
? (bLiveInspectionPhase ? TEXT("Start Solve") : TEXT("Attempt Active"))
|
||||
: (bHasNextCaseFromLastStep
|
||||
? TEXT("Continue Run")
|
||||
: (CachedRunSummary.AttemptCount > 0 ? TEXT("Start Next Attempt") : TEXT("Start First Attempt")));
|
||||
|
||||
if (HeadlineTextBlock != nullptr)
|
||||
{
|
||||
|
|
@ -1382,7 +1501,7 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
}
|
||||
if (LastAttemptTextBlock != nullptr)
|
||||
{
|
||||
if (!LastStepResult.SessionSummary.TrainingSessionId.IsEmpty())
|
||||
if (bHasSessionScopedLastStep)
|
||||
{
|
||||
LastAttemptTextBlock->SetText(FText::FromString(FString::Printf(
|
||||
TEXT("Last recorded attempt: case %s | completed at %s | session completed attempts %d"),
|
||||
|
|
@ -1484,6 +1603,14 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
));
|
||||
}
|
||||
}
|
||||
if (TransitionHeaderTextBlock != nullptr)
|
||||
{
|
||||
TransitionHeaderTextBlock->SetText(FText::FromString(TEXT("[Next Step]")));
|
||||
}
|
||||
if (TransitionStatusTextBlock != nullptr)
|
||||
{
|
||||
TransitionStatusTextBlock->SetText(FText::FromString(TransitionStatusLine));
|
||||
}
|
||||
if (AttemptControlHeaderTextBlock != nullptr)
|
||||
{
|
||||
AttemptControlHeaderTextBlock->SetText(FText::FromString(TEXT("[Attempt Controls]")));
|
||||
|
|
@ -1812,6 +1939,17 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
{
|
||||
CompleteRunButton->SetIsEnabled(bHasActiveRun && !bHasLiveAttemptTimer);
|
||||
}
|
||||
if (ContinueRunButtonLabel != nullptr)
|
||||
{
|
||||
ContinueRunButtonLabel->SetText(FText::FromString(ContinueRunLabel));
|
||||
}
|
||||
if (ContinueRunButton != nullptr)
|
||||
{
|
||||
ContinueRunButton->SetIsEnabled(
|
||||
(!bHasLiveAttemptTimer && bCanContinueCurrentRun)
|
||||
|| (bLiveInspectionPhase && bHasRunnableCurrentCase)
|
||||
);
|
||||
}
|
||||
if (ClearRunButtonLabel != nullptr)
|
||||
{
|
||||
ClearRunButtonLabel->SetText(FText::FromString(TEXT("Clear Run")));
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ void UHyperTwistTrainingPanelWidget::RefreshTrainingState()
|
|||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartSampleClassicTrainingRun()
|
||||
{
|
||||
LastStepResult = FHyperTwistTrainingRunStepResult();
|
||||
CachedRunState = UHyperTwistTrainingRuntimeLibrary::StartSampleClassicTrainingRun(
|
||||
this,
|
||||
DefaultUserId,
|
||||
|
|
@ -58,6 +59,7 @@ FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartTrainingRunFrom
|
|||
EHyperTwistTrainingDeliveryMode Mode
|
||||
)
|
||||
{
|
||||
LastStepResult = FHyperTwistTrainingRunStepResult();
|
||||
CachedRunState = UHyperTwistTrainingRuntimeLibrary::StartTrainingRunFromDeck(
|
||||
this,
|
||||
Deck,
|
||||
|
|
@ -118,6 +120,7 @@ FHyperTwistTrainingDeck UHyperTwistTrainingPanelWidget::BuildActiveCoachFollowUp
|
|||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachRecommendedRun(const int32 MaxCases)
|
||||
{
|
||||
LastStepResult = FHyperTwistTrainingRunStepResult();
|
||||
CachedRunState = UHyperTwistTrainingRuntimeLibrary::StartCoachRecommendedRun(
|
||||
this,
|
||||
DefaultSessionId + TEXT("_coach"),
|
||||
|
|
@ -129,6 +132,7 @@ FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachRecommende
|
|||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachFollowUpRun(const int32 MaxCases)
|
||||
{
|
||||
LastStepResult = FHyperTwistTrainingRunStepResult();
|
||||
CachedRunState = UHyperTwistTrainingRuntimeLibrary::StartCoachFollowUpRun(
|
||||
this,
|
||||
DefaultSessionId + TEXT("_follow_up"),
|
||||
|
|
@ -140,6 +144,7 @@ FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachFollowUpRu
|
|||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartNextQueuedCoachRun(const int32 MaxCases)
|
||||
{
|
||||
LastStepResult = FHyperTwistTrainingRunStepResult();
|
||||
CachedRunState = UHyperTwistTrainingRuntimeLibrary::StartNextQueuedCoachRun(
|
||||
this,
|
||||
DefaultSessionId + TEXT("_queue"),
|
||||
|
|
@ -154,6 +159,7 @@ FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachQueueEntry
|
|||
const int32 MaxCases
|
||||
)
|
||||
{
|
||||
LastStepResult = FHyperTwistTrainingRunStepResult();
|
||||
CachedRunState = UHyperTwistTrainingRuntimeLibrary::StartCoachQueueEntry(
|
||||
this,
|
||||
EntryId,
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ public:
|
|||
int32 TimeMs
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
bool ContinueCurrentRunFlow();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
bool StartLiveAttemptTimer();
|
||||
|
||||
|
|
@ -151,6 +154,12 @@ protected:
|
|||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> CurrentCaseNotationTextBlock = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> TransitionHeaderTextBlock = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> TransitionStatusTextBlock = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> AttemptControlHeaderTextBlock = nullptr;
|
||||
|
||||
|
|
@ -238,6 +247,12 @@ protected:
|
|||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> CompleteRunButtonLabel = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UButton> ContinueRunButton = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> ContinueRunButtonLabel = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UButton> ClearRunButton = nullptr;
|
||||
|
||||
|
|
@ -337,6 +352,9 @@ protected:
|
|||
UFUNCTION()
|
||||
void HandleCompleteRunClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void HandleContinueRunClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void HandleClearRunClicked();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue