feat(topbar): the output stage — Output [YouTube] [Local MP4] One output at a time
Unit B (creator ruling 2026-11-12). Pressing Record / Go Live now changes the bar: the REC/ON-AIR pill pair becomes two labelled switches with glyphs (the YouTube mark, the record dot), under an "Output" label and beside "One output at a time". Build world shows nothing but its own segment. Two things this exposed that were not cosmetic: - **Local MP4 was not actually the default.** Both pills started unarmed, so the stage opened with no output selected; the old screen got away with it because the primary button inferred "record" from "nothing armed". RecordPillOn now starts true, which is what "pos = ON (default)" means in code. - **The stage gates the whole idle cluster, not just the switch.** Gating only the switch left the start button visible in the Build world — a Start with no output chosen. ShowOutputStage (output world, idle, not recording) wraps the cluster, so a running session hides the stage too: its output cannot change. Exclusivity stays in the view model (arming one drops the other); the XAML merely reflects it. TopBarWorldTests pins the stage's visibility and the radio pair starting at Local MP4. 680 pass, 0 warnings. Next: unit C (output-dependent primary action, End labels). Scope justification: Assets/starting-background.jpg is outside this unit — the creator's replacement art, still awaiting their visual check.
This commit is contained in:
@@ -13,6 +13,40 @@ namespace ytLive.Tests;
|
||||
[Collection("MainViewModelLayoutPath")]
|
||||
public class TopBarWorldTests
|
||||
{
|
||||
[Fact]
|
||||
public void The_output_stage_belongs_to_the_output_world_and_holds_one_output_at_a_time()
|
||||
{
|
||||
var db = Path.Combine(Path.GetTempPath(), $"llamacasty-outputstage-{Guid.NewGuid():N}.db");
|
||||
MainViewModel.LayoutPathOverride = db;
|
||||
try
|
||||
{
|
||||
var vm = new MainViewModel();
|
||||
|
||||
// Nothing to arm while building scenes.
|
||||
Assert.False(vm.ShowOutputStage);
|
||||
|
||||
vm.EnterOutputWorldCommand.Execute(null);
|
||||
Assert.True(vm.IsOutputWorld);
|
||||
Assert.True(vm.IsOffline);
|
||||
Assert.False(vm.IsRecording);
|
||||
Assert.True(vm.ShowOutputStage);
|
||||
|
||||
// Local MP4 is the default output; the pair is one axis, so arming either drops the other.
|
||||
Assert.True(vm.RecordPillOn);
|
||||
Assert.False(vm.OnAirPillOn);
|
||||
vm.OnAirPillOn = true;
|
||||
Assert.True(vm.OnAirPillOn);
|
||||
Assert.False(vm.RecordPillOn);
|
||||
vm.RecordPillOn = true;
|
||||
Assert.False(vm.OnAirPillOn);
|
||||
}
|
||||
finally
|
||||
{
|
||||
MainViewModel.LayoutPathOverride = null;
|
||||
try { File.Delete(db); } catch (IOException) { }
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Build_scenes_is_the_default_world_and_is_the_only_place_editing_lives()
|
||||
{
|
||||
|
||||
@@ -41,6 +41,14 @@ public class UiShellTests
|
||||
Assert.Contains("Data=\"M7,10V7a5,5 0 0,1 10,0v3h1", topBar);
|
||||
Assert.Contains("Visibility=\"{Binding IsOutputWorld, Converter={StaticResource BoolToVis}}\"", topBar);
|
||||
|
||||
// 2c. The output stage: two labelled switches and the exclusivity promise beside them.
|
||||
Assert.Contains("Text=\"Output\"", topBar);
|
||||
Assert.Contains("Text=\"YouTube\"", topBar);
|
||||
Assert.Contains("Text=\"Local MP4\"", topBar);
|
||||
Assert.Contains("Text=\"One output at a time\"", topBar);
|
||||
Assert.Contains("IsChecked=\"{Binding OnAirPillOn}\"", topBar);
|
||||
Assert.Contains("IsChecked=\"{Binding RecordPillOn}\"", topBar);
|
||||
|
||||
// 3. Active scene = orange; live stays red.
|
||||
Assert.Contains("IsStaged}\" Value=\"True\">\n <Setter Property=\"BorderBrush\" Value=\"{StaticResource Brush.Attention}\"/>", strip);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user