namespace Lumi.Companion.Overlay; public static class OverlayVisibilityPolicy { public static bool Automatic(LumiOverlaySettings settings, IEnumerable sources) { if (!settings.Enabled || settings.Visibility == OverlayVisibilityMode.Off) return false; if (settings.Visibility == OverlayVisibilityMode.On) return true; var selected = settings.SelectedSourceIds.ToHashSet(StringComparer.Ordinal); return sources.Any(source => source.Live == true && source.Platform is "twitch" or "youtube" && selected.Contains(source.Id)); } public static bool Effective(LumiOverlaySettings settings, IEnumerable sources, bool preview, bool? visibilityOverride) => preview || settings.Enabled && (visibilityOverride ?? Automatic(settings, sources)); } public sealed record OverlayVisibilityPresentation(bool Visible, string State, string Action, bool CanToggle); public static class OverlayVisibilityPresenter { public static OverlayVisibilityPresentation Describe( LumiOverlaySettings settings, bool automaticVisible, bool preview, bool? visibilityOverride) { if (preview) return new(true, "Shown — sample preview is controlling visibility", "End preview to change visibility", false); if (!settings.Enabled) return new(false, "Hidden — Lumi Overlay is disabled", "Enable and save Lumi Overlay first", false); var visible = visibilityOverride ?? automaticVisible; if (visibilityOverride.HasValue) return new(visible, visible ? "Shown — temporary override" : "Hidden — temporary override", "Restore automatic visibility", true); var automaticDetail = settings.Visibility switch { OverlayVisibilityMode.Off => "visibility is set to Off", OverlayVisibilityMode.WhenLive when visible => "a selected channel is live", OverlayVisibilityMode.WhenLive => "waiting for a selected channel to go live", _ => "visibility is set to Always on" }; return new(visible, $"{(visible ? "Shown" : "Hidden")} — automatic; {automaticDetail}", visible ? "Hide temporarily" : "Show temporarily", true); } } public sealed record MonitorResolution(string? MonitorId, bool UsedFallback, string? Warning); public static class OverlayMonitorPolicy { public static MonitorResolution Resolve(string? savedMonitorId, IEnumerable availableMonitorIds, string? primaryMonitorId) { var available = availableMonitorIds.Where(value => !string.IsNullOrWhiteSpace(value)).ToHashSet(StringComparer.Ordinal); if (savedMonitorId is not null && available.Contains(savedMonitorId)) return new(savedMonitorId, false, null); var fallback = primaryMonitorId is not null && available.Contains(primaryMonitorId) ? primaryMonitorId : available.FirstOrDefault(); return new(fallback, savedMonitorId is not null, savedMonitorId is null ? null : "The selected monitor is unavailable. Lumi Overlay is temporarily using the primary monitor."); } } public static class CompanionLiveReconnectPolicy { public static TimeSpan Delay(int attempt) => TimeSpan.FromSeconds(Math.Min(30, Math.Pow(2, Math.Min(Math.Max(1, attempt), 5)))); }