feat(top bar): EDIT decides live vs test on the primary button — the TEST button is gone
Creator ruling (2026-10-30): - EDIT off + ON-AIR armed → the primary button reads "Go Live" and runs the livestream. - EDIT on + ON-AIR armed → the same button reads "Test Stream" and runs the test broadcast. - REC armed (or nothing armed) → "Start Recording", whatever EDIT says; there is no test recording, and an unarmed start records locally rather than doing nothing. So the fifth button was redundant: `ShowTestButton` no longer feeds any control. The decision is a pure function (`Models/SessionStartDecision`) so the whole matrix is testable without a window; `PrimaryStartCommand` follows the same kind, so label and action cannot disagree. Guard: SessionStartDecisionTests pins the four cases, including the no-dead-ends fallback that my first version got wrong (unarmed returned Live instead of Record — the test caught it). Note for the v1 gate: the "hide TEST at v1" item is now satisfied by construction — the test path is a mode of the primary button, not a separate control.
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
namespace ytLive.Models;
|
||||
|
||||
/// <summary>What the top bar's primary action button will do.</summary>
|
||||
public enum SessionStartKind
|
||||
{
|
||||
Record,
|
||||
Live,
|
||||
Test,
|
||||
}
|
||||
|
||||
/// <summary>Creator ruling (2026-10-30): the primary button is context-sensitive, so the separate
|
||||
/// TEST button is gone.
|
||||
///
|
||||
/// <list type="bullet">
|
||||
/// <item>EDIT off + ON-AIR armed → Go Live (the livestream message)</item>
|
||||
/// <item>EDIT on + ON-AIR armed → Test Stream (the test-livestream message) — a dry run you
|
||||
/// cannot leak, because every broadcast is private pre-v1 anyway</item>
|
||||
/// <item>REC armed → Start Recording, whatever EDIT says (there is no test recording)</item>
|
||||
/// </list>
|
||||
///
|
||||
/// <para>Pure so the whole matrix is testable without a window.</para></summary>
|
||||
public static class SessionStartDecision
|
||||
{
|
||||
public static SessionStartKind For(bool recordArmed, bool onAirArmed, bool editing)
|
||||
{
|
||||
// Neither pill armed still starts something: local recording needs no account, and the
|
||||
// no-dead-ends rule forbids an inert primary button.
|
||||
if (recordArmed || !onAirArmed) return SessionStartKind.Record;
|
||||
return editing ? SessionStartKind.Test : SessionStartKind.Live;
|
||||
}
|
||||
|
||||
public static string LabelFor(SessionStartKind kind) => kind switch
|
||||
{
|
||||
SessionStartKind.Record => "Start Recording",
|
||||
SessionStartKind.Test => "Test Stream",
|
||||
_ => "Go Live",
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user