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(ShowGoLive)); } } } 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 { if (SetProperty(ref _isYouTubeConnected, value)) { OnPropertyChanged(nameof(ShowConnect)); OnPropertyChanged(nameof(ShowGoLive)); } } } public bool ShowConnect => !IsYouTubeConnected; public bool ShowGoLive => IsYouTubeConnected && IsOffline; // Commands public ICommand AddSceneCommand { get; } public ICommand RemoveSceneCommand { get; } public ICommand ConnectCommand { get; } public ICommand GoLiveCommand { get; } public ICommand EndStreamCommand { 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)); ConnectCommand = new RelayCommand(_ => ConnectYouTube()); GoLiveCommand = new RelayCommand(_ => StartStream(), _ => IsYouTubeConnected && IsOffline); EndStreamCommand = new RelayCommand(_ => StopStream(), _ => IsLive); // 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; // TODO: Initialize capture pipeline, encode, and push to RTMP // For now, simulate connection await Task.Delay(500); StreamStatus = StreamStatus.Streaming; } private void StopStream() { StreamStatus = StreamStatus.Offline; } private void ConnectYouTube() { // TODO: Launch OAuth2 flow in browser // For now, this is a stub IsYouTubeConnected = false; } }