Files
LlamaCasty/ViewModels/MainViewModel.TopBar.cs
T
gramps 4bc41c488c feat(topbar): the action follows the armed output; Test is an explicit ask again
Unit C (creator ruling 2026-11-12).

- Local MP4: one button, "Start Recording".
- YouTube: "Private Test Stream" beside "Review & Go Live", the latter with the primary face because it
  is the default ask.
- Running: "End Live Stream" (or "End Test" for a test run, "Stop Recording" for a local one).

The behavioural change underneath: SessionStartDecision.For no longer takes `editing`. Since 2026-10-30
EDIT silently chose test-vs-real, which meant the same button did two different things depending on a
toggle three inches away. With Test as its own button that inference has no job, so For() now reads only
the armed output and ON-AIR always means the real livestream. That supersedes the 2026-10-30 ruling;
SessionStartDecisionTests is rewritten to pin the new matrix rather than the old one.

A signed-out press still starts the sign-in flow instead of sitting dead (no-dead-ends), unchanged from
before — now stated in one place, the two new commands, instead of inside a route table.

680 pass, 0 warnings. Scope justification: Assets/starting-background.jpg is outside this unit — the
creator's replacement art, still awaiting their visual check.
2026-11-12 15:44:15 -08:00

83 lines
3.6 KiB
C#

using System.Windows.Input;
using ytLive.Helpers;
namespace ytLive.ViewModels;
/// <summary>Which half of the top bar's dual segment is in force.</summary>
public enum BarWorld
{
/// <summary>Build Scenes — the edit surface. The default at launch (creator ruling 2026-11-12).</summary>
Build,
/// <summary>Record / Go Live — the output surface: which output, and the one action that starts it.</summary>
Output,
}
/// <summary>
/// The top bar's one decision (creator ruling 2026-11-12): <c>[ Build Scenes ][ Record / Go Live ]</c>.
/// Build Scenes <b>is</b> edit mode — there is no separate EDIT toggle any more, so "may I edit?" and
/// "which world am I in?" cannot disagree.
///
/// <para>Clicking the highlighted segment is not a no-op: it re-enters that world, which matters while a
/// session runs because Build Scenes is the only way back to the layers (see
/// <see cref="LockEditWhileLive"/>).</para>
/// </summary>
public partial class MainViewModel
{
private BarWorld _barWorld = BarWorld.Build;
public BarWorld BarWorld => _barWorld;
public bool IsBuildWorld => _barWorld == BarWorld.Build;
public bool IsOutputWorld => _barWorld == BarWorld.Output;
/// <summary>The output stage belongs to the Record / Go Live world, and only while nothing is
/// running — a live session cannot change its output, so its switch is not offered.</summary>
public bool ShowOutputStage => IsOutputWorld && IsOffline && !IsRecording;
/// <summary>The action the armed output offers: recording is one button, YouTube is two — the test
/// run and the real one are separate asks since 2026-11-12, not something inferred from EDIT.</summary>
public bool ShowStartRecordingAction => ShowOutputStage && RecordPillOn;
public bool ShowYouTubeStartActions => ShowOutputStage && OnAirPillOn;
public ICommand StartRecordingCommand { get; private set; } = null!;
public ICommand TestStreamCommand { get; private set; } = null!;
public ICommand GoLiveCommand { get; private set; } = null!;
public ICommand EnterBuildWorldCommand { get; private set; } = null!;
public ICommand EnterOutputWorldCommand { get; private set; } = null!;
private void InitializeWorldCommands()
{
StartRecordingCommand = new RelayCommand(_ => BeginRecordOnly(), _ => ShowStartRecordingAction);
// A signed-out press starts the sign-in flow instead of sitting dead (no-dead-ends rule).
TestStreamCommand = new RelayCommand(_ =>
{
if (!IsConnected) { _ = SignInAsync(); return; }
BeginTestStream();
}, _ => ShowYouTubeStartActions);
GoLiveCommand = new RelayCommand(_ =>
{
if (!IsConnected) { _ = SignInAsync(); return; }
StartSession();
}, _ => ShowYouTubeStartActions);
EnterBuildWorldCommand = new RelayCommand(_ => EnterWorld(BarWorld.Build));
EnterOutputWorldCommand = new RelayCommand(_ => EnterWorld(BarWorld.Output));
}
/// <summary>Switches worlds. Re-entering the current one still re-asserts its edit state, which is
/// what lets a creator take EDIT back mid-show by clicking Build Scenes.</summary>
internal void EnterWorld(BarWorld world)
{
_barWorld = world;
OnPropertyChanged(nameof(BarWorld));
OnPropertyChanged(nameof(IsBuildWorld));
OnPropertyChanged(nameof(IsOutputWorld));
EditingActive = world == BarWorld.Build;
OnPropertyChanged(nameof(ShowOutputStage));
OnPropertyChanged(nameof(ShowStartRecordingAction));
OnPropertyChanged(nameof(ShowYouTubeStartActions));
}
}