Surface method drill follow-up on dashboard

This commit is contained in:
axiomlogicnexus 2026-04-29 02:29:23 +02:00
parent 45164a7790
commit ce4b46b156
8 changed files with 385 additions and 0 deletions

View file

@ -1952,6 +1952,15 @@ void UHyperTwistCoachDashboardWidget::HandleStartPreviewCaseClicked()
StartSelectedGuidancePreviewCaseRun();
}
void UHyperTwistCoachDashboardWidget::HandleStartMethodDrillFollowUpClicked()
{
StartActiveMethodDrillFollowUpRun(DefaultSessionId + TEXT("_method_drill_follow_up"));
SyncRetainedRunRecap();
SyncSelectedQueueEntry();
SyncSelectedAttempt();
UpdateDashboardPresentation();
}
void UHyperTwistCoachDashboardWidget::HandleCompleteRunClicked()
{
CompleteActiveTrainingRun(false);
@ -2414,6 +2423,46 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
TEXT("CoachGuidancePreviewCaseDetail"),
2
);
MethodDrillDiagnosticsHeaderTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
WidgetTree,
RootLayout,
TEXT("CoachMethodDrillDiagnosticsHeader"),
2
);
MethodDrillDiagnosticsStatusTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
WidgetTree,
RootLayout,
TEXT("CoachMethodDrillDiagnosticsStatus"),
2
);
MethodDrillDiagnosticsDetailTextBlock = HyperTwistCoachDashboardWidgetInternal::AddTextRow(
WidgetTree,
RootLayout,
TEXT("CoachMethodDrillDiagnosticsDetail"),
8
);
UHorizontalBox* MethodDrillActionRow = WidgetTree->ConstructWidget<UHorizontalBox>(
UHorizontalBox::StaticClass(),
TEXT("CoachDashboardMethodDrillActions")
);
if (MethodDrillActionRow != nullptr)
{
if (UVerticalBoxSlot* MethodDrillActionRowSlot = RootLayout->AddChildToVerticalBox(MethodDrillActionRow))
{
MethodDrillActionRowSlot->SetPadding(FMargin(0.0f, 4.0f, 0.0f, 0.0f));
}
UTextBlock* StartMethodDrillFollowUpLabelRaw = nullptr;
StartMethodDrillFollowUpButton = HyperTwistCoachDashboardWidgetInternal::AddButton(
WidgetTree,
MethodDrillActionRow,
TEXT("StartMethodDrillFollowUpButton"),
TEXT("StartMethodDrillFollowUpButtonLabel"),
TEXT("Launch Drill Follow-Up"),
StartMethodDrillFollowUpLabelRaw
);
StartMethodDrillFollowUpButtonLabel = StartMethodDrillFollowUpLabelRaw;
}
UHorizontalBox* RunRecapActionRow = WidgetTree->ConstructWidget<UHorizontalBox>(
UHorizontalBox::StaticClass(),
TEXT("CoachDashboardRunRecapActions")
@ -3408,6 +3457,13 @@ void UHyperTwistCoachDashboardWidget::EnsureDefaultDashboardBuilt()
{
StartPreviewCaseButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleStartPreviewCaseClicked);
}
if (StartMethodDrillFollowUpButton != nullptr)
{
StartMethodDrillFollowUpButton->OnClicked.AddDynamic(
this,
&UHyperTwistCoachDashboardWidget::HandleStartMethodDrillFollowUpClicked
);
}
if (CompleteRunButton != nullptr)
{
CompleteRunButton->OnClicked.AddDynamic(this, &UHyperTwistCoachDashboardWidget::HandleCompleteRunClicked);
@ -5086,6 +5142,158 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
: (bCanContinueCurrentRun
? (CachedRunSummary.AttemptCount > 0 ? TEXT("Start Next Attempt") : TEXT("Start First Attempt"))
: TransitionLaunchLabel));
const bool bHasMethodDrillRun = CachedMethodDrillRunState.IsStructurallyValid();
const bool bHasMethodDrillDiagnosticPacket = CachedMethodDrillDiagnosticPacket.IsStructurallyValid();
const bool bHasMethodDrillFollowUpTemplate = CachedMethodDrillFollowUpTemplate.IsStructurallyValid();
const bool bHasMethodDrillFollowUpDeck = CachedMethodDrillFollowUpDeck.IsStructurallyValid();
const bool bMethodDrillLifecycleClosed =
bHasMethodDrillRun
&& (CachedMethodDrillRunState.LifecycleState == EHyperTwistTrainingDrillLifecycleState::Completed
|| CachedMethodDrillRunState.LifecycleState == EHyperTwistTrainingDrillLifecycleState::Aborted);
const bool bCanLaunchMethodDrillFollowUp =
!bHasLiveAttemptTimer
&& !bHasActiveRun
&& bMethodDrillLifecycleClosed
&& bHasMethodDrillDiagnosticPacket
&& bHasMethodDrillFollowUpTemplate
&& bHasMethodDrillFollowUpDeck;
const auto BuildCaseIdPreview = [](const TArray<FString>& CaseIds) -> FString
{
if (CaseIds.Num() <= 0)
{
return TEXT("none");
}
TArray<FString> PreviewCaseIds;
const int32 PreviewCount = FMath::Min(CaseIds.Num(), 3);
PreviewCaseIds.Reserve(PreviewCount + 1);
for (int32 CaseIndex = 0; CaseIndex < PreviewCount; ++CaseIndex)
{
PreviewCaseIds.Add(CaseIds[CaseIndex]);
}
if (CaseIds.Num() > PreviewCount)
{
PreviewCaseIds.Add(FString::Printf(TEXT("+%d more"), CaseIds.Num() - PreviewCount));
}
return FString::Join(PreviewCaseIds, TEXT(", "));
};
const FHyperTwistTrainingMethodDrillCaseComparisonPacket* PrimaryMethodDrillCase =
bHasMethodDrillDiagnosticPacket && CachedMethodDrillDiagnosticPacket.CasePackets.Num() > 0
? &CachedMethodDrillDiagnosticPacket.CasePackets[0]
: nullptr;
const FString MethodDrillFocusPreview = BuildCaseIdPreview(
CachedMethodDrillDiagnosticPacket.FocusCaseIds);
const FString MethodDrillTemplateLabel = bHasMethodDrillFollowUpTemplate
? (CachedMethodDrillFollowUpTemplate.Title.IsEmpty()
? CachedMethodDrillFollowUpTemplate.TemplateId
: CachedMethodDrillFollowUpTemplate.Title)
: TEXT("n/a");
FString MethodDrillDiagnosticsStatusLine;
if (!bHasMethodDrillDiagnosticPacket)
{
MethodDrillDiagnosticsStatusLine = bHasMethodDrillRun
? FString::Printf(
TEXT("Method drill: %s is active, but no diagnostic packet is available yet."),
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
CachedMethodDrillRunState.LifecycleState))
: TEXT("Method drill: no active drill diagnostics are available yet.");
}
else
{
MethodDrillDiagnosticsStatusLine = FString::Printf(
TEXT("Method drill: %s | %s | review %s | focus %d | pending %d | assisted %d | repeat burden %d | deferred %d | follow-up %s"),
CachedMethodDrillDiagnosticPacket.StageLabel.IsEmpty()
? (CachedMethodDrillDiagnosticPacket.DrillId.IsEmpty()
? TEXT("drill")
: *CachedMethodDrillDiagnosticPacket.DrillId)
: *CachedMethodDrillDiagnosticPacket.StageLabel,
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
CachedMethodDrillDiagnosticPacket.DiagnosticState),
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
CachedMethodDrillDiagnosticPacket.RecommendedReviewGrade),
CachedMethodDrillDiagnosticPacket.FocusCaseIds.Num(),
CachedMethodDrillDiagnosticPacket.PendingCaseCount,
CachedMethodDrillDiagnosticPacket.AssistedCompletionCount,
CachedMethodDrillDiagnosticPacket.RepeatBurdenCaseCount,
CachedMethodDrillDiagnosticPacket.DeferredCaseCount,
bHasMethodDrillFollowUpTemplate ? TEXT("ready") : TEXT("not ready")
);
}
FString MethodDrillDiagnosticsDetailLine;
if (!bHasMethodDrillDiagnosticPacket)
{
MethodDrillDiagnosticsDetailLine =
TEXT("Method drill detail: a completed or resumed method-drill run will surface its owned diagnostic packet and follow-up template here.");
}
else
{
MethodDrillDiagnosticsDetailLine = FString::Printf(
TEXT("Lifecycle: %s | mode: %s | visibility: %s | boundary: %s | template: %s | kind: %s | suggested mode: %s | selection: %s | recommended %d | focus: %s%s%s"),
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
CachedMethodDrillDiagnosticPacket.LifecycleState),
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
CachedMethodDrillDiagnosticPacket.DrillMode),
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
CachedMethodDrillDiagnosticPacket.VisibilityPolicy),
CachedMethodDrillDiagnosticPacket.BoundaryReason.IsEmpty()
? TEXT("n/a")
: *CachedMethodDrillDiagnosticPacket.BoundaryReason,
*MethodDrillTemplateLabel,
bHasMethodDrillFollowUpTemplate
? *HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
CachedMethodDrillFollowUpTemplate.TemplateKind)
: TEXT("n/a"),
bHasMethodDrillFollowUpTemplate
? *HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
CachedMethodDrillFollowUpTemplate.SuggestedMode)
: TEXT("n/a"),
bHasMethodDrillFollowUpTemplate
? *HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
CachedMethodDrillFollowUpTemplate.SuggestedSelectionPolicy)
: TEXT("n/a"),
bHasMethodDrillFollowUpTemplate ? CachedMethodDrillFollowUpTemplate.RecommendedCaseCount : 0,
*MethodDrillFocusPreview,
PrimaryMethodDrillCase != nullptr ? TEXT(" || Top case: ") : TEXT(""),
PrimaryMethodDrillCase != nullptr
? *FString::Printf(
TEXT("%s [%s | grade %s | attempts %d | repeats %d | reveals %d]"),
*PrimaryMethodDrillCase->CaseId,
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
PrimaryMethodDrillCase->DiagnosticState),
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(
PrimaryMethodDrillCase->RecommendedReviewGrade),
PrimaryMethodDrillCase->AttemptCount,
PrimaryMethodDrillCase->RepeatCount,
PrimaryMethodDrillCase->RevealCount)
: TEXT("")
);
}
FString StartMethodDrillFollowUpLabel = TEXT("Launch Drill Follow-Up");
if (bHasLiveAttemptTimer)
{
StartMethodDrillFollowUpLabel = TEXT("Drill Follow-Up Busy");
}
else if (bHasActiveRun)
{
StartMethodDrillFollowUpLabel = TEXT("Clear Run For Drill Follow-Up");
}
else if (bHasMethodDrillRun && !bMethodDrillLifecycleClosed)
{
StartMethodDrillFollowUpLabel = TEXT("Finish Drill Before Follow-Up");
}
else if (bHasMethodDrillDiagnosticPacket && CachedMethodDrillDiagnosticPacket.bNeedsFollowUpTemplate
&& !bHasMethodDrillFollowUpTemplate)
{
StartMethodDrillFollowUpLabel = TEXT("Follow-Up Template Missing");
}
else if (bHasMethodDrillFollowUpTemplate && !bHasMethodDrillFollowUpDeck)
{
StartMethodDrillFollowUpLabel = TEXT("No Drill Follow-Up Deck");
}
else if (!bHasMethodDrillDiagnosticPacket)
{
StartMethodDrillFollowUpLabel = TEXT("No Drill Follow-Up");
}
const bool bHasCurrentRunRecap = bHasActiveRun
&& (CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Completed
|| CachedRunState.Session.SessionState == EHyperTwistTrainingSessionState::Aborted);
@ -6669,6 +6877,26 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
{
GuidancePreviewCaseDetailTextBlock->SetText(FText::FromString(GuidancePreviewCaseDetailLine));
}
if (MethodDrillDiagnosticsHeaderTextBlock != nullptr)
{
MethodDrillDiagnosticsHeaderTextBlock->SetText(FText::FromString(TEXT("[Method Drill Diagnostics]")));
}
if (MethodDrillDiagnosticsStatusTextBlock != nullptr)
{
MethodDrillDiagnosticsStatusTextBlock->SetText(FText::FromString(MethodDrillDiagnosticsStatusLine));
}
if (MethodDrillDiagnosticsDetailTextBlock != nullptr)
{
MethodDrillDiagnosticsDetailTextBlock->SetText(FText::FromString(MethodDrillDiagnosticsDetailLine));
}
if (StartMethodDrillFollowUpButtonLabel != nullptr)
{
StartMethodDrillFollowUpButtonLabel->SetText(FText::FromString(StartMethodDrillFollowUpLabel));
}
if (StartMethodDrillFollowUpButton != nullptr)
{
StartMethodDrillFollowUpButton->SetIsEnabled(bCanLaunchMethodDrillFollowUp);
}
if (StartQueuedRunButtonLabel != nullptr)
{
StartQueuedRunButtonLabel->SetText(FText::FromString(QueuedRunLabel));

View file

@ -17,10 +17,24 @@ bool UHyperTwistTrainingPanelWidget::HasActiveTrainingRun() const
return UHyperTwistTrainingRuntimeLibrary::HasActiveTrainingRun(const_cast<UHyperTwistTrainingPanelWidget*>(this));
}
bool UHyperTwistTrainingPanelWidget::HasActiveMethodDrillRun() const
{
return UHyperTwistTrainingRuntimeLibrary::HasActiveMethodDrillRun(
const_cast<UHyperTwistTrainingPanelWidget*>(this));
}
void UHyperTwistTrainingPanelWidget::RefreshTrainingState()
{
CachedRunState = UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingRunState(this);
CachedRunSummary = UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingRunSummary(this);
CachedMethodDrillRunState = UHyperTwistTrainingRuntimeLibrary::GetActiveMethodDrillRunState(this);
CachedMethodDrillSummary = UHyperTwistTrainingRuntimeLibrary::GetActiveMethodDrillSummary(this);
CachedMethodDrillDiagnosticPacket =
UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingMethodDrillDiagnosticPacket(this);
CachedMethodDrillFollowUpTemplate =
UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingMethodDrillFollowUpTemplate(this);
CachedMethodDrillFollowUpDeck =
UHyperTwistTrainingRuntimeLibrary::BuildActiveMethodDrillFollowUpDeck(this);
CachedCoachSignals = UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingCoachSignals(this);
CachedCoachBrief = UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingCoachBrief(this);
CachedCoachFollowUpBrief = UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingCoachFollowUpBrief(this);
@ -118,6 +132,14 @@ FHyperTwistTrainingDeck UHyperTwistTrainingPanelWidget::BuildActiveCoachFollowUp
return CachedCoachFollowUpDeck;
}
FHyperTwistTrainingDeck UHyperTwistTrainingPanelWidget::BuildActiveMethodDrillFollowUpDeck()
{
CachedMethodDrillFollowUpDeck =
UHyperTwistTrainingRuntimeLibrary::BuildActiveMethodDrillFollowUpDeck(this);
RefreshTrainingState();
return CachedMethodDrillFollowUpDeck;
}
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartCoachRecommendedRun(
const int32 MaxCases,
const FString& StartActionSourceLabel
@ -226,6 +248,17 @@ bool UHyperTwistTrainingPanelWidget::PromoteCoachQueueEntry(const FString& Entry
return bSucceeded;
}
FHyperTwistTrainingRunState UHyperTwistTrainingPanelWidget::StartActiveMethodDrillFollowUpRun(
const FString& SessionId
)
{
LastStepResult = FHyperTwistTrainingRunStepResult();
CachedRunState =
UHyperTwistTrainingRuntimeLibrary::StartActiveMethodDrillFollowUpRun(this, SessionId);
RefreshTrainingState();
return CachedRunState;
}
FHyperTwistTrainingRepositoryRoundTripVerification
UHyperTwistTrainingPanelWidget::VerifyTrainingRepositoryRoundTrip()
{

View file

@ -1054,6 +1054,18 @@ FHyperTwistTrainingDeck UHyperTwistTrainingRuntimeLibrary::BuildActiveCoachFollo
return FHyperTwistTrainingDeck();
}
FHyperTwistTrainingDeck UHyperTwistTrainingRuntimeLibrary::BuildActiveMethodDrillFollowUpDeck(
UObject* WorldContextObject
)
{
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
{
return TrainingSubsystem->BuildActiveMethodDrillFollowUpDeck();
}
return FHyperTwistTrainingDeck();
}
FHyperTwistTrainingRunState UHyperTwistTrainingRuntimeLibrary::StartTrainingRunFromTemplate(
UObject* WorldContextObject,
const FString& TemplateId,
@ -1069,6 +1081,19 @@ FHyperTwistTrainingRunState UHyperTwistTrainingRuntimeLibrary::StartTrainingRunF
return FHyperTwistTrainingRunState();
}
FHyperTwistTrainingRunState UHyperTwistTrainingRuntimeLibrary::StartActiveMethodDrillFollowUpRun(
UObject* WorldContextObject,
const FString& SessionId
)
{
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
{
return TrainingSubsystem->StartActiveMethodDrillFollowUpRun(SessionId);
}
return FHyperTwistTrainingRunState();
}
FHyperTwistTrainingRunState UHyperTwistTrainingRuntimeLibrary::StartRecommendedReviewRun(
UObject* WorldContextObject,
const FString& SessionId,

View file

@ -1555,6 +1555,21 @@ FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveCoachFollowUpDe
return FocusDeck;
}
FHyperTwistTrainingDeck UHyperTwistTrainingSubsystem::BuildActiveMethodDrillFollowUpDeck() const
{
if (!ActiveMethodDrillFollowUpTemplate.IsStructurallyValid())
{
return FHyperTwistTrainingDeck();
}
const FHyperTwistTrainingDeck MaterializedDeck =
UHyperTwistTrainingCatalogLibrary::MaterializeTrainingSessionTemplateDeck(
ActiveMethodDrillFollowUpTemplate,
UHyperTwistTrainingCatalogLibrary::MakePhase3TrainingCatalog()
);
return MaterializedDeck.IsStructurallyValid() ? MaterializedDeck : FHyperTwistTrainingDeck();
}
FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartTrainingRunFromTemplate(
const FString& TemplateId,
const FString& UserId,
@ -1594,6 +1609,33 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartTrainingRunFromTe
);
}
FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartActiveMethodDrillFollowUpRun(
const FString& SessionId
)
{
if (!ActiveMethodDrillRunState.IsStructurallyValid()
|| !ActiveMethodDrillFollowUpTemplate.IsStructurallyValid())
{
return FHyperTwistTrainingRunState();
}
const FHyperTwistTrainingDeck FollowUpDeck = BuildActiveMethodDrillFollowUpDeck();
if (!FollowUpDeck.IsStructurallyValid())
{
return FHyperTwistTrainingRunState();
}
const FString ResolvedSessionId = !SessionId.IsEmpty()
? SessionId
: FString::Printf(TEXT("method_drill_follow_up_%s"), *ActiveMethodDrillRunState.RunId);
return StartTrainingRunFromDeck(
FollowUpDeck,
ActiveMethodDrillRunState.UserId,
ResolvedSessionId,
ActiveMethodDrillFollowUpTemplate.SuggestedMode
);
}
FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartRecommendedReviewRun(
const FString& SessionId,
int32 MaxCases,

View file

@ -597,6 +597,21 @@ protected:
UPROPERTY(Transient)
TObjectPtr<UTextBlock> GuidancePreviewCaseDetailTextBlock = nullptr;
UPROPERTY(Transient)
TObjectPtr<UTextBlock> MethodDrillDiagnosticsHeaderTextBlock = nullptr;
UPROPERTY(Transient)
TObjectPtr<UTextBlock> MethodDrillDiagnosticsStatusTextBlock = nullptr;
UPROPERTY(Transient)
TObjectPtr<UTextBlock> MethodDrillDiagnosticsDetailTextBlock = nullptr;
UPROPERTY(Transient)
TObjectPtr<UButton> StartMethodDrillFollowUpButton = nullptr;
UPROPERTY(Transient)
TObjectPtr<UTextBlock> StartMethodDrillFollowUpButtonLabel = nullptr;
UPROPERTY(Transient)
TObjectPtr<UButton> RepeatRunButton = nullptr;
@ -999,6 +1014,9 @@ protected:
UFUNCTION()
void HandleStartPreviewCaseClicked();
UFUNCTION()
void HandleStartMethodDrillFollowUpClicked();
UFUNCTION()
void HandleCompleteRunClicked();

View file

@ -35,6 +35,21 @@ public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training")
FHyperTwistTrainingSessionSummary CachedRunSummary;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Drill")
FHyperTwistTrainingMethodDrillRunState CachedMethodDrillRunState;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Drill")
FHyperTwistTrainingMethodDrillSummary CachedMethodDrillSummary;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Drill")
FHyperTwistTrainingMethodDrillDiagnosticPacket CachedMethodDrillDiagnosticPacket;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Drill")
FHyperTwistTrainingSessionTemplate CachedMethodDrillFollowUpTemplate;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training|Drill")
FHyperTwistTrainingDeck CachedMethodDrillFollowUpDeck;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "HyperTwist|Training")
FHyperTwistTrainingRunStepResult LastStepResult;
@ -77,6 +92,9 @@ public:
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
bool HasActiveTrainingRun() const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
bool HasActiveMethodDrillRun() const;
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training")
void RefreshTrainingState();
@ -109,6 +127,9 @@ public:
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
FHyperTwistTrainingDeck BuildActiveCoachFollowUpDeck(int32 MaxCases);
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
FHyperTwistTrainingDeck BuildActiveMethodDrillFollowUpDeck();
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
FHyperTwistTrainingRunState StartCoachRecommendedRun(
int32 MaxCases,
@ -151,6 +172,9 @@ public:
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach")
bool PromoteCoachQueueEntry(const FString& EntryId);
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
FHyperTwistTrainingRunState StartActiveMethodDrillFollowUpRun(const FString& SessionId);
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training")
FHyperTwistTrainingRepositoryRoundTripVerification VerifyTrainingRepositoryRoundTrip();
};

View file

@ -426,6 +426,9 @@ public:
int32 MaxCases
);
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
static FHyperTwistTrainingDeck BuildActiveMethodDrillFollowUpDeck(UObject* WorldContextObject);
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
static FHyperTwistTrainingRunState StartTrainingRunFromTemplate(
UObject* WorldContextObject,
@ -434,6 +437,12 @@ public:
const FString& SessionId
);
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
static FHyperTwistTrainingRunState StartActiveMethodDrillFollowUpRun(
UObject* WorldContextObject,
const FString& SessionId
);
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
static FHyperTwistTrainingRunState StartRecommendedReviewRun(
UObject* WorldContextObject,

View file

@ -341,6 +341,9 @@ public:
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach")
FHyperTwistTrainingDeck BuildActiveCoachFollowUpDeck(int32 MaxCases) const;
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
FHyperTwistTrainingDeck BuildActiveMethodDrillFollowUpDeck() const;
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training")
FHyperTwistTrainingRunState StartTrainingRunFromTemplate(
const FString& TemplateId,
@ -348,6 +351,9 @@ public:
const FString& SessionId
);
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
FHyperTwistTrainingRunState StartActiveMethodDrillFollowUpRun(const FString& SessionId);
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training")
FHyperTwistTrainingRunState StartRecommendedReviewRun(
const FString& SessionId,