Launch previewed guidance from dashboard

This commit is contained in:
axiomlogicnexus 2026-04-27 15:23:01 +02:00
parent 93cc528fcd
commit e6322c0088
2 changed files with 166 additions and 0 deletions

View file

@ -367,6 +367,62 @@ bool UHyperTwistCoachDashboardWidget::SelectNextGuidancePreviewCase()
return true;
}
FHyperTwistTrainingRunState UHyperTwistCoachDashboardWidget::StartActiveGuidancePreviewDeckRun()
{
const FHyperTwistTrainingDeck* Deck = GetActiveGuidancePreviewDeck();
if (Deck == nullptr || !Deck->IsStructurallyValid())
{
UpdateDashboardPresentation();
return FHyperTwistTrainingRunState();
}
const FString SessionSuffix =
ActiveGuidancePreviewLane == EHyperTwistCoachDashboardGuidancePreviewLane::Recommended
? TEXT("_preview_recommended")
: (ActiveGuidancePreviewLane == EHyperTwistCoachDashboardGuidancePreviewLane::FollowUp
? TEXT("_preview_follow_up")
: TEXT("_preview"));
const FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck(
*Deck,
DefaultUserId,
DefaultSessionId + SessionSuffix,
DefaultMode
);
SyncRetainedRunRecap();
SyncSelectedQueueEntry();
SyncSelectedAttempt();
UpdateDashboardPresentation();
return RunState;
}
FHyperTwistTrainingRunState UHyperTwistCoachDashboardWidget::StartSelectedGuidancePreviewCaseRun()
{
const FHyperTwistTrainingDeck Deck = BuildSelectedGuidancePreviewCaseDeck();
if (!Deck.IsStructurallyValid())
{
UpdateDashboardPresentation();
return FHyperTwistTrainingRunState();
}
const FString SessionSuffix =
ActiveGuidancePreviewLane == EHyperTwistCoachDashboardGuidancePreviewLane::Recommended
? TEXT("_preview_case_recommended")
: (ActiveGuidancePreviewLane == EHyperTwistCoachDashboardGuidancePreviewLane::FollowUp
? TEXT("_preview_case_follow_up")
: TEXT("_preview_case"));
const FHyperTwistTrainingRunState RunState = StartTrainingRunFromDeck(
Deck,
DefaultUserId,
DefaultSessionId + SessionSuffix,
DefaultMode
);
SyncRetainedRunRecap();
SyncSelectedQueueEntry();
SyncSelectedAttempt();
UpdateDashboardPresentation();
return RunState;
}
FHyperTwistTrainingRunState UHyperTwistCoachDashboardWidget::RestartRetainedRunRecapDeck()
{
if (!RetainedRunRecapDeck.IsStructurallyValid())
@ -714,6 +770,16 @@ void UHyperTwistCoachDashboardWidget::HandleNextGuidanceCaseClicked()
SelectNextGuidancePreviewCase();
}
void UHyperTwistCoachDashboardWidget::HandleStartPreviewDeckClicked()
{
StartActiveGuidancePreviewDeckRun();
}
void UHyperTwistCoachDashboardWidget::HandleStartPreviewCaseClicked()
{
StartSelectedGuidancePreviewCaseRun();
}
void UHyperTwistCoachDashboardWidget::HandleCompleteRunClicked()
{
CompleteActiveTrainingRun(false);
@ -1118,6 +1184,28 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
NextGuidanceCaseLabelRaw
);
NextGuidanceCaseButtonLabel = NextGuidanceCaseLabelRaw;
UTextBlock* StartPreviewDeckLabelRaw = nullptr;
StartPreviewDeckButton = HyperTwistCoachDashboardWidgetInternal::AddButton(
WidgetTree,
GuidancePreviewActionRow,
TEXT("StartPreviewDeckButton"),
TEXT("StartPreviewDeckButtonLabel"),
TEXT("Start Preview Deck"),
StartPreviewDeckLabelRaw
);
StartPreviewDeckButtonLabel = StartPreviewDeckLabelRaw;
UTextBlock* StartPreviewCaseLabelRaw = nullptr;
StartPreviewCaseButton = HyperTwistCoachDashboardWidgetInternal::AddButton(
WidgetTree,
GuidancePreviewActionRow,
TEXT("StartPreviewCaseButton"),
TEXT("StartPreviewCaseButtonLabel"),
TEXT("Start Selected Preview Case"),
StartPreviewCaseLabelRaw
);
StartPreviewCaseButtonLabel = StartPreviewCaseLabelRaw;
}
LastAttemptTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
WidgetTree,
@ -1664,6 +1752,14 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
{
NextGuidanceCaseButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleNextGuidanceCaseClicked);
}
if (StartPreviewDeckButton != nullptr)
{
StartPreviewDeckButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleStartPreviewDeckClicked);
}
if (StartPreviewCaseButton != nullptr)
{
StartPreviewCaseButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleStartPreviewCaseClicked);
}
if (CompleteRunButton != nullptr)
{
CompleteRunButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleCompleteRunClicked);
@ -1861,6 +1957,32 @@ const FHyperTwistTrainingDeck* UHyperTwistCoachDashboardWidget::GetActiveGuidanc
}
}
FHyperTwistTrainingDeck UHyperTwistCoachDashboardWidget::BuildSelectedGuidancePreviewCaseDeck() const
{
const FHyperTwistTrainingDeck* Deck = GetActiveGuidancePreviewDeck();
if (Deck == nullptr
|| !Deck->IsStructurallyValid()
|| SelectedGuidancePreviewCaseIndex < 0
|| SelectedGuidancePreviewCaseIndex >= Deck->Cases.Num())
{
return FHyperTwistTrainingDeck();
}
FHyperTwistTrainingDeck SingleCaseDeck = *Deck;
const FHyperTwistTrainingCase SelectedCase = Deck->Cases[SelectedGuidancePreviewCaseIndex];
SingleCaseDeck.Cases = { SelectedCase };
SingleCaseDeck.DeckId = FString::Printf(
TEXT("%s_case_%s"),
Deck->DeckId.IsEmpty() ? TEXT("preview") : *Deck->DeckId,
SelectedCase.CaseId.IsEmpty() ? TEXT("selected") : *SelectedCase.CaseId
);
SingleCaseDeck.Title = FString::Printf(
TEXT("%s (Selected Case)"),
Deck->Title.IsEmpty() ? TEXT("Preview Guidance") : *Deck->Title
);
return SingleCaseDeck;
}
void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
{
const bool bHasActiveRun = CachedRunState.Session.IsStructurallyValid()
@ -2220,6 +2342,9 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
SelectedGuidancePreviewCase->CanonicalNotation.IsEmpty() ? TEXT("n/a") : *SelectedGuidancePreviewCase->CanonicalNotation
)
: TEXT("Preview case: none selected yet.");
const bool bCanStartPreviewDeck =
!bHasLiveAttemptTimer && !bHasActiveRun && ActivePreviewDeck != nullptr && ActivePreviewDeck->IsStructurallyValid();
const bool bCanStartPreviewCase = bCanStartPreviewDeck && SelectedGuidancePreviewCase != nullptr;
if (HeadlineTextBlock != nullptr)
{
@ -2449,6 +2574,22 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
ActivePreviewDeck != nullptr && ActivePreviewDeck->Cases.Num() > 1
);
}
if (StartPreviewDeckButtonLabel != nullptr)
{
StartPreviewDeckButtonLabel->SetText(FText::FromString(TEXT("Start Preview Deck")));
}
if (StartPreviewDeckButton != nullptr)
{
StartPreviewDeckButton->SetIsEnabled(bCanStartPreviewDeck);
}
if (StartPreviewCaseButtonLabel != nullptr)
{
StartPreviewCaseButtonLabel->SetText(FText::FromString(TEXT("Start Selected Preview Case")));
}
if (StartPreviewCaseButton != nullptr)
{
StartPreviewCaseButton->SetIsEnabled(bCanStartPreviewCase);
}
if (LastAttemptTextBlock != nullptr)
{
if (ReviewedAttempt != nullptr)

View file

@ -116,6 +116,12 @@ public:
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
bool SelectNextGuidancePreviewCase();
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingRunState StartActiveGuidancePreviewDeckRun();
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingRunState StartSelectedGuidancePreviewCaseRun();
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
FHyperTwistTrainingRunState RestartRetainedRunRecapDeck();
@ -257,6 +263,18 @@ protected:
UPROPERTY(Transient)
TObjectPtr<UTextBlock> NextGuidanceCaseButtonLabel = nullptr;
UPROPERTY(Transient)
TObjectPtr<UButton> StartPreviewDeckButton = nullptr;
UPROPERTY(Transient)
TObjectPtr<UTextBlock> StartPreviewDeckButtonLabel = nullptr;
UPROPERTY(Transient)
TObjectPtr<UButton> StartPreviewCaseButton = nullptr;
UPROPERTY(Transient)
TObjectPtr<UTextBlock> StartPreviewCaseButtonLabel = nullptr;
UPROPERTY(Transient)
TObjectPtr<UTextBlock> LastAttemptTextBlock = nullptr;
@ -509,6 +527,12 @@ protected:
UFUNCTION()
void HandleNextGuidanceCaseClicked();
UFUNCTION()
void HandleStartPreviewDeckClicked();
UFUNCTION()
void HandleStartPreviewCaseClicked();
UFUNCTION()
void HandleCompleteRunClicked();
@ -579,6 +603,7 @@ private:
const FHyperTwistTrainingCoachSessionQueueStateEntry* FindSelectedQueueEntry() const;
const FHyperTwistTrainingTimingPolicy* FindActiveTimingPolicy() const;
const FHyperTwistTrainingDeck* GetActiveGuidancePreviewDeck() const;
FHyperTwistTrainingDeck BuildSelectedGuidancePreviewCaseDeck() const;
bool IsLiveAttemptInspectionPhase() const;
int32 GetMaxManualSplitCaptureCount() const;
const FHyperTwistTrainingSplitPhaseDefinition* FindNextSplitPhaseToCapture() const;