Add guidance case review to coach dashboard
This commit is contained in:
parent
12c675d211
commit
93cc528fcd
2 changed files with 237 additions and 0 deletions
|
|
@ -306,6 +306,10 @@ bool UHyperTwistCoachDashboardWidget::SelectNextAttemptReview()
|
|||
FHyperTwistTrainingDeck UHyperTwistCoachDashboardWidget::PreviewRecommendedCoachDeck()
|
||||
{
|
||||
const FHyperTwistTrainingDeck Deck = BuildActiveCoachRecommendedDeck(DefaultCoachMaxCases);
|
||||
ActiveGuidancePreviewLane = Deck.IsStructurallyValid()
|
||||
? EHyperTwistCoachDashboardGuidancePreviewLane::Recommended
|
||||
: EHyperTwistCoachDashboardGuidancePreviewLane::None;
|
||||
SyncSelectedGuidancePreviewCase();
|
||||
UpdateDashboardPresentation();
|
||||
return Deck;
|
||||
}
|
||||
|
|
@ -313,10 +317,56 @@ FHyperTwistTrainingDeck UHyperTwistCoachDashboardWidget::PreviewRecommendedCoach
|
|||
FHyperTwistTrainingDeck UHyperTwistCoachDashboardWidget::PreviewFollowUpCoachDeck()
|
||||
{
|
||||
const FHyperTwistTrainingDeck Deck = BuildActiveCoachFollowUpDeck(DefaultCoachMaxCases);
|
||||
ActiveGuidancePreviewLane = Deck.IsStructurallyValid()
|
||||
? EHyperTwistCoachDashboardGuidancePreviewLane::FollowUp
|
||||
: EHyperTwistCoachDashboardGuidancePreviewLane::None;
|
||||
SyncSelectedGuidancePreviewCase();
|
||||
UpdateDashboardPresentation();
|
||||
return Deck;
|
||||
}
|
||||
|
||||
bool UHyperTwistCoachDashboardWidget::SelectPreviousGuidancePreviewCase()
|
||||
{
|
||||
const FHyperTwistTrainingDeck* Deck = GetActiveGuidancePreviewDeck();
|
||||
if (Deck == nullptr || Deck->Cases.Num() <= 0)
|
||||
{
|
||||
SelectedGuidancePreviewCaseIndex = INDEX_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SelectedGuidancePreviewCaseIndex == INDEX_NONE)
|
||||
{
|
||||
SyncSelectedGuidancePreviewCase();
|
||||
return SelectedGuidancePreviewCaseIndex != INDEX_NONE;
|
||||
}
|
||||
|
||||
SelectedGuidancePreviewCaseIndex =
|
||||
(SelectedGuidancePreviewCaseIndex - 1 + Deck->Cases.Num()) % Deck->Cases.Num();
|
||||
UpdateDashboardPresentation();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UHyperTwistCoachDashboardWidget::SelectNextGuidancePreviewCase()
|
||||
{
|
||||
const FHyperTwistTrainingDeck* Deck = GetActiveGuidancePreviewDeck();
|
||||
if (Deck == nullptr || Deck->Cases.Num() <= 0)
|
||||
{
|
||||
SelectedGuidancePreviewCaseIndex = INDEX_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SelectedGuidancePreviewCaseIndex == INDEX_NONE)
|
||||
{
|
||||
SyncSelectedGuidancePreviewCase();
|
||||
return SelectedGuidancePreviewCaseIndex != INDEX_NONE;
|
||||
}
|
||||
|
||||
SelectedGuidancePreviewCaseIndex =
|
||||
(SelectedGuidancePreviewCaseIndex + 1) % Deck->Cases.Num();
|
||||
UpdateDashboardPresentation();
|
||||
return true;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState UHyperTwistCoachDashboardWidget::RestartRetainedRunRecapDeck()
|
||||
{
|
||||
if (!RetainedRunRecapDeck.IsStructurallyValid())
|
||||
|
|
@ -654,6 +704,16 @@ void UHyperTwistCoachDashboardWidget::HandlePreviewFollowUpClicked()
|
|||
PreviewFollowUpCoachDeck();
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::HandlePreviousGuidanceCaseClicked()
|
||||
{
|
||||
SelectPreviousGuidancePreviewCase();
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::HandleNextGuidanceCaseClicked()
|
||||
{
|
||||
SelectNextGuidancePreviewCase();
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::HandleCompleteRunClicked()
|
||||
{
|
||||
CompleteActiveTrainingRun(false);
|
||||
|
|
@ -903,6 +963,12 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
|
|||
TEXT("CoachGuidanceReviewHeader"),
|
||||
2
|
||||
);
|
||||
GuidancePreviewSelectionTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
|
||||
WidgetTree,
|
||||
RootLayout,
|
||||
TEXT("CoachGuidancePreviewSelection"),
|
||||
2
|
||||
);
|
||||
RecommendedDeckPreviewTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
|
||||
WidgetTree,
|
||||
RootLayout,
|
||||
|
|
@ -915,6 +981,12 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
|
|||
TEXT("CoachFollowUpDeckPreview"),
|
||||
2
|
||||
);
|
||||
GuidancePreviewCaseDetailTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
|
||||
WidgetTree,
|
||||
RootLayout,
|
||||
TEXT("CoachGuidancePreviewCaseDetail"),
|
||||
2
|
||||
);
|
||||
UHorizontalBox* RunRecapActionRow = WidgetTree->ConstructWidget<UHorizontalBox>(
|
||||
UHorizontalBox::StaticClass(),
|
||||
TEXT("CoachDashboardRunRecapActions")
|
||||
|
|
@ -1024,6 +1096,28 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
|
|||
PreviewFollowUpLabelRaw
|
||||
);
|
||||
PreviewFollowUpButtonLabel = PreviewFollowUpLabelRaw;
|
||||
|
||||
UTextBlock* PreviousGuidanceCaseLabelRaw = nullptr;
|
||||
PreviousGuidanceCaseButton = HyperTwistCoachDashboardWidgetInternal::AddButton(
|
||||
WidgetTree,
|
||||
GuidancePreviewActionRow,
|
||||
TEXT("PreviousGuidanceCaseButton"),
|
||||
TEXT("PreviousGuidanceCaseButtonLabel"),
|
||||
TEXT("Prev Guidance Case"),
|
||||
PreviousGuidanceCaseLabelRaw
|
||||
);
|
||||
PreviousGuidanceCaseButtonLabel = PreviousGuidanceCaseLabelRaw;
|
||||
|
||||
UTextBlock* NextGuidanceCaseLabelRaw = nullptr;
|
||||
NextGuidanceCaseButton = HyperTwistCoachDashboardWidgetInternal::AddButton(
|
||||
WidgetTree,
|
||||
GuidancePreviewActionRow,
|
||||
TEXT("NextGuidanceCaseButton"),
|
||||
TEXT("NextGuidanceCaseButtonLabel"),
|
||||
TEXT("Next Guidance Case"),
|
||||
NextGuidanceCaseLabelRaw
|
||||
);
|
||||
NextGuidanceCaseButtonLabel = NextGuidanceCaseLabelRaw;
|
||||
}
|
||||
LastAttemptTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
|
||||
WidgetTree,
|
||||
|
|
@ -1562,6 +1656,14 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
|
|||
{
|
||||
PreviewFollowUpButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandlePreviewFollowUpClicked);
|
||||
}
|
||||
if (PreviousGuidanceCaseButton != nullptr)
|
||||
{
|
||||
PreviousGuidanceCaseButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandlePreviousGuidanceCaseClicked);
|
||||
}
|
||||
if (NextGuidanceCaseButton != nullptr)
|
||||
{
|
||||
NextGuidanceCaseButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleNextGuidanceCaseClicked);
|
||||
}
|
||||
if (CompleteRunButton != nullptr)
|
||||
{
|
||||
CompleteRunButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleCompleteRunClicked);
|
||||
|
|
@ -1730,6 +1832,35 @@ void UHyperTwistCoachDashboardWidget::SyncRetainedRunRecap()
|
|||
}
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::SyncSelectedGuidancePreviewCase()
|
||||
{
|
||||
const FHyperTwistTrainingDeck* Deck = GetActiveGuidancePreviewDeck();
|
||||
if (Deck == nullptr || Deck->Cases.Num() <= 0)
|
||||
{
|
||||
SelectedGuidancePreviewCaseIndex = INDEX_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (SelectedGuidancePreviewCaseIndex < 0
|
||||
|| SelectedGuidancePreviewCaseIndex >= Deck->Cases.Num())
|
||||
{
|
||||
SelectedGuidancePreviewCaseIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingDeck* UHyperTwistCoachDashboardWidget::GetActiveGuidancePreviewDeck() const
|
||||
{
|
||||
switch (ActiveGuidancePreviewLane)
|
||||
{
|
||||
case EHyperTwistCoachDashboardGuidancePreviewLane::Recommended:
|
||||
return CachedCoachRecommendedDeck.IsStructurallyValid() ? &CachedCoachRecommendedDeck : nullptr;
|
||||
case EHyperTwistCoachDashboardGuidancePreviewLane::FollowUp:
|
||||
return CachedCoachFollowUpDeck.IsStructurallyValid() ? &CachedCoachFollowUpDeck : nullptr;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
||||
{
|
||||
const bool bHasActiveRun = CachedRunState.Session.IsStructurallyValid()
|
||||
|
|
@ -2053,6 +2184,42 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
CachedCoachFollowUpBrief,
|
||||
TEXT("Follow-up guidance")
|
||||
);
|
||||
const FHyperTwistTrainingDeck* ActivePreviewDeck = GetActiveGuidancePreviewDeck();
|
||||
const FHyperTwistTrainingCase* SelectedGuidancePreviewCase =
|
||||
ActivePreviewDeck != nullptr
|
||||
&& SelectedGuidancePreviewCaseIndex >= 0
|
||||
&& SelectedGuidancePreviewCaseIndex < ActivePreviewDeck->Cases.Num()
|
||||
? &ActivePreviewDeck->Cases[SelectedGuidancePreviewCaseIndex]
|
||||
: nullptr;
|
||||
const FString ActivePreviewLaneLabel =
|
||||
ActiveGuidancePreviewLane == EHyperTwistCoachDashboardGuidancePreviewLane::Recommended
|
||||
? TEXT("recommended")
|
||||
: (ActiveGuidancePreviewLane == EHyperTwistCoachDashboardGuidancePreviewLane::FollowUp
|
||||
? TEXT("follow-up")
|
||||
: TEXT("none"));
|
||||
const FString GuidancePreviewSelectionLine =
|
||||
SelectedGuidancePreviewCase != nullptr && ActivePreviewDeck != nullptr
|
||||
? FString::Printf(
|
||||
TEXT("Active preview: %s | case %d/%d | deck %s"),
|
||||
*ActivePreviewLaneLabel,
|
||||
SelectedGuidancePreviewCaseIndex + 1,
|
||||
ActivePreviewDeck->Cases.Num(),
|
||||
ActivePreviewDeck->Title.IsEmpty() ? *ActivePreviewDeck->DeckId : *ActivePreviewDeck->Title
|
||||
)
|
||||
: FString::Printf(TEXT("Active preview: %s | build a coach deck preview to inspect specific cases"), *ActivePreviewLaneLabel);
|
||||
const FString GuidancePreviewCaseDetailLine =
|
||||
SelectedGuidancePreviewCase != nullptr
|
||||
? FString::Printf(
|
||||
TEXT("Preview case: %s | Prompt: %s | Kind: %s | Subset: %s | Target: %d ms | Scramble: %s | Canonical: %s"),
|
||||
SelectedGuidancePreviewCase->CaseId.IsEmpty() ? TEXT("n/a") : *SelectedGuidancePreviewCase->CaseId,
|
||||
SelectedGuidancePreviewCase->PromptLabel.IsEmpty() ? TEXT("n/a") : *SelectedGuidancePreviewCase->PromptLabel,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(SelectedGuidancePreviewCase->PromptKind),
|
||||
SelectedGuidancePreviewCase->SubsetId.IsEmpty() ? TEXT("n/a") : *SelectedGuidancePreviewCase->SubsetId,
|
||||
SelectedGuidancePreviewCase->TimeTargetMs,
|
||||
SelectedGuidancePreviewCase->ScrambleNotation.IsEmpty() ? TEXT("n/a") : *SelectedGuidancePreviewCase->ScrambleNotation,
|
||||
SelectedGuidancePreviewCase->CanonicalNotation.IsEmpty() ? TEXT("n/a") : *SelectedGuidancePreviewCase->CanonicalNotation
|
||||
)
|
||||
: TEXT("Preview case: none selected yet.");
|
||||
|
||||
if (HeadlineTextBlock != nullptr)
|
||||
{
|
||||
|
|
@ -2194,6 +2361,10 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
{
|
||||
GuidanceReviewHeaderTextBlock->SetText(FText::FromString(TEXT("[Guidance Review]")));
|
||||
}
|
||||
if (GuidancePreviewSelectionTextBlock != nullptr)
|
||||
{
|
||||
GuidancePreviewSelectionTextBlock->SetText(FText::FromString(GuidancePreviewSelectionLine));
|
||||
}
|
||||
if (RecommendedDeckPreviewTextBlock != nullptr)
|
||||
{
|
||||
RecommendedDeckPreviewTextBlock->SetText(FText::FromString(RecommendedDeckPreviewLine));
|
||||
|
|
@ -2202,6 +2373,10 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
{
|
||||
FollowUpDeckPreviewTextBlock->SetText(FText::FromString(FollowUpDeckPreviewLine));
|
||||
}
|
||||
if (GuidancePreviewCaseDetailTextBlock != nullptr)
|
||||
{
|
||||
GuidancePreviewCaseDetailTextBlock->SetText(FText::FromString(GuidancePreviewCaseDetailLine));
|
||||
}
|
||||
if (StartQueuedRunButtonLabel != nullptr)
|
||||
{
|
||||
StartQueuedRunButtonLabel->SetText(FText::FromString(QueuedRunLabel));
|
||||
|
|
@ -2254,6 +2429,26 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
&& CachedCoachPanelState.bHasFollowUpGuidance
|
||||
);
|
||||
}
|
||||
if (PreviousGuidanceCaseButtonLabel != nullptr)
|
||||
{
|
||||
PreviousGuidanceCaseButtonLabel->SetText(FText::FromString(TEXT("Prev Guidance Case")));
|
||||
}
|
||||
if (PreviousGuidanceCaseButton != nullptr)
|
||||
{
|
||||
PreviousGuidanceCaseButton->SetIsEnabled(
|
||||
ActivePreviewDeck != nullptr && ActivePreviewDeck->Cases.Num() > 1
|
||||
);
|
||||
}
|
||||
if (NextGuidanceCaseButtonLabel != nullptr)
|
||||
{
|
||||
NextGuidanceCaseButtonLabel->SetText(FText::FromString(TEXT("Next Guidance Case")));
|
||||
}
|
||||
if (NextGuidanceCaseButton != nullptr)
|
||||
{
|
||||
NextGuidanceCaseButton->SetIsEnabled(
|
||||
ActivePreviewDeck != nullptr && ActivePreviewDeck->Cases.Num() > 1
|
||||
);
|
||||
}
|
||||
if (LastAttemptTextBlock != nullptr)
|
||||
{
|
||||
if (ReviewedAttempt != nullptr)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,13 @@ enum class EHyperTwistCoachDashboardAttemptPhase : uint8
|
|||
Solving
|
||||
};
|
||||
|
||||
enum class EHyperTwistCoachDashboardGuidancePreviewLane : uint8
|
||||
{
|
||||
None,
|
||||
Recommended,
|
||||
FollowUp
|
||||
};
|
||||
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class UNREALHYPERTWIST_API UHyperTwistCoachDashboardWidget : public UHyperTwistTrainingPanelWidget
|
||||
{
|
||||
|
|
@ -103,6 +110,12 @@ public:
|
|||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
FHyperTwistTrainingDeck PreviewFollowUpCoachDeck();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
bool SelectPreviousGuidancePreviewCase();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
bool SelectNextGuidancePreviewCase();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
FHyperTwistTrainingRunState RestartRetainedRunRecapDeck();
|
||||
|
||||
|
|
@ -178,12 +191,18 @@ protected:
|
|||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> GuidanceReviewHeaderTextBlock = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> GuidancePreviewSelectionTextBlock = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> RecommendedDeckPreviewTextBlock = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> FollowUpDeckPreviewTextBlock = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> GuidancePreviewCaseDetailTextBlock = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UButton> RepeatRunButton = nullptr;
|
||||
|
||||
|
|
@ -226,6 +245,18 @@ protected:
|
|||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> PreviewFollowUpButtonLabel = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UButton> PreviousGuidanceCaseButton = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> PreviousGuidanceCaseButtonLabel = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UButton> NextGuidanceCaseButton = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> NextGuidanceCaseButtonLabel = nullptr;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextBlock> LastAttemptTextBlock = nullptr;
|
||||
|
||||
|
|
@ -472,6 +503,12 @@ protected:
|
|||
UFUNCTION()
|
||||
void HandlePreviewFollowUpClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void HandlePreviousGuidanceCaseClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void HandleNextGuidanceCaseClicked();
|
||||
|
||||
UFUNCTION()
|
||||
void HandleCompleteRunClicked();
|
||||
|
||||
|
|
@ -531,6 +568,7 @@ private:
|
|||
void SyncSelectedQueueEntry();
|
||||
void SyncSelectedAttempt();
|
||||
void SyncRetainedRunRecap();
|
||||
void SyncSelectedGuidancePreviewCase();
|
||||
void UpdateDashboardPresentation();
|
||||
void RefreshLiveAttemptClock();
|
||||
FString BuildDefaultDeferredUntilUtc() const;
|
||||
|
|
@ -540,6 +578,7 @@ private:
|
|||
void SetAttemptTimeText(int32 TimeMs);
|
||||
const FHyperTwistTrainingCoachSessionQueueStateEntry* FindSelectedQueueEntry() const;
|
||||
const FHyperTwistTrainingTimingPolicy* FindActiveTimingPolicy() const;
|
||||
const FHyperTwistTrainingDeck* GetActiveGuidancePreviewDeck() const;
|
||||
bool IsLiveAttemptInspectionPhase() const;
|
||||
int32 GetMaxManualSplitCaptureCount() const;
|
||||
const FHyperTwistTrainingSplitPhaseDefinition* FindNextSplitPhaseToCapture() const;
|
||||
|
|
@ -555,4 +594,7 @@ private:
|
|||
FString RetainedRunRecapUserId;
|
||||
FString RetainedRunRecapSessionId;
|
||||
EHyperTwistTrainingDeliveryMode RetainedRunRecapMode = EHyperTwistTrainingDeliveryMode::Timer;
|
||||
EHyperTwistCoachDashboardGuidancePreviewLane ActiveGuidancePreviewLane =
|
||||
EHyperTwistCoachDashboardGuidancePreviewLane::None;
|
||||
int32 SelectedGuidancePreviewCaseIndex = INDEX_NONE;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue