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.
62 lines
2.3 KiB
C#
62 lines
2.3 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// Which kind of session the armed output starts. Since 2026-11-12 there is no inference from
|
|
/// editing: the output stage offers "Private Test Stream" and "Review & Go Live" as separate
|
|
/// buttons, so ON-AIR always means the real livestream and Test is something the creator asks for.
|
|
/// </summary>
|
|
public static SessionStartKind For(bool recordArmed, bool onAirArmed)
|
|
{
|
|
// Neither output 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 SessionStartKind.Live;
|
|
}
|
|
|
|
/// <summary>What pressing the button actually does, given whether YouTube is connected.
|
|
/// A signed-out ON-AIR press must start the SIGN-IN flow, not sit there disabled — a dead
|
|
/// primary button is the dead end the design principle forbids (creator, 2026-10-30).</summary>
|
|
public enum Route
|
|
{
|
|
SignIn,
|
|
Record,
|
|
Live,
|
|
Test,
|
|
}
|
|
|
|
public static Route RouteFor(SessionStartKind kind, bool connected) => kind switch
|
|
{
|
|
SessionStartKind.Record => Route.Record,
|
|
SessionStartKind.Test => connected ? Route.Test : Route.SignIn,
|
|
_ => connected ? Route.Live : Route.SignIn,
|
|
};
|
|
|
|
public static string LabelFor(SessionStartKind kind) => kind switch
|
|
{
|
|
SessionStartKind.Record => "Start Recording",
|
|
SessionStartKind.Test => "Test Stream",
|
|
_ => "Go Live",
|
|
};
|
|
}
|