using System.Collections.ObjectModel; using System.Windows.Input; using ytLive.Helpers; using ytLive.Models; using ytLive.Services; namespace ytLive.ViewModels; public class MainViewModel : ViewModelBase { private readonly YouTubeAuthService _youtubeAuth; private readonly YouTubeStreamService _youtubeStream; private readonly YouTubeChatService _youtubeChat; private Scene? _activeScene; private StreamStatus _streamStatus = StreamStatus.Offline; private StreamHealth _currentHealth = new(); private string _streamTitle = string.Empty; private string _streamKey = string.Empty; private bool _isYouTubeConnected; public ObservableCollection Scenes { get; } = new(); public ObservableCollection ChatMessages { get; } = new(); public Scene? ActiveScene { get => _activeScene; set => SetProperty(ref _activeScene, value); } public StreamStatus StreamStatus { get => _streamStatus; set { if (SetProperty(ref _streamStatus, value)) { OnPropertyChanged(nameof(IsOffline)); OnPropertyChanged(nameof(IsLive)); OnPropertyChanged(nameof(StatusDisplay)); } } } public bool IsOffline => StreamStatus == StreamStatus.Offline; public bool IsLive => StreamStatus == StreamStatus.Streaming; public StreamHealth CurrentHealth { get => _currentHealth; set => SetProperty(ref _currentHealth, value); } public string StreamTitle { get => _streamTitle; set => SetProperty(ref _streamTitle, value); } public string StreamKey { get => _streamKey; set => SetProperty(ref _streamKey, value); } public bool IsYouTubeConnected { get => _isYouTubeConnected; set => SetProperty(ref _isYouTubeConnected, value); } public string StatusDisplay => StreamStatus switch { StreamStatus.Offline => "OFFLINE", StreamStatus.Connecting => "CONNECTING...", StreamStatus.Streaming => "LIVE", StreamStatus.Error => "ERROR", _ => "UNKNOWN" }; // Commands public ICommand AddSceneCommand { get; } public ICommand RemoveSceneCommand { get; } public ICommand StartStreamCommand { get; } public ICommand StopStreamCommand { get; } public ICommand ConnectYouTubeCommand { get; } public MainViewModel() { _youtubeAuth = new YouTubeAuthService("", ""); // TODO: load from config _youtubeStream = new YouTubeStreamService(_youtubeAuth); _youtubeChat = new YouTubeChatService(_youtubeAuth); _youtubeChat.MessageReceived += OnChatMessageReceived; AddSceneCommand = new RelayCommand(_ => AddScene()); RemoveSceneCommand = new RelayCommand(scene => RemoveScene(scene as Scene)); StartStreamCommand = new RelayCommand(_ => StartStream(), _ => StreamStatus == StreamStatus.Offline); StopStreamCommand = new RelayCommand(_ => StopStream(), _ => StreamStatus == StreamStatus.Streaming); ConnectYouTubeCommand = new RelayCommand(_ => ConnectYouTube()); // Start with a default scene AddScene("Scene 1"); } private void AddScene(string? name = null) { var scene = new Scene { Name = name ?? $"Scene {Scenes.Count + 1}" }; Scenes.Add(scene); ActiveScene = scene; } private void RemoveScene(Scene? scene) { if (scene == null) return; Scenes.Remove(scene); if (ActiveScene == scene) ActiveScene = Scenes.FirstOrDefault(); } private void OnChatMessageReceived(ChatMessage message) { System.Windows.Application.Current.Dispatcher.Invoke(() => { ChatMessages.Add(message); if (ChatMessages.Count > 500) ChatMessages.RemoveAt(0); }); } private async void StartStream() { StreamStatus = StreamStatus.Connecting; OnPropertyChanged(nameof(StatusDisplay)); // TODO: Initialize capture pipeline, encode, and push to RTMP // For now, simulate connection await Task.Delay(500); StreamStatus = StreamStatus.Streaming; OnPropertyChanged(nameof(StatusDisplay)); } private void StopStream() { StreamStatus = StreamStatus.Offline; OnPropertyChanged(nameof(StatusDisplay)); } private void ConnectYouTube() { // TODO: Launch OAuth2 flow in browser // For now, this is a stub IsYouTubeConnected = false; } }