Add dashboard guidance decision history
This commit is contained in:
parent
d0ccdde06a
commit
214aeb42b7
2 changed files with 340 additions and 0 deletions
|
|
@ -143,6 +143,7 @@ void UHyperTwistCoachDashboardWidget::RefreshCoachDashboardView()
|
|||
SyncRetainedRunRecap();
|
||||
SyncSelectedQueueEntry();
|
||||
SyncSelectedAttempt();
|
||||
SyncSelectedGuidanceDecisionHistoryEntry();
|
||||
UpdateDashboardPresentation();
|
||||
}
|
||||
|
||||
|
|
@ -611,6 +612,18 @@ bool UHyperTwistCoachDashboardWidget::ApplyGuidanceOutcomeAction()
|
|||
true,
|
||||
DisplayedGuidanceComparisonSelectedCaseId
|
||||
);
|
||||
if (RunState.Session.IsStructurallyValid() && RunState.ActiveDeck.IsStructurallyValid())
|
||||
{
|
||||
RecordGuidanceOutcomeDecision(
|
||||
Action,
|
||||
EHyperTwistCoachDashboardOutcomeAction::RepeatSelectedCase,
|
||||
*DisplayedRunRecap,
|
||||
*DisplayedGuidanceComparisonBrief,
|
||||
*DisplayedGuidanceComparisonDeck,
|
||||
DisplayedGuidanceComparisonSelectedCaseId,
|
||||
bDisplayedGuidanceComparisonSingleCase
|
||||
);
|
||||
}
|
||||
SyncRetainedRunRecap();
|
||||
SyncSelectedQueueEntry();
|
||||
SyncSelectedAttempt();
|
||||
|
|
@ -641,6 +654,18 @@ bool UHyperTwistCoachDashboardWidget::ApplyGuidanceOutcomeAction()
|
|||
false,
|
||||
DisplayedGuidanceComparisonSelectedCaseId
|
||||
);
|
||||
if (RunState.Session.IsStructurallyValid() && RunState.ActiveDeck.IsStructurallyValid())
|
||||
{
|
||||
RecordGuidanceOutcomeDecision(
|
||||
Action,
|
||||
Action,
|
||||
*DisplayedRunRecap,
|
||||
*DisplayedGuidanceComparisonBrief,
|
||||
*DisplayedGuidanceComparisonDeck,
|
||||
DisplayedGuidanceComparisonSelectedCaseId,
|
||||
bDisplayedGuidanceComparisonSingleCase
|
||||
);
|
||||
}
|
||||
SyncRetainedRunRecap();
|
||||
SyncSelectedQueueEntry();
|
||||
SyncSelectedAttempt();
|
||||
|
|
@ -668,6 +693,18 @@ bool UHyperTwistCoachDashboardWidget::ApplyGuidanceOutcomeAction()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (RunState.Session.IsStructurallyValid() && RunState.ActiveDeck.IsStructurallyValid())
|
||||
{
|
||||
RecordGuidanceOutcomeDecision(
|
||||
Action,
|
||||
EHyperTwistCoachDashboardOutcomeAction::RedirectCoachGuidance,
|
||||
*DisplayedRunRecap,
|
||||
*DisplayedGuidanceComparisonBrief,
|
||||
*DisplayedGuidanceComparisonDeck,
|
||||
DisplayedGuidanceComparisonSelectedCaseId,
|
||||
bDisplayedGuidanceComparisonSingleCase
|
||||
);
|
||||
}
|
||||
SyncRetainedRunRecap();
|
||||
SyncSelectedQueueEntry();
|
||||
SyncSelectedAttempt();
|
||||
|
|
@ -680,6 +717,46 @@ bool UHyperTwistCoachDashboardWidget::ApplyGuidanceOutcomeAction()
|
|||
}
|
||||
}
|
||||
|
||||
bool UHyperTwistCoachDashboardWidget::SelectPreviousGuidanceDecisionHistoryEntry()
|
||||
{
|
||||
if (GuidanceDecisionHistoryEntries.Num() <= 0)
|
||||
{
|
||||
SelectedGuidanceDecisionIndex = INDEX_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SelectedGuidanceDecisionIndex == INDEX_NONE)
|
||||
{
|
||||
SyncSelectedGuidanceDecisionHistoryEntry();
|
||||
return SelectedGuidanceDecisionIndex != INDEX_NONE;
|
||||
}
|
||||
|
||||
SelectedGuidanceDecisionIndex =
|
||||
(SelectedGuidanceDecisionIndex - 1 + GuidanceDecisionHistoryEntries.Num()) % GuidanceDecisionHistoryEntries.Num();
|
||||
UpdateDashboardPresentation();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UHyperTwistCoachDashboardWidget::SelectNextGuidanceDecisionHistoryEntry()
|
||||
{
|
||||
if (GuidanceDecisionHistoryEntries.Num() <= 0)
|
||||
{
|
||||
SelectedGuidanceDecisionIndex = INDEX_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SelectedGuidanceDecisionIndex == INDEX_NONE)
|
||||
{
|
||||
SyncSelectedGuidanceDecisionHistoryEntry();
|
||||
return SelectedGuidanceDecisionIndex != INDEX_NONE;
|
||||
}
|
||||
|
||||
SelectedGuidanceDecisionIndex =
|
||||
(SelectedGuidanceDecisionIndex + 1) % GuidanceDecisionHistoryEntries.Num();
|
||||
UpdateDashboardPresentation();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UHyperTwistCoachDashboardWidget::StartLiveAttemptTimer()
|
||||
{
|
||||
if (!CachedRunState.Session.IsStructurallyValid() || !CachedRunState.CurrentSelection.TrainingCase.IsStructurallyValid())
|
||||
|
|
@ -950,6 +1027,16 @@ void UHyperTwistCoachDashboardWidget::HandleGuidanceOutcomeActionClicked()
|
|||
ApplyGuidanceOutcomeAction();
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::HandlePreviousGuidanceDecisionClicked()
|
||||
{
|
||||
SelectPreviousGuidanceDecisionHistoryEntry();
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::HandleNextGuidanceDecisionClicked()
|
||||
{
|
||||
SelectNextGuidanceDecisionHistoryEntry();
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::HandleClearRunClicked()
|
||||
{
|
||||
ClearActiveTrainingRun();
|
||||
|
|
@ -1203,6 +1290,24 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
|
|||
TEXT("CoachGuidanceOutcomeDetail"),
|
||||
8
|
||||
);
|
||||
GuidanceDecisionHistoryHeaderTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
|
||||
WidgetTree,
|
||||
RootLayout,
|
||||
TEXT("CoachGuidanceDecisionHistoryHeader"),
|
||||
2
|
||||
);
|
||||
GuidanceDecisionHistoryStatusTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
|
||||
WidgetTree,
|
||||
RootLayout,
|
||||
TEXT("CoachGuidanceDecisionHistoryStatus"),
|
||||
2
|
||||
);
|
||||
GuidanceDecisionHistoryDetailTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
|
||||
WidgetTree,
|
||||
RootLayout,
|
||||
TEXT("CoachGuidanceDecisionHistoryDetail"),
|
||||
8
|
||||
);
|
||||
CoachHandoffHeaderTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
|
||||
WidgetTree,
|
||||
RootLayout,
|
||||
|
|
@ -1296,6 +1401,28 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
|
|||
);
|
||||
GuidanceOutcomeActionButtonLabel = GuidanceOutcomeActionLabelRaw;
|
||||
|
||||
UTextBlock* PreviousGuidanceDecisionLabelRaw = nullptr;
|
||||
PreviousGuidanceDecisionButton = HyperTwistCoachDashboardWidgetInternal::AddButton(
|
||||
WidgetTree,
|
||||
RunRecapActionRow,
|
||||
TEXT("PreviousGuidanceDecisionButton"),
|
||||
TEXT("PreviousGuidanceDecisionButtonLabel"),
|
||||
TEXT("Prev Decision"),
|
||||
PreviousGuidanceDecisionLabelRaw
|
||||
);
|
||||
PreviousGuidanceDecisionButtonLabel = PreviousGuidanceDecisionLabelRaw;
|
||||
|
||||
UTextBlock* NextGuidanceDecisionLabelRaw = nullptr;
|
||||
NextGuidanceDecisionButton = HyperTwistCoachDashboardWidgetInternal::AddButton(
|
||||
WidgetTree,
|
||||
RunRecapActionRow,
|
||||
TEXT("NextGuidanceDecisionButton"),
|
||||
TEXT("NextGuidanceDecisionButtonLabel"),
|
||||
TEXT("Next Decision"),
|
||||
NextGuidanceDecisionLabelRaw
|
||||
);
|
||||
NextGuidanceDecisionButtonLabel = NextGuidanceDecisionLabelRaw;
|
||||
|
||||
UTextBlock* DismissRecapLabelRaw = nullptr;
|
||||
DismissRecapButton = HyperTwistCoachDashboardWidgetInternal::AddButton(
|
||||
WidgetTree,
|
||||
|
|
@ -1945,6 +2072,14 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
|
|||
{
|
||||
GuidanceOutcomeActionButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleGuidanceOutcomeActionClicked);
|
||||
}
|
||||
if (PreviousGuidanceDecisionButton != nullptr)
|
||||
{
|
||||
PreviousGuidanceDecisionButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandlePreviousGuidanceDecisionClicked);
|
||||
}
|
||||
if (NextGuidanceDecisionButton != nullptr)
|
||||
{
|
||||
NextGuidanceDecisionButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleNextGuidanceDecisionClicked);
|
||||
}
|
||||
if (DismissRecapButton != nullptr)
|
||||
{
|
||||
DismissRecapButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleDismissRecapClicked);
|
||||
|
|
@ -2181,6 +2316,21 @@ void UHyperTwistCoachDashboardWidget::SyncSelectedGuidancePreviewCase()
|
|||
}
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::SyncSelectedGuidanceDecisionHistoryEntry()
|
||||
{
|
||||
if (GuidanceDecisionHistoryEntries.Num() <= 0)
|
||||
{
|
||||
SelectedGuidanceDecisionIndex = INDEX_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectedGuidanceDecisionIndex < 0
|
||||
|| SelectedGuidanceDecisionIndex >= GuidanceDecisionHistoryEntries.Num())
|
||||
{
|
||||
SelectedGuidanceDecisionIndex = GuidanceDecisionHistoryEntries.Num() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingDeck* UHyperTwistCoachDashboardWidget::GetActiveGuidancePreviewDeck() const
|
||||
{
|
||||
switch (ActiveGuidancePreviewLane)
|
||||
|
|
@ -2427,6 +2577,54 @@ FHyperTwistTrainingDeck UHyperTwistCoachDashboardWidget::BuildGuidanceOutcomeSel
|
|||
return SingleCaseDeck;
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::RecordGuidanceOutcomeDecision(
|
||||
const EHyperTwistCoachDashboardOutcomeAction RecommendedAction,
|
||||
const EHyperTwistCoachDashboardOutcomeAction AppliedAction,
|
||||
const FHyperTwistTrainingSessionSummary& DisplayedRunRecap,
|
||||
const FHyperTwistCoachBrief& DisplayedGuidanceComparisonBrief,
|
||||
const FHyperTwistTrainingDeck& DisplayedGuidanceComparisonDeck,
|
||||
const FString& DisplayedGuidanceComparisonSelectedCaseId,
|
||||
const bool bDisplayedGuidanceComparisonSingleCase
|
||||
)
|
||||
{
|
||||
FHyperTwistCoachDashboardDecisionHistoryEntry Entry;
|
||||
Entry.RecordedAtUtc = FDateTime::UtcNow().ToIso8601();
|
||||
Entry.SourceSessionId = DisplayedRunRecap.TrainingSessionId;
|
||||
Entry.GuidanceLane = !ActiveGuidanceLaunchSessionId.IsEmpty()
|
||||
&& DisplayedRunRecap.TrainingSessionId == ActiveGuidanceLaunchSessionId
|
||||
? ActiveGuidanceLaunchLane
|
||||
: (!RetainedGuidanceComparisonSessionId.IsEmpty()
|
||||
&& DisplayedRunRecap.TrainingSessionId == RetainedGuidanceComparisonSessionId
|
||||
? RetainedGuidanceComparisonLane
|
||||
: EHyperTwistCoachDashboardGuidancePreviewLane::None);
|
||||
Entry.bSingleCaseScope = bDisplayedGuidanceComparisonSingleCase;
|
||||
Entry.SelectedCaseId = DisplayedGuidanceComparisonSelectedCaseId;
|
||||
Entry.BriefHeadline = DisplayedGuidanceComparisonBrief.Headline.IsEmpty()
|
||||
? (DisplayedGuidanceComparisonDeck.Title.IsEmpty()
|
||||
? DisplayedGuidanceComparisonDeck.DeckId
|
||||
: DisplayedGuidanceComparisonDeck.Title)
|
||||
: DisplayedGuidanceComparisonBrief.Headline;
|
||||
Entry.RecommendedAction = RecommendedAction;
|
||||
Entry.RecommendedActionLabel = BuildGuidanceOutcomeActionLabel(RecommendedAction);
|
||||
Entry.AppliedAction = AppliedAction;
|
||||
Entry.AppliedActionLabel = BuildGuidanceOutcomeActionLabel(AppliedAction);
|
||||
Entry.SuccessRate = DisplayedRunRecap.SuccessRate;
|
||||
Entry.CompletedAttemptCount = DisplayedRunRecap.CompletedAttemptCount;
|
||||
Entry.TotalMistakes = DisplayedRunRecap.TotalMistakes;
|
||||
|
||||
if (Entry.IsStructurallyValid())
|
||||
{
|
||||
GuidanceDecisionHistoryEntries.Add(Entry);
|
||||
constexpr int32 MaxRetainedDecisionHistoryEntries = 16;
|
||||
if (GuidanceDecisionHistoryEntries.Num() > MaxRetainedDecisionHistoryEntries)
|
||||
{
|
||||
const int32 ExcessCount = GuidanceDecisionHistoryEntries.Num() - MaxRetainedDecisionHistoryEntries;
|
||||
GuidanceDecisionHistoryEntries.RemoveAt(0, ExcessCount, EAllowShrinking::No);
|
||||
}
|
||||
SelectedGuidanceDecisionIndex = GuidanceDecisionHistoryEntries.Num() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
||||
{
|
||||
const bool bHasActiveRun = CachedRunState.Session.IsStructurallyValid()
|
||||
|
|
@ -3055,6 +3253,45 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
&& (GuidanceOutcomeAction != EHyperTwistCoachDashboardOutcomeAction::RedirectCoachGuidance
|
||||
|| bCanRedirectGuidanceOutcome);
|
||||
const FString GuidanceOutcomeActionLabel = BuildGuidanceOutcomeActionLabel(GuidanceOutcomeAction);
|
||||
const FHyperTwistCoachDashboardDecisionHistoryEntry* SelectedGuidanceDecisionEntry =
|
||||
SelectedGuidanceDecisionIndex >= 0
|
||||
&& SelectedGuidanceDecisionIndex < GuidanceDecisionHistoryEntries.Num()
|
||||
? &GuidanceDecisionHistoryEntries[SelectedGuidanceDecisionIndex]
|
||||
: nullptr;
|
||||
const FString GuidanceDecisionLaneLabel =
|
||||
SelectedGuidanceDecisionEntry != nullptr
|
||||
? (SelectedGuidanceDecisionEntry->GuidanceLane == EHyperTwistCoachDashboardGuidancePreviewLane::Recommended
|
||||
? TEXT("recommended")
|
||||
: (SelectedGuidanceDecisionEntry->GuidanceLane == EHyperTwistCoachDashboardGuidancePreviewLane::FollowUp
|
||||
? TEXT("follow-up")
|
||||
: TEXT("none")))
|
||||
: TEXT("none");
|
||||
const FString GuidanceDecisionHistoryStatusLine =
|
||||
SelectedGuidanceDecisionEntry != nullptr
|
||||
? FString::Printf(
|
||||
TEXT("Decision history: %d entries | selected %d/%d | Lane: %s | Scope: %s | Recorded: %s"),
|
||||
GuidanceDecisionHistoryEntries.Num(),
|
||||
SelectedGuidanceDecisionIndex + 1,
|
||||
GuidanceDecisionHistoryEntries.Num(),
|
||||
*GuidanceDecisionLaneLabel,
|
||||
SelectedGuidanceDecisionEntry->bSingleCaseScope ? TEXT("selected case") : TEXT("preview deck"),
|
||||
*SelectedGuidanceDecisionEntry->RecordedAtUtc
|
||||
)
|
||||
: TEXT("Decision history: no applied guidance-outcome decisions recorded yet.");
|
||||
const FString GuidanceDecisionHistoryDetailLine =
|
||||
SelectedGuidanceDecisionEntry != nullptr
|
||||
? FString::Printf(
|
||||
TEXT("Session: %s | Brief: %s | Recommended: %s | Applied: %s | Selected case: %s | Success rate: %.2f | Completed attempts: %d | Mistakes: %d"),
|
||||
*SelectedGuidanceDecisionEntry->SourceSessionId,
|
||||
SelectedGuidanceDecisionEntry->BriefHeadline.IsEmpty() ? TEXT("n/a") : *SelectedGuidanceDecisionEntry->BriefHeadline,
|
||||
*SelectedGuidanceDecisionEntry->RecommendedActionLabel,
|
||||
*SelectedGuidanceDecisionEntry->AppliedActionLabel,
|
||||
SelectedGuidanceDecisionEntry->SelectedCaseId.IsEmpty() ? TEXT("n/a") : *SelectedGuidanceDecisionEntry->SelectedCaseId,
|
||||
SelectedGuidanceDecisionEntry->SuccessRate,
|
||||
SelectedGuidanceDecisionEntry->CompletedAttemptCount,
|
||||
SelectedGuidanceDecisionEntry->TotalMistakes
|
||||
)
|
||||
: TEXT("Decision detail: apply a guidance outcome from the dashboard to retain the authored choice history.");
|
||||
const bool bCanStartPreviewDeck =
|
||||
!bHasLiveAttemptTimer && !bHasActiveRun && ActivePreviewDeck != nullptr && ActivePreviewDeck->IsStructurallyValid();
|
||||
const bool bCanStartPreviewCase = bCanStartPreviewDeck && SelectedGuidancePreviewCase != nullptr;
|
||||
|
|
@ -3203,6 +3440,34 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
{
|
||||
GuidanceOutcomeActionButton->SetIsEnabled(bCanApplyGuidanceOutcomeAction);
|
||||
}
|
||||
if (GuidanceDecisionHistoryHeaderTextBlock != nullptr)
|
||||
{
|
||||
GuidanceDecisionHistoryHeaderTextBlock->SetText(FText::FromString(TEXT("[Decision History]")));
|
||||
}
|
||||
if (GuidanceDecisionHistoryStatusTextBlock != nullptr)
|
||||
{
|
||||
GuidanceDecisionHistoryStatusTextBlock->SetText(FText::FromString(GuidanceDecisionHistoryStatusLine));
|
||||
}
|
||||
if (GuidanceDecisionHistoryDetailTextBlock != nullptr)
|
||||
{
|
||||
GuidanceDecisionHistoryDetailTextBlock->SetText(FText::FromString(GuidanceDecisionHistoryDetailLine));
|
||||
}
|
||||
if (PreviousGuidanceDecisionButtonLabel != nullptr)
|
||||
{
|
||||
PreviousGuidanceDecisionButtonLabel->SetText(FText::FromString(TEXT("Prev Decision")));
|
||||
}
|
||||
if (PreviousGuidanceDecisionButton != nullptr)
|
||||
{
|
||||
PreviousGuidanceDecisionButton->SetIsEnabled(GuidanceDecisionHistoryEntries.Num() > 1);
|
||||
}
|
||||
if (NextGuidanceDecisionButtonLabel != nullptr)
|
||||
{
|
||||
NextGuidanceDecisionButtonLabel->SetText(FText::FromString(TEXT("Next Decision")));
|
||||
}
|
||||
if (NextGuidanceDecisionButton != nullptr)
|
||||
{
|
||||
NextGuidanceDecisionButton->SetIsEnabled(GuidanceDecisionHistoryEntries.Num() > 1);
|
||||
}
|
||||
if (RepeatRunButtonLabel != nullptr)
|
||||
{
|
||||
RepeatRunButtonLabel->SetText(FText::FromString(TEXT("Repeat Run")));
|
||||
|
|
|
|||
|
|
@ -32,6 +32,34 @@ enum class EHyperTwistCoachDashboardOutcomeAction : uint8
|
|||
RedirectCoachGuidance
|
||||
};
|
||||
|
||||
struct FHyperTwistCoachDashboardDecisionHistoryEntry
|
||||
{
|
||||
FString RecordedAtUtc;
|
||||
FString SourceSessionId;
|
||||
EHyperTwistCoachDashboardGuidancePreviewLane GuidanceLane =
|
||||
EHyperTwistCoachDashboardGuidancePreviewLane::None;
|
||||
bool bSingleCaseScope = false;
|
||||
FString SelectedCaseId;
|
||||
FString BriefHeadline;
|
||||
FString RecommendedActionLabel;
|
||||
EHyperTwistCoachDashboardOutcomeAction RecommendedAction =
|
||||
EHyperTwistCoachDashboardOutcomeAction::None;
|
||||
FString AppliedActionLabel;
|
||||
EHyperTwistCoachDashboardOutcomeAction AppliedAction =
|
||||
EHyperTwistCoachDashboardOutcomeAction::None;
|
||||
float SuccessRate = 0.0f;
|
||||
int32 CompletedAttemptCount = 0;
|
||||
int32 TotalMistakes = 0;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !RecordedAtUtc.IsEmpty()
|
||||
&& !SourceSessionId.IsEmpty()
|
||||
&& RecommendedAction != EHyperTwistCoachDashboardOutcomeAction::None
|
||||
&& AppliedAction != EHyperTwistCoachDashboardOutcomeAction::None;
|
||||
}
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class UNREALHYPERTWIST_API UHyperTwistCoachDashboardWidget : public UHyperTwistTrainingPanelWidget
|
||||
{
|
||||
|
|
@ -71,6 +99,9 @@ public:
|
|||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
int32 SelectedAttemptIndex = INDEX_NONE;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
int32 SelectedGuidanceDecisionIndex = INDEX_NONE;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
bool bHasLiveAttemptTimer = false;
|
||||
|
||||
|
|
@ -149,6 +180,12 @@ public:
|
|||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
bool ApplyGuidanceOutcomeAction();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
bool SelectPreviousGuidanceDecisionHistoryEntry();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
bool SelectNextGuidanceDecisionHistoryEntry();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
bool StartLiveAttemptTimer();
|
||||
|
||||
|
|
@ -224,6 +261,27 @@ protected:
|
|||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> GuidanceOutcomeActionButtonLabel = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> GuidanceDecisionHistoryHeaderTextBlock = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> GuidanceDecisionHistoryStatusTextBlock = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> GuidanceDecisionHistoryDetailTextBlock = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UButton> PreviousGuidanceDecisionButton = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> PreviousGuidanceDecisionButtonLabel = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UButton> NextGuidanceDecisionButton = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> NextGuidanceDecisionButtonLabel = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> CoachHandoffHeaderTextBlock = nullptr;
|
||||
|
||||
|
|
@ -587,6 +645,12 @@ protected:
|
|||
UFUNCTION()
|
||||
void HandleGuidanceOutcomeActionClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void HandlePreviousGuidanceDecisionClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void HandleNextGuidanceDecisionClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void HandleClearRunClicked();
|
||||
|
||||
|
|
@ -641,6 +705,7 @@ private:
|
|||
void SyncSelectedAttempt();
|
||||
void SyncRetainedRunRecap();
|
||||
void SyncSelectedGuidancePreviewCase();
|
||||
void SyncSelectedGuidanceDecisionHistoryEntry();
|
||||
void UpdateDashboardPresentation();
|
||||
void RefreshLiveAttemptClock();
|
||||
FString BuildDefaultDeferredUntilUtc() const;
|
||||
|
|
@ -663,6 +728,15 @@ private:
|
|||
EHyperTwistCoachDashboardOutcomeAction DeriveGuidanceOutcomeAction() const;
|
||||
FString BuildGuidanceOutcomeActionLabel(EHyperTwistCoachDashboardOutcomeAction Action) const;
|
||||
FHyperTwistTrainingDeck BuildGuidanceOutcomeSelectedCaseDeck() const;
|
||||
void RecordGuidanceOutcomeDecision(
|
||||
EHyperTwistCoachDashboardOutcomeAction RecommendedAction,
|
||||
EHyperTwistCoachDashboardOutcomeAction AppliedAction,
|
||||
const FHyperTwistTrainingSessionSummary& DisplayedRunRecap,
|
||||
const FHyperTwistCoachBrief& DisplayedGuidanceComparisonBrief,
|
||||
const FHyperTwistTrainingDeck& DisplayedGuidanceComparisonDeck,
|
||||
const FString& DisplayedGuidanceComparisonSelectedCaseId,
|
||||
bool bDisplayedGuidanceComparisonSingleCase
|
||||
);
|
||||
void CaptureActiveGuidanceLaunchContext(
|
||||
const FString& SessionId,
|
||||
const FHyperTwistTrainingDeck& Deck,
|
||||
|
|
@ -699,6 +773,7 @@ private:
|
|||
FHyperTwistCoachBrief RetainedGuidanceComparisonBrief;
|
||||
FHyperTwistTrainingDeck RetainedGuidanceComparisonDeck;
|
||||
FString RetainedGuidanceComparisonSelectedCaseId;
|
||||
TArray<FHyperTwistCoachDashboardDecisionHistoryEntry> GuidanceDecisionHistoryEntries;
|
||||
EHyperTwistCoachDashboardGuidancePreviewLane ActiveGuidancePreviewLane =
|
||||
EHyperTwistCoachDashboardGuidancePreviewLane::None;
|
||||
int32 SelectedGuidancePreviewCaseIndex = INDEX_NONE;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue