using System.Collections.Generic; using System.Linq; namespace ytLive.Models; /// Keeps exactly one Scoreboard layer in EVERY scene. /// /// Creator ruling (2026-10-30): "YT_ACTIVITY_TICKER … is available to all scenes." The /// scoreboard is not something to add five times — it exists once per scene like the Background and /// the Brand logo, and a creator turns it off per scene with the ordinary eye toggle. Removing it is /// therefore not a delete: it heals on the next load. /// /// Pure over a scene collection, so the rule is testable without a view-model. public static class ScoreboardHealer { public const string LayerName = "Scoreboard"; /// The strip's default box: full width, a strip's height, and its Y for the bottom /// edge. Geometry only — the EDGE itself is resolved against the social bar at render time. public const double StripHeight = 56; public const double BottomY = 1080 - StripHeight; /// Ensures one scoreboard per scene, appended as the TOPMOST layer: it is a full-width /// strip drawn over the scene, and inserting it above the background would break the Brand /// logo's documented invariant ("directly above the background"). Returns true when anything /// changed, so the caller can save. public static bool Ensure(IEnumerable scenes) { var changed = false; foreach (var scene in scenes) { var existing = scene.Elements.OfType().Where(s => s.IsScoreboard).ToList(); // More than one: keep the first, drop the rest. foreach (var extra in existing.Skip(1)) { scene.Elements.Remove(extra); changed = true; } if (existing.Count > 0) continue; scene.Elements.Add(new Source { Name = LayerName, Type = SourceType.Scoreboard, IsEnabled = true, X = 0, Y = BottomY, Width = 1920, Height = StripHeight, }); changed = true; } return changed; } }