fix(scoreboard): the strip finally reaches the preview, and dev labels are orange

"Clicking on everything produces no visible effect" — the cause was upstream of the controls, and it
is the same defect as the invisible alert box (TASK 47):

- `Source.DisplaySource` returned `VideoImageSource` only for ChatBox / WebSource / MediaSource /
  AlertBox. The scoreboard's frame was rendered and published, then never displayed.
- the preview's Image has a per-type Visibility trigger for each of those and none for IsScoreboard,
  so even a correct DisplaySource would have stayed collapsed.

Both are fixed, and the layer test now pins the frame-source list AND the trigger so the pair cannot
drift apart again.

Dev-only affordances are ORANGE from now on (creator ruling): "Simulate (dev)" is a TextBlock in
Brush.Attention, so a development control can never be mistaken for product. The panel test pins the
colour.
This commit is contained in:
2026-10-30 15:05:33 -07:00
parent 9405c54750
commit 8caee21b9a
5 changed files with 29 additions and 3 deletions
+6 -2
View File
@@ -463,9 +463,13 @@
<!-- DEBUG builds only: prove the strip in the preview before a real
stream. Absent from Release, not merely hidden by a flag. -->
<CheckBox Style="{StaticResource YtCheckBox}" Margin="0,0,0,4"
Content="Simulate (dev)" IsChecked="{Binding ScoreboardSimulate, Mode=TwoWay}"
IsChecked="{Binding ScoreboardSimulate, Mode=TwoWay}"
ToolTip="Push sample events so the strip appears in the preview."
Visibility="{Binding IsDevelopmentBuild, Converter={StaticResource BoolToVis}}"/>
Visibility="{Binding IsDevelopmentBuild, Converter={StaticResource BoolToVis}}">
<!-- Dev-only affordances wear orange so a development control can never
be mistaken for product. -->
<TextBlock Text="Simulate (dev)" Foreground="{StaticResource Brush.Attention}" FontSize="12"/>
</CheckBox>
<CheckBox Style="{StaticResource YtCheckBox}" Margin="0,0,0,4"
Content="Show the scoreboard" IsChecked="{Binding ScoreboardEnabled, Mode=TwoWay}"
ToolTip="Off hides the strip in every scene AND stops the channel polling."/>
+5
View File
@@ -138,6 +138,11 @@
<DataTrigger Binding="{Binding IsAlertBox}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<!-- The scoreboard strip is a frame-source too: without this trigger its
Image stays collapsed and every property change looks inert. -->
<DataTrigger Binding="{Binding IsScoreboard}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsWebSource}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
<Setter Property="Stretch" Value="Fill"/>
+8 -1
View File
@@ -143,9 +143,16 @@ public class Source : SceneElement
public ImageSource? ImageSource => _imageSource;
/// <summary>Types whose frame is produced at runtime rather than stored as an asset. The
/// scoreboard joined this list 2026-10-30 — without it the strip was rendered, published to
/// VideoImageSource, and never displayed (the same shape as the invisible-alert defect).</summary>
private bool IsFrameSource =>
Type is SourceType.ChatBox or SourceType.WebSource or SourceType.MediaSource
or SourceType.AlertBox or SourceType.Scoreboard;
public override ImageSource? DisplaySource => IsLiveCapture
? (VideoImageSource ?? _imageSource)
: (Type is SourceType.ChatBox or SourceType.WebSource or SourceType.MediaSource or SourceType.AlertBox ? VideoImageSource : _imageSource);
: (IsFrameSource ? VideoImageSource : _imageSource);
public override bool IsImageSource => Type == SourceType.Image;
+6
View File
@@ -25,6 +25,12 @@ public class ScoreboardLayerTests
var resolver = SourceAssert.Text("ViewModels", "MainViewModel.cs");
Assert.Contains("Source { Type: SourceType.Scoreboard } => _scoreboardPresenter?.Frame", resolver);
// The PREVIEW must show the strip: its frame is a runtime frame-source and its Image needs
// the visibility trigger. Missing either made every property change look inert (2026-10-30).
var source = SourceAssert.Text("Models", "Source.cs");
Assert.Contains("or SourceType.AlertBox or SourceType.Scoreboard", source);
Assert.Contains("IsScoreboard", SourceAssert.Text("Controls", "PreviewPane.xaml"));
// Session lifecycle: every start clears the tallies.
var ops = SourceAssert.Text("ViewModels", "MainViewModel.Streaming.Operations.cs");
Assert.Contains("StartScoreboardSession();", ops);
@@ -25,6 +25,10 @@ public class ScoreboardPropertiesTests
Assert.Contains("Sign in to YouTube to use the scoreboard.", block);
Assert.Contains("CanUseScoreboard, Converter={StaticResource InverseBoolToVis}", block);
// Dev-only labels are ORANGE, so a development affordance cannot pass for product.
Assert.Contains("Simulate (dev)", block);
Assert.Contains("Brush.Attention", block);
// The master switch sits in the same panel: off hides the strip and stops the polling.
Assert.Contains("ScoreboardEnabled", panel);