Expose dashboard active run, attempt timer, and current case surfaces
This commit is contained in:
parent
67ec0915cb
commit
b0d89dbca4
5 changed files with 692 additions and 104 deletions
|
|
@ -10725,6 +10725,278 @@ UHyperTwistCoachDashboardWidget::GetDisplayedRunActionLabelsInspectSurface() con
|
|||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachDashboardActiveRunStatusInspectSurface
|
||||
UHyperTwistCoachDashboardWidget::GetDisplayedActiveRunStatusInspectSurface() const
|
||||
{
|
||||
FHyperTwistTrainingCoachDashboardActiveRunStatusInspectSurface Surface;
|
||||
Surface.Headline = TEXT("Active run status");
|
||||
|
||||
const bool bHasActiveRun = CachedRunState.Session.IsStructurallyValid()
|
||||
&& CachedRunState.ActiveDeck.IsStructurallyValid();
|
||||
const FString ActiveDeckLabel = CachedRunState.ActiveDeck.Title.IsEmpty()
|
||||
? (CachedRunState.ActiveDeck.DeckId.IsEmpty() ? TEXT("n/a") : CachedRunState.ActiveDeck.DeckId)
|
||||
: CachedRunState.ActiveDeck.Title;
|
||||
const FString ActiveCaseId = CachedRunState.CurrentSelection.TrainingCase.CaseId.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: CachedRunState.CurrentSelection.TrainingCase.CaseId;
|
||||
|
||||
Surface.TrainingSessionId = CachedRunState.Session.TrainingSessionId.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: CachedRunState.Session.TrainingSessionId;
|
||||
Surface.SessionStateLabel =
|
||||
HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CachedRunState.Session.SessionState);
|
||||
Surface.DeliveryModeLabel =
|
||||
HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CachedRunState.Session.Mode);
|
||||
Surface.ActiveDeckLabel = ActiveDeckLabel;
|
||||
Surface.ActiveCaseId = ActiveCaseId;
|
||||
Surface.LastCaseId = CachedRunSummary.LastCaseId.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: CachedRunSummary.LastCaseId;
|
||||
Surface.RemainingCaseCount = CachedRunState.RemainingCaseIds.Num();
|
||||
Surface.AttemptCount = CachedRunSummary.AttemptCount;
|
||||
Surface.CompletedAttemptCount = CachedRunSummary.CompletedAttemptCount;
|
||||
Surface.SuccessCount = CachedRunSummary.SuccessCount;
|
||||
Surface.FailureCount = CachedRunSummary.FailureCount;
|
||||
Surface.TimeoutCount = CachedRunSummary.TimeoutCount;
|
||||
Surface.DNFCount = CachedRunSummary.DNFCount;
|
||||
Surface.BestTotalTimeMs = CachedRunSummary.BestTotalTimeMs;
|
||||
Surface.AverageTotalTimeMs = CachedRunSummary.AverageTotalTimeMs;
|
||||
Surface.bHasActiveRun = bHasActiveRun;
|
||||
|
||||
const bool bQueueRecoveryMemorySource =
|
||||
HyperTwistCoachDashboardWidgetInternal::IsQueueRecoveryMemorySource(
|
||||
CachedCoachPanelState.PreferredGuidanceSourceLabel);
|
||||
Surface.bClosedLoopIdleDashboard =
|
||||
IsCoachLoopActionabilityClosed()
|
||||
&& (
|
||||
bQueueRecoveryMemorySource
|
||||
|| !CachedCoachPanelState.PreferredGuidanceSourceLabel.IsEmpty()
|
||||
|| DisplayedCoachHandoffRecommendationKind != EHyperTwistTrainingCoachHandoffKind::None);
|
||||
|
||||
Surface.StatusLine = !DisplayedActiveRunStatusLine.IsEmpty()
|
||||
? DisplayedActiveRunStatusLine
|
||||
: (bHasActiveRun
|
||||
? FString::Printf(
|
||||
TEXT("Session: %s | State: %s | Deck: %s | Mode: %s | Current case: %s | Remaining: %d"),
|
||||
*Surface.TrainingSessionId,
|
||||
*Surface.SessionStateLabel,
|
||||
*Surface.ActiveDeckLabel,
|
||||
*Surface.DeliveryModeLabel,
|
||||
*Surface.ActiveCaseId,
|
||||
Surface.RemainingCaseCount)
|
||||
: (Surface.bClosedLoopIdleDashboard
|
||||
? TEXT("No active run. The coach-to-review loop is closed and idle.")
|
||||
: TEXT("No active run. Queue and coach guidance are ready for launch from this screen.")));
|
||||
Surface.SummaryLine = !DisplayedActiveRunSummaryLine.IsEmpty()
|
||||
? DisplayedActiveRunSummaryLine
|
||||
: FString::Printf(
|
||||
TEXT("Attempts: %d total | %d completed | Success %d | Failure %d | Timeout %d | DNF %d | Best %d ms | Avg %d ms | Last case: %s"),
|
||||
Surface.AttemptCount,
|
||||
Surface.CompletedAttemptCount,
|
||||
Surface.SuccessCount,
|
||||
Surface.FailureCount,
|
||||
Surface.TimeoutCount,
|
||||
Surface.DNFCount,
|
||||
Surface.BestTotalTimeMs,
|
||||
Surface.AverageTotalTimeMs,
|
||||
*Surface.LastCaseId);
|
||||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachDashboardActiveAttemptTimerStatusInspectSurface
|
||||
UHyperTwistCoachDashboardWidget::GetDisplayedActiveAttemptTimerStatusInspectSurface() const
|
||||
{
|
||||
FHyperTwistTrainingCoachDashboardActiveAttemptTimerStatusInspectSurface Surface;
|
||||
Surface.Headline = TEXT("Active attempt / timer status");
|
||||
|
||||
int32 ParsedAttemptOverrideMs = 0;
|
||||
const bool bHasParsedAttemptOverride = TryParseAttemptTimeOverride(ParsedAttemptOverrideMs);
|
||||
const int32 ResolvedSuccessTimeMs = ResolveAttemptTimeMs(EHyperTwistTrainingAttemptResult::Success);
|
||||
const int32 ResolvedFailureTimeMs = ResolveAttemptTimeMs(EHyperTwistTrainingAttemptResult::Failure);
|
||||
const int32 ResolvedTimeoutTimeMs = ResolveAttemptTimeMs(EHyperTwistTrainingAttemptResult::Timeout);
|
||||
const int32 ResolvedDnfTimeMs = ResolveAttemptTimeMs(EHyperTwistTrainingAttemptResult::DNF);
|
||||
const FHyperTwistTrainingTimingPolicy* TimingPolicy = FindActiveTimingPolicy();
|
||||
const bool bHasInspectionWindow = TimingPolicy != nullptr
|
||||
&& TimingPolicy->bInspectionEnabled
|
||||
&& TimingPolicy->InspectionDurationMs > 0;
|
||||
const int32 InspectionLimitMs = bHasInspectionWindow ? FMath::Max(TimingPolicy->InspectionDurationMs, 0) : 0;
|
||||
const bool bLiveInspectionPhase = IsLiveAttemptInspectionPhase();
|
||||
const bool bLiveSolvePhase = bHasLiveAttemptTimer
|
||||
&& LiveAttemptPhase == EHyperTwistCoachDashboardAttemptPhase::Solving;
|
||||
const bool bRunningSolveTimeHidden =
|
||||
TimingPolicy != nullptr && TimingPolicy->bHideRunningTime && bLiveSolvePhase;
|
||||
const FString RunningSolveLabel =
|
||||
bRunningSolveTimeHidden ? TEXT("hidden") : FString::FromInt(LiveAttemptSolveElapsedMs);
|
||||
const EHyperTwistTrainingPenalty LiveInspectionPenalty =
|
||||
(bHasInspectionWindow
|
||||
&& TimingPolicy->bInspectionPenaltiesEnabled
|
||||
&& LiveAttemptInspectionElapsedMs > InspectionLimitMs
|
||||
&& LiveAttemptInspectionElapsedMs <= InspectionLimitMs + 2000)
|
||||
? EHyperTwistTrainingPenalty::Plus2
|
||||
: ((bHasInspectionWindow
|
||||
&& TimingPolicy->bInspectionPenaltiesEnabled
|
||||
&& LiveAttemptInspectionElapsedMs > InspectionLimitMs + 2000)
|
||||
? EHyperTwistTrainingPenalty::DNF
|
||||
: EHyperTwistTrainingPenalty::None);
|
||||
const FString InspectionWindowLabel = bHasInspectionWindow
|
||||
? FString::Printf(TEXT("inspection target %d ms"), InspectionLimitMs)
|
||||
: TEXT("no inspection window");
|
||||
|
||||
Surface.AttemptOverrideMs = ParsedAttemptOverrideMs;
|
||||
Surface.TargetTimeMs = CachedRunState.CurrentSelection.TrainingCase.TimeTargetMs;
|
||||
Surface.AverageTotalTimeMs = CachedRunSummary.AverageTotalTimeMs;
|
||||
Surface.ResolvedSuccessTimeMs = ResolvedSuccessTimeMs;
|
||||
Surface.ResolvedFailureTimeMs = ResolvedFailureTimeMs;
|
||||
Surface.ResolvedTimeoutTimeMs = ResolvedTimeoutTimeMs;
|
||||
Surface.ResolvedDnfTimeMs = ResolvedDnfTimeMs;
|
||||
Surface.InspectionLimitMs = InspectionLimitMs;
|
||||
Surface.InspectionElapsedMs = LiveAttemptInspectionElapsedMs;
|
||||
Surface.SolveElapsedMs = LiveAttemptSolveElapsedMs;
|
||||
Surface.DisplayedElapsedMs = LiveAttemptDisplayedMs;
|
||||
Surface.TimerPhaseLabel = bLiveInspectionPhase
|
||||
? TEXT("inspection")
|
||||
: (bLiveSolvePhase ? TEXT("solving") : TEXT("idle"));
|
||||
Surface.RunningSolveLabel = RunningSolveLabel;
|
||||
Surface.InspectionWindowLabel = InspectionWindowLabel;
|
||||
Surface.PendingPenaltyLabel =
|
||||
HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(LiveInspectionPenalty);
|
||||
Surface.bHasParsedAttemptOverride = bHasParsedAttemptOverride;
|
||||
Surface.bHasLiveAttemptTimer = bHasLiveAttemptTimer;
|
||||
Surface.bLiveInspectionPhase = bLiveInspectionPhase;
|
||||
Surface.bLiveSolvePhase = bLiveSolvePhase;
|
||||
Surface.bHasInspectionWindow = bHasInspectionWindow;
|
||||
Surface.bRunningSolveTimeHidden = bRunningSolveTimeHidden;
|
||||
|
||||
Surface.AttemptInputLine = !DisplayedAttemptInputStatusLine.IsEmpty()
|
||||
? DisplayedAttemptInputStatusLine
|
||||
: FString::Printf(
|
||||
TEXT("Attempt ms input: %s | Target %d | Avg %d | Success %d | Failure %d | Timeout %d | DNF %d"),
|
||||
bHasParsedAttemptOverride ? *FString::FromInt(ParsedAttemptOverrideMs) : TEXT("auto"),
|
||||
Surface.TargetTimeMs,
|
||||
Surface.AverageTotalTimeMs,
|
||||
Surface.ResolvedSuccessTimeMs,
|
||||
Surface.ResolvedFailureTimeMs,
|
||||
Surface.ResolvedTimeoutTimeMs,
|
||||
Surface.ResolvedDnfTimeMs);
|
||||
Surface.TimerStatusLine = !DisplayedTimerStatusLine.IsEmpty()
|
||||
? DisplayedTimerStatusLine
|
||||
: (bLiveInspectionPhase
|
||||
? FString::Printf(
|
||||
TEXT("Phase: inspection | elapsed %d ms | remaining %d ms | pending penalty: %s | click Start Solve when ready"),
|
||||
Surface.InspectionElapsedMs,
|
||||
bHasInspectionWindow ? FMath::Max(InspectionLimitMs - LiveAttemptInspectionElapsedMs, 0) : 0,
|
||||
*Surface.PendingPenaltyLabel)
|
||||
: (bLiveSolvePhase
|
||||
? FString::Printf(
|
||||
TEXT("Phase: solving | inspection %d ms | solve %s ms | finish with Success / Failure / Timeout / DNF"),
|
||||
Surface.InspectionElapsedMs,
|
||||
*Surface.RunningSolveLabel)
|
||||
: FString::Printf(
|
||||
TEXT("Timer idle | %s | start a live attempt for less-synthetic run entry"),
|
||||
*Surface.InspectionWindowLabel)));
|
||||
return Surface;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCoachDashboardCurrentCaseDeckStatusInspectSurface
|
||||
UHyperTwistCoachDashboardWidget::GetDisplayedCurrentCaseDeckStatusInspectSurface() const
|
||||
{
|
||||
FHyperTwistTrainingCoachDashboardCurrentCaseDeckStatusInspectSurface Surface;
|
||||
Surface.Headline = TEXT("Current case / deck status");
|
||||
|
||||
const bool bHasActiveRun = CachedRunState.Session.IsStructurallyValid()
|
||||
&& CachedRunState.ActiveDeck.IsStructurallyValid();
|
||||
const bool bHasRunnableCurrentCase =
|
||||
bHasActiveRun && CachedRunState.CurrentSelection.TrainingCase.IsStructurallyValid();
|
||||
const FHyperTwistTrainingCase& CurrentTrainingCase = CachedRunState.CurrentSelection.TrainingCase;
|
||||
const FString ActiveDeckLabel = CachedRunState.ActiveDeck.Title.IsEmpty()
|
||||
? (CachedRunState.ActiveDeck.DeckId.IsEmpty() ? TEXT("n/a") : CachedRunState.ActiveDeck.DeckId)
|
||||
: CachedRunState.ActiveDeck.Title;
|
||||
const FString ActiveCaseId = CurrentTrainingCase.CaseId.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: CurrentTrainingCase.CaseId;
|
||||
const FString TagLine = CurrentTrainingCase.Tags.Num() > 0
|
||||
? FString::Join(CurrentTrainingCase.Tags, TEXT(", "))
|
||||
: TEXT("n/a");
|
||||
|
||||
Surface.ActiveDeckLabel = ActiveDeckLabel;
|
||||
Surface.ActiveDeckId = CachedRunState.ActiveDeck.DeckId.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: CachedRunState.ActiveDeck.DeckId;
|
||||
Surface.DeliveryModeLabel =
|
||||
HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CachedRunState.Session.Mode);
|
||||
Surface.ActiveCaseId = ActiveCaseId;
|
||||
Surface.PromptLabel = CurrentTrainingCase.PromptLabel.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: CurrentTrainingCase.PromptLabel;
|
||||
Surface.PromptKindLabel =
|
||||
HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CurrentTrainingCase.PromptKind);
|
||||
Surface.SubsetId = CurrentTrainingCase.SubsetId.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: CurrentTrainingCase.SubsetId;
|
||||
Surface.ScrambleNotation = CurrentTrainingCase.ScrambleNotation.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: CurrentTrainingCase.ScrambleNotation;
|
||||
Surface.CanonicalNotation = CurrentTrainingCase.CanonicalNotation.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: CurrentTrainingCase.CanonicalNotation;
|
||||
Surface.TagLine = TagLine;
|
||||
Surface.TimeTargetMs = CurrentTrainingCase.TimeTargetMs;
|
||||
Surface.SelectionAttemptCount = CachedRunState.CurrentSelection.AttemptCount;
|
||||
Surface.SelectionSuccessCount = CachedRunState.CurrentSelection.SuccessCount;
|
||||
Surface.RemainingCaseCount = CachedRunState.RemainingCaseIds.Num();
|
||||
Surface.bHasActiveRun = bHasActiveRun;
|
||||
Surface.bHasRunnableCurrentCase = bHasRunnableCurrentCase;
|
||||
|
||||
const bool bQueueRecoveryMemorySource =
|
||||
HyperTwistCoachDashboardWidgetInternal::IsQueueRecoveryMemorySource(
|
||||
CachedCoachPanelState.PreferredGuidanceSourceLabel);
|
||||
Surface.bClosedLoopIdleDashboard =
|
||||
IsCoachLoopActionabilityClosed()
|
||||
&& (
|
||||
bQueueRecoveryMemorySource
|
||||
|| !CachedCoachPanelState.PreferredGuidanceSourceLabel.IsEmpty()
|
||||
|| DisplayedCoachHandoffRecommendationKind != EHyperTwistTrainingCoachHandoffKind::None);
|
||||
|
||||
Surface.StatusLine = !DisplayedActiveRunStatusLine.IsEmpty()
|
||||
? DisplayedActiveRunStatusLine
|
||||
: (bHasActiveRun
|
||||
? FString::Printf(
|
||||
TEXT("Session: %s | State: %s | Deck: %s | Mode: %s | Current case: %s | Remaining: %d"),
|
||||
CachedRunState.Session.TrainingSessionId.IsEmpty()
|
||||
? TEXT("n/a")
|
||||
: *CachedRunState.Session.TrainingSessionId,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CachedRunState.Session.SessionState),
|
||||
*Surface.ActiveDeckLabel,
|
||||
*Surface.DeliveryModeLabel,
|
||||
*Surface.ActiveCaseId,
|
||||
Surface.RemainingCaseCount)
|
||||
: (Surface.bClosedLoopIdleDashboard
|
||||
? TEXT("No active run. The coach-to-review loop is closed and idle.")
|
||||
: TEXT("No active run. Queue and coach guidance are ready for launch from this screen.")));
|
||||
Surface.PromptLine = !DisplayedCurrentCasePromptLine.IsEmpty()
|
||||
? DisplayedCurrentCasePromptLine
|
||||
: (bHasRunnableCurrentCase
|
||||
? FString::Printf(
|
||||
TEXT("Prompt: %s | Kind: %s | Subset: %s | Target: %d ms | Attempts on selection: %d | Successes on selection: %d"),
|
||||
*Surface.PromptLabel,
|
||||
*Surface.PromptKindLabel,
|
||||
*Surface.SubsetId,
|
||||
Surface.TimeTargetMs,
|
||||
Surface.SelectionAttemptCount,
|
||||
Surface.SelectionSuccessCount)
|
||||
: TEXT("Prompt: no active current case is loaded."));
|
||||
Surface.NotationLine = !DisplayedCurrentCaseNotationLine.IsEmpty()
|
||||
? DisplayedCurrentCaseNotationLine
|
||||
: (bHasRunnableCurrentCase
|
||||
? FString::Printf(
|
||||
TEXT("Scramble: %s\nCanonical: %s\nTags: %s"),
|
||||
*Surface.ScrambleNotation,
|
||||
*Surface.CanonicalNotation,
|
||||
*Surface.TagLine)
|
||||
: TEXT("Scramble / notation: unavailable until a run is active."));
|
||||
return Surface;
|
||||
}
|
||||
|
||||
bool UHyperTwistCoachDashboardWidget::SelectPreviousMethodDrillFollowUpHistoryEntry()
|
||||
{
|
||||
if (MethodDrillFollowUpHistoryEntries.Num() <= 0)
|
||||
|
|
@ -22095,37 +22367,39 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
{
|
||||
ActiveRunHeaderTextBlock->SetText(FText::FromString(TEXT("[Active Run]")));
|
||||
}
|
||||
const FString ActiveRunLine = bHasActiveRun
|
||||
? FString::Printf(
|
||||
TEXT("Session: %s | State: %s | Deck: %s | Mode: %s | Current case: %s | Remaining: %d"),
|
||||
*CachedRunState.Session.TrainingSessionId,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CachedRunState.Session.SessionState),
|
||||
*ActiveDeckLabel,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CachedRunState.Session.Mode),
|
||||
*ActiveCaseId,
|
||||
CachedRunState.RemainingCaseIds.Num()
|
||||
)
|
||||
: (bHasClosedLoopIdleCoachActionability
|
||||
? TEXT("No active run. The coach-to-review loop is closed and idle.")
|
||||
: TEXT("No active run. Queue and coach guidance are ready for launch from this screen."));
|
||||
DisplayedActiveRunStatusLine = ActiveRunLine;
|
||||
if (ActiveRunStatusTextBlock != nullptr)
|
||||
{
|
||||
const FString ActiveRunLine = bHasActiveRun
|
||||
? FString::Printf(
|
||||
TEXT("Session: %s | State: %s | Deck: %s | Mode: %s | Current case: %s | Remaining: %d"),
|
||||
*CachedRunState.Session.TrainingSessionId,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CachedRunState.Session.SessionState),
|
||||
*ActiveDeckLabel,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CachedRunState.Session.Mode),
|
||||
*ActiveCaseId,
|
||||
CachedRunState.RemainingCaseIds.Num()
|
||||
)
|
||||
: (bHasClosedLoopIdleCoachActionability
|
||||
? TEXT("No active run. The coach-to-review loop is closed and idle.")
|
||||
: TEXT("No active run. Queue and coach guidance are ready for launch from this screen."));
|
||||
ActiveRunStatusTextBlock->SetText(FText::FromString(ActiveRunLine));
|
||||
ActiveRunStatusTextBlock->SetText(FText::FromString(DisplayedActiveRunStatusLine));
|
||||
}
|
||||
DisplayedActiveRunSummaryLine = FString::Printf(
|
||||
TEXT("Attempts: %d total | %d completed | Success %d | Failure %d | Timeout %d | DNF %d | Best %d ms | Avg %d ms | Last case: %s"),
|
||||
CachedRunSummary.AttemptCount,
|
||||
CachedRunSummary.CompletedAttemptCount,
|
||||
CachedRunSummary.SuccessCount,
|
||||
CachedRunSummary.FailureCount,
|
||||
CachedRunSummary.TimeoutCount,
|
||||
CachedRunSummary.DNFCount,
|
||||
CachedRunSummary.BestTotalTimeMs,
|
||||
CachedRunSummary.AverageTotalTimeMs,
|
||||
CachedRunSummary.LastCaseId.IsEmpty() ? TEXT("n/a") : *CachedRunSummary.LastCaseId
|
||||
);
|
||||
if (ActiveRunSummaryTextBlock != nullptr)
|
||||
{
|
||||
ActiveRunSummaryTextBlock->SetText(FText::FromString(FString::Printf(
|
||||
TEXT("Attempts: %d total | %d completed | Success %d | Failure %d | Timeout %d | DNF %d | Best %d ms | Avg %d ms | Last case: %s"),
|
||||
CachedRunSummary.AttemptCount,
|
||||
CachedRunSummary.CompletedAttemptCount,
|
||||
CachedRunSummary.SuccessCount,
|
||||
CachedRunSummary.FailureCount,
|
||||
CachedRunSummary.TimeoutCount,
|
||||
CachedRunSummary.DNFCount,
|
||||
CachedRunSummary.BestTotalTimeMs,
|
||||
CachedRunSummary.AverageTotalTimeMs,
|
||||
CachedRunSummary.LastCaseId.IsEmpty() ? TEXT("n/a") : *CachedRunSummary.LastCaseId
|
||||
)));
|
||||
ActiveRunSummaryTextBlock->SetText(FText::FromString(DisplayedActiveRunSummaryLine));
|
||||
}
|
||||
if (RunRecapHeaderTextBlock != nullptr)
|
||||
{
|
||||
|
|
@ -22695,47 +22969,49 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
{
|
||||
CurrentCaseHeaderTextBlock->SetText(FText::FromString(TEXT("[Current Case]")));
|
||||
}
|
||||
FString CurrentCasePromptLine;
|
||||
if (bHasRunnableCurrentCase)
|
||||
{
|
||||
CurrentCasePromptLine = FString::Printf(
|
||||
TEXT("Prompt: %s | Kind: %s | Subset: %s | Target: %d ms | Attempts on selection: %d | Successes on selection: %d"),
|
||||
CurrentTrainingCase.PromptLabel.IsEmpty() ? TEXT("n/a") : *CurrentTrainingCase.PromptLabel,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CurrentTrainingCase.PromptKind),
|
||||
CurrentTrainingCase.SubsetId.IsEmpty() ? TEXT("n/a") : *CurrentTrainingCase.SubsetId,
|
||||
CurrentTrainingCase.TimeTargetMs,
|
||||
CachedRunState.CurrentSelection.AttemptCount,
|
||||
CachedRunState.CurrentSelection.SuccessCount
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentCasePromptLine = TEXT("Prompt: no active current case is loaded.");
|
||||
}
|
||||
DisplayedCurrentCasePromptLine = CurrentCasePromptLine;
|
||||
if (CurrentCasePromptTextBlock != nullptr)
|
||||
{
|
||||
if (bHasRunnableCurrentCase)
|
||||
{
|
||||
CurrentCasePromptTextBlock->SetText(FText::FromString(FString::Printf(
|
||||
TEXT("Prompt: %s | Kind: %s | Subset: %s | Target: %d ms | Attempts on selection: %d | Successes on selection: %d"),
|
||||
CurrentTrainingCase.PromptLabel.IsEmpty() ? TEXT("n/a") : *CurrentTrainingCase.PromptLabel,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(CurrentTrainingCase.PromptKind),
|
||||
CurrentTrainingCase.SubsetId.IsEmpty() ? TEXT("n/a") : *CurrentTrainingCase.SubsetId,
|
||||
CurrentTrainingCase.TimeTargetMs,
|
||||
CachedRunState.CurrentSelection.AttemptCount,
|
||||
CachedRunState.CurrentSelection.SuccessCount
|
||||
)));
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentCasePromptTextBlock->SetText(FText::FromString(
|
||||
TEXT("Prompt: no active current case is loaded.")
|
||||
));
|
||||
}
|
||||
CurrentCasePromptTextBlock->SetText(FText::FromString(DisplayedCurrentCasePromptLine));
|
||||
}
|
||||
FString CurrentCaseNotationLine;
|
||||
if (bHasRunnableCurrentCase)
|
||||
{
|
||||
const FString TagLine = CurrentTrainingCase.Tags.Num() > 0
|
||||
? FString::Join(CurrentTrainingCase.Tags, TEXT(", "))
|
||||
: TEXT("n/a");
|
||||
CurrentCaseNotationLine = FString::Printf(
|
||||
TEXT("Scramble: %s\nCanonical: %s\nTags: %s"),
|
||||
CurrentTrainingCase.ScrambleNotation.IsEmpty() ? TEXT("n/a") : *CurrentTrainingCase.ScrambleNotation,
|
||||
CurrentTrainingCase.CanonicalNotation.IsEmpty() ? TEXT("n/a") : *CurrentTrainingCase.CanonicalNotation,
|
||||
*TagLine
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentCaseNotationLine = TEXT("Scramble / notation: unavailable until a run is active.");
|
||||
}
|
||||
DisplayedCurrentCaseNotationLine = CurrentCaseNotationLine;
|
||||
if (CurrentCaseNotationTextBlock != nullptr)
|
||||
{
|
||||
if (bHasRunnableCurrentCase)
|
||||
{
|
||||
const FString TagLine = CurrentTrainingCase.Tags.Num() > 0
|
||||
? FString::Join(CurrentTrainingCase.Tags, TEXT(", "))
|
||||
: TEXT("n/a");
|
||||
CurrentCaseNotationTextBlock->SetText(FText::FromString(FString::Printf(
|
||||
TEXT("Scramble: %s\nCanonical: %s\nTags: %s"),
|
||||
CurrentTrainingCase.ScrambleNotation.IsEmpty() ? TEXT("n/a") : *CurrentTrainingCase.ScrambleNotation,
|
||||
CurrentTrainingCase.CanonicalNotation.IsEmpty() ? TEXT("n/a") : *CurrentTrainingCase.CanonicalNotation,
|
||||
*TagLine
|
||||
)));
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentCaseNotationTextBlock->SetText(FText::FromString(
|
||||
TEXT("Scramble / notation: unavailable until a run is active.")
|
||||
));
|
||||
}
|
||||
CurrentCaseNotationTextBlock->SetText(FText::FromString(DisplayedCurrentCaseNotationLine));
|
||||
}
|
||||
if (TransitionHeaderTextBlock != nullptr)
|
||||
{
|
||||
|
|
@ -22749,55 +23025,57 @@ void UHyperTwistCoachDashboardWidget::UpdateDashboardPresentation()
|
|||
{
|
||||
AttemptControlHeaderTextBlock->SetText(FText::FromString(TEXT("[Attempt Controls]")));
|
||||
}
|
||||
DisplayedAttemptInputStatusLine = FString::Printf(
|
||||
TEXT("Attempt ms input: %s | Target %d | Avg %d | Success %d | Failure %d | Timeout %d | DNF %d"),
|
||||
bHasParsedAttemptOverride ? *FString::FromInt(ParsedAttemptOverrideMs) : TEXT("auto"),
|
||||
CurrentTrainingCase.TimeTargetMs,
|
||||
CachedRunSummary.AverageTotalTimeMs,
|
||||
ResolvedSuccessTimeMs,
|
||||
ResolvedFailureTimeMs,
|
||||
ResolvedTimeoutTimeMs,
|
||||
ResolvedDnfTimeMs
|
||||
);
|
||||
if (AttemptInputStatusTextBlock != nullptr)
|
||||
{
|
||||
AttemptInputStatusTextBlock->SetText(FText::FromString(FString::Printf(
|
||||
TEXT("Attempt ms input: %s | Target %d | Avg %d | Success %d | Failure %d | Timeout %d | DNF %d"),
|
||||
bHasParsedAttemptOverride ? *FString::FromInt(ParsedAttemptOverrideMs) : TEXT("auto"),
|
||||
CurrentTrainingCase.TimeTargetMs,
|
||||
CachedRunSummary.AverageTotalTimeMs,
|
||||
ResolvedSuccessTimeMs,
|
||||
ResolvedFailureTimeMs,
|
||||
ResolvedTimeoutTimeMs,
|
||||
ResolvedDnfTimeMs
|
||||
)));
|
||||
AttemptInputStatusTextBlock->SetText(FText::FromString(DisplayedAttemptInputStatusLine));
|
||||
}
|
||||
if (TimerHeaderTextBlock != nullptr)
|
||||
{
|
||||
TimerHeaderTextBlock->SetText(FText::FromString(TEXT("[Live Timer]")));
|
||||
}
|
||||
if (bLiveInspectionPhase)
|
||||
{
|
||||
const int32 RemainingInspectionMs = bHasInspectionWindow
|
||||
? FMath::Max(InspectionLimitMs - LiveAttemptInspectionElapsedMs, 0)
|
||||
: 0;
|
||||
DisplayedTimerStatusLine = FString::Printf(
|
||||
TEXT("Phase: inspection | elapsed %d ms | remaining %d ms | pending penalty: %s | click Start Solve when ready"),
|
||||
LiveAttemptInspectionElapsedMs,
|
||||
RemainingInspectionMs,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(LiveInspectionPenalty)
|
||||
);
|
||||
}
|
||||
else if (bLiveSolvePhase)
|
||||
{
|
||||
DisplayedTimerStatusLine = FString::Printf(
|
||||
TEXT("Phase: solving | inspection %d ms | solve %s ms | finish with Success / Failure / Timeout / DNF"),
|
||||
LiveAttemptInspectionElapsedMs,
|
||||
*RunningSolveLabel
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
const FString InspectionLabel = bHasInspectionWindow
|
||||
? FString::Printf(TEXT("inspection target %d ms"), InspectionLimitMs)
|
||||
: TEXT("no inspection window");
|
||||
DisplayedTimerStatusLine = FString::Printf(
|
||||
TEXT("Timer idle | %s | start a live attempt for less-synthetic run entry"),
|
||||
*InspectionLabel
|
||||
);
|
||||
}
|
||||
if (TimerStatusTextBlock != nullptr)
|
||||
{
|
||||
if (bLiveInspectionPhase)
|
||||
{
|
||||
const int32 RemainingInspectionMs = bHasInspectionWindow
|
||||
? FMath::Max(InspectionLimitMs - LiveAttemptInspectionElapsedMs, 0)
|
||||
: 0;
|
||||
TimerStatusTextBlock->SetText(FText::FromString(FString::Printf(
|
||||
TEXT("Phase: inspection | elapsed %d ms | remaining %d ms | pending penalty: %s | click Start Solve when ready"),
|
||||
LiveAttemptInspectionElapsedMs,
|
||||
RemainingInspectionMs,
|
||||
*HyperTwistCoachDashboardWidgetInternal::EnumDisplayName(LiveInspectionPenalty)
|
||||
)));
|
||||
}
|
||||
else if (bLiveSolvePhase)
|
||||
{
|
||||
TimerStatusTextBlock->SetText(FText::FromString(FString::Printf(
|
||||
TEXT("Phase: solving | inspection %d ms | solve %s ms | finish with Success / Failure / Timeout / DNF"),
|
||||
LiveAttemptInspectionElapsedMs,
|
||||
*RunningSolveLabel
|
||||
)));
|
||||
}
|
||||
else
|
||||
{
|
||||
const FString InspectionLabel = bHasInspectionWindow
|
||||
? FString::Printf(TEXT("inspection target %d ms"), InspectionLimitMs)
|
||||
: TEXT("no inspection window");
|
||||
TimerStatusTextBlock->SetText(FText::FromString(FString::Printf(
|
||||
TEXT("Timer idle | %s | start a live attempt for less-synthetic run entry"),
|
||||
*InspectionLabel
|
||||
)));
|
||||
}
|
||||
TimerStatusTextBlock->SetText(FText::FromString(DisplayedTimerStatusLine));
|
||||
}
|
||||
if (SplitHeaderTextBlock != nullptr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -815,6 +815,18 @@ public:
|
|||
FHyperTwistTrainingCoachDashboardRunActionLabelsInspectSurface
|
||||
GetDisplayedRunActionLabelsInspectSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
FHyperTwistTrainingCoachDashboardActiveRunStatusInspectSurface
|
||||
GetDisplayedActiveRunStatusInspectSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
FHyperTwistTrainingCoachDashboardActiveAttemptTimerStatusInspectSurface
|
||||
GetDisplayedActiveAttemptTimerStatusInspectSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
FHyperTwistTrainingCoachDashboardCurrentCaseDeckStatusInspectSurface
|
||||
GetDisplayedCurrentCaseDeckStatusInspectSurface() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Coach|Dashboard")
|
||||
bool SelectPreviousMethodDrillFollowUpHistoryEntry();
|
||||
|
||||
|
|
@ -1856,6 +1868,12 @@ private:
|
|||
FString DisplayedCoachHandoffRecommendationDetailLine;
|
||||
FString DisplayedCoachHandoffStatusLine;
|
||||
FString DisplayedTransitionStatusLine;
|
||||
FString DisplayedActiveRunStatusLine;
|
||||
FString DisplayedActiveRunSummaryLine;
|
||||
FString DisplayedCurrentCasePromptLine;
|
||||
FString DisplayedCurrentCaseNotationLine;
|
||||
FString DisplayedAttemptInputStatusLine;
|
||||
FString DisplayedTimerStatusLine;
|
||||
FString DisplayedRecommendedDeckPreviewLine;
|
||||
FString DisplayedFollowUpDeckPreviewLine;
|
||||
FString DisplayedContinueRunLabel;
|
||||
|
|
|
|||
|
|
@ -10821,6 +10821,242 @@ struct FHyperTwistTrainingCoachDashboardHandoffRecommendationInspectSurface
|
|||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachDashboardActiveRunStatusInspectSurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Headline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SummaryLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TrainingSessionId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SessionStateLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DeliveryModeLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActiveDeckLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActiveCaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString LastCaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RemainingCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 AttemptCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CompletedAttemptCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 SuccessCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 FailureCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TimeoutCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DNFCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 BestTotalTimeMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 AverageTotalTimeMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasActiveRun = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bClosedLoopIdleDashboard = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !StatusLine.IsEmpty()
|
||||
|| !SummaryLine.IsEmpty()
|
||||
|| bHasActiveRun;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachDashboardActiveAttemptTimerStatusInspectSurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Headline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString AttemptInputLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TimerStatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TimerPhaseLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RunningSolveLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString InspectionWindowLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PendingPenaltyLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 AttemptOverrideMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TargetTimeMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 AverageTotalTimeMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ResolvedSuccessTimeMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ResolvedFailureTimeMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ResolvedTimeoutTimeMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ResolvedDnfTimeMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 InspectionLimitMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 InspectionElapsedMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 SolveElapsedMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DisplayedElapsedMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasParsedAttemptOverride = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasLiveAttemptTimer = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bLiveInspectionPhase = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bLiveSolvePhase = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasInspectionWindow = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bRunningSolveTimeHidden = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !AttemptInputLine.IsEmpty()
|
||||
|| !TimerStatusLine.IsEmpty()
|
||||
|| bHasLiveAttemptTimer;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachDashboardCurrentCaseDeckStatusInspectSurface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Headline;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StatusLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PromptLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString NotationLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActiveDeckLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActiveDeckId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DeliveryModeLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ActiveCaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PromptLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PromptKindLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SubsetId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ScrambleNotation;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CanonicalNotation;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString TagLine;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TimeTargetMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 SelectionAttemptCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 SelectionSuccessCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RemainingCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasActiveRun = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bHasRunnableCurrentCase = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bClosedLoopIdleDashboard = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !StatusLine.IsEmpty()
|
||||
|| !PromptLine.IsEmpty()
|
||||
|| !NotationLine.IsEmpty()
|
||||
|| bHasRunnableCurrentCase
|
||||
|| bHasActiveRun;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingCoachDashboardHandoffStatusInspectSurface
|
||||
{
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ Current correction call from the source-exposed audit and current execution refr
|
|||
- the latest landed bounded `Phase 4` packet closes the retained-idle comparison/outcome actionability gap at the end of the recognition-assisted coach-to-review continuity lane, and the final retained-surface confirmation pass now leaves that closure lane functionally complete
|
||||
- the retained idle widget surface now keeps retained comparison and decision history inspectable without continuing to advertise live launch or guidance-outcome actions once the coach-to-review loop has already collapsed to truthful closed-loop idle
|
||||
- the now-complete deliberate `UHyperTwistTrainingRuntimeLibrary` world-context consumer lane reaches through active generated-mode selector option owned-execution split-phase current-selection merged ordered roster phase-id lookup, normalized-order lookup, and evaluation-order lookup inspect surfaces, so gameplay/Blueprint callers can inspect one retained merged-roster row directly by phase id, normalized order, or evaluation order without scanning the merged roster array or re-running inspect derivation details directly
|
||||
- the latest landed bounded `Phase 4` packet stays on that same live `UHyperTwistCoachDashboardWidget` guidance-consumer lane and adds displayed coach handoff status, displayed transition status, and displayed continuation / queued / follow-up / recommended run action-label inspect surfaces over already-derived live dashboard transition and action-label state, so gameplay/Blueprint callers can inspect the current transition posture, coach handoff availability line, and surfaced launch/control labels without scraping dashboard text blocks or reopening transition/handoff derivation
|
||||
- the next clean move is to stay on that same live dashboard guidance-consumer lane and land the displayed active-run status, active-attempt/timer status, and current-case / current-deck status inspect surface group rather than drifting back into backend continuity or reopening the already-complete retained-history seam
|
||||
- the latest landed bounded `Phase 4` packet stays on that same live `UHyperTwistCoachDashboardWidget` guidance-consumer lane and adds displayed active-run status, displayed active-attempt/timer status, and displayed current-case / current-deck status inspect surfaces over already-derived live dashboard run-state, timer-state, and current-selection presentation state, so gameplay/Blueprint callers can inspect the current active-run line, run-summary line, attempt-input/timer posture, and current-case/current-deck presentation without scraping dashboard text blocks or reopening run/timer/current-case derivation
|
||||
- the next clean move is to stay on that same live dashboard guidance-consumer lane and land the displayed last-attempt review summary, displayed last-attempt timing / derived-phase review, and live split-capture status inspect surface group rather than drifting back into backend continuity or reopening the already-complete retained-history seam
|
||||
- the current execution-discipline rule that broad refactor / monolith-splitting work should not interrupt the active bounded roadmap packet unless structure is actually blocking it
|
||||
|
||||
## Current execution-reality references
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
# HyperTwist Phase 4 dashboard live active-run, attempt-timer, and current-case / current-deck status inspect surface packet
|
||||
|
||||
- bounded Phase `4` dashboard-consumer slice
|
||||
- date: `2026-05-09`
|
||||
|
||||
## Intent
|
||||
|
||||
Stay on the deliberate live `UHyperTwistCoachDashboardWidget` guidance-consumer lane and expose the remaining live active-run, attempt/timer, and current-case/current-deck presentation state directly to gameplay and Blueprint callers.
|
||||
|
||||
## Why this packet exists
|
||||
|
||||
The dashboard already derived:
|
||||
|
||||
- the displayed active-run status line
|
||||
- the displayed active-run summary line
|
||||
- the displayed attempt-input and live-timer status lines
|
||||
- the displayed current-case prompt and notation lines
|
||||
|
||||
But that live state still only surfaced through dashboard text blocks. Callers still had to scrape widget presentation or reopen active-run / timer / current-case derivation to inspect what the dashboard was currently showing.
|
||||
|
||||
## What changed
|
||||
|
||||
- added `FHyperTwistTrainingCoachDashboardActiveRunStatusInspectSurface`
|
||||
- added `FHyperTwistTrainingCoachDashboardActiveAttemptTimerStatusInspectSurface`
|
||||
- added `FHyperTwistTrainingCoachDashboardCurrentCaseDeckStatusInspectSurface`
|
||||
- added `GetDisplayedActiveRunStatusInspectSurface()`
|
||||
- added `GetDisplayedActiveAttemptTimerStatusInspectSurface()`
|
||||
- added `GetDisplayedCurrentCaseDeckStatusInspectSurface()`
|
||||
- retained the exact displayed active-run status/summary lines, attempt-input line, timer-status line, and current-case prompt/notation lines inside the widget so the new inspect surfaces report the same live strings the dashboard is already presenting
|
||||
- kept the packet bounded to `UHyperTwistCoachDashboardWidget` plus shared surface types, with no dashboard redesign and no backend continuity changes
|
||||
|
||||
## Files
|
||||
|
||||
- `C:\HyperTwist\UnrealHyperTwist\Source\UnrealHyperTwist\Public\HyperTwistTraining\HyperTwistTrainingTypes.h`
|
||||
- `C:\HyperTwist\UnrealHyperTwist\Source\UnrealHyperTwist\Public\HyperTwistTraining\HyperTwistCoachDashboardWidget.h`
|
||||
- `C:\HyperTwist\UnrealHyperTwist\Source\UnrealHyperTwist\Private\HyperTwistTraining\HyperTwistCoachDashboardWidget.cpp`
|
||||
- `C:\HyperTwist\docs\HYPERTWIST_ROADMAP_OVERHAUL_EXPANSION_GUIDE.md`
|
||||
|
||||
## Outcome
|
||||
|
||||
Gameplay and Blueprint callers can now inspect:
|
||||
|
||||
- the displayed active-run line and summarized active-run attempt totals
|
||||
- the displayed attempt-input posture and live timer phase/status line
|
||||
- the displayed current-case prompt/notation presentation plus the active current-deck context
|
||||
|
||||
without scraping dashboard text blocks or reopening active-run / timer / current-case derivation.
|
||||
|
||||
## Validation
|
||||
|
||||
- full `Development Editor | Win64` MSBuild on `UnrealHyperTwist.sln`
|
||||
- passed with `0 Warning(s), 0 Error(s)`
|
||||
|
||||
## Next clean slice
|
||||
|
||||
Stay on the same live dashboard guidance-consumer lane and land the displayed last-attempt review summary, displayed last-attempt timing / derived-phase review, and live split-capture status inspect surface group.
|
||||
Loading…
Add table
Reference in a new issue