using System.Collections.ObjectModel; using System.Linq; using ytLive.Helpers; using ytLive.Models; using ytLive.Services; namespace ytLive.ViewModels; public partial class MainViewModel : ViewModelBase { private readonly ChatOverlayLayer _chatLayer; private readonly AlertOverlayLayer _alertLayer; /// The live chat message buffer — the same collection the /// owns; here so XAML can bind it and the /// left panel can subscribe to its changes. public ObservableCollection ChatMessages => _chatLayer.Messages; /// The Add → YouTube Chat menu item: enabled only while no chat layer exists /// anywhere — one chat overlay per layout. public bool CanAddYouTubeChat => StagedScene != null && !Scenes.Any(s => s.Elements.OfType().Any(e => e.Type == SourceType.ChatBox)); /// The Add → Stream Alerts menu item: one alert zone per layout /// (multiple zones would double-play every event). public bool CanAddAlerts => StagedScene != null && !Scenes.Any(s => s.Elements.OfType().Any(e => e.Type == SourceType.AlertBox)); public bool ShowChatInactiveMessage => !IsLive; private void OnChatMessageReceived(ChatMessage message) { _chatLayer.OnMessageReceived(message, Scenes); _alertLayer.OnMessageReceived(message, Scenes); } private void UpdateChatBoxPreview(Source chatBox, IReadOnlyList? messages = null) => _chatLayer.UpdatePreview(chatBox, messages); private VideoFrame? RenderChatBox(Source chatBox) => _chatLayer.RenderFrame(chatBox); private void UpdateAlertBoxPreview(Source alertBox) => _alertLayer.UpdatePreview(alertBox); private VideoFrame? RenderAlertBox(Source alertBox) => _alertLayer.RenderFrame(alertBox); private void StartMockChatPreview() => _chatLayer.StartMockPreview(Scenes); private void StopMockChatPreview() => _chatLayer.StopMockPreview(); private void UpdateActiveChatBoxPreviews() => _chatLayer.UpdateConfiguredBoxes(Scenes); private void UpdateActiveAlertBoxPreviews() => _alertLayer.UpdateConfiguredBoxes(Scenes); }