222 lines
6.5 KiB
C#
222 lines
6.5 KiB
C#
using System.Collections.ObjectModel;
|
|
using System.Windows;
|
|
using System.Windows.Input;
|
|
using System.Windows.Threading;
|
|
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 readonly DispatcherTimer _liveTimer;
|
|
|
|
private Scene? _activeScene;
|
|
private StreamStatus _streamStatus = StreamStatus.Offline;
|
|
private StreamHealth _currentHealth = new();
|
|
private string _streamTitle = string.Empty;
|
|
private string _streamDescription = string.Empty;
|
|
private string _streamVisibility = "Public";
|
|
private string _windowTitle = "ytLive";
|
|
private string _topBarBackground = "#16213e";
|
|
private string _previewGlowBrush = "Transparent";
|
|
private Thickness _previewGlowThickness = new(0);
|
|
private string _liveElapsedText = "00:00:00";
|
|
private double _livePulseOpacity = 1.0;
|
|
private TimeSpan _liveElapsed;
|
|
|
|
public ObservableCollection<Scene> Scenes { get; } = new();
|
|
public ObservableCollection<ChatMessage> 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(LiveIndicatorVisible));
|
|
UpdateLiveVisuals();
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsOffline => StreamStatus == StreamStatus.Offline;
|
|
public bool IsLive => StreamStatus == StreamStatus.Streaming;
|
|
public bool LiveIndicatorVisible => IsLive;
|
|
|
|
public StreamHealth CurrentHealth
|
|
{
|
|
get => _currentHealth;
|
|
set => SetProperty(ref _currentHealth, value);
|
|
}
|
|
|
|
public string StreamTitle
|
|
{
|
|
get => _streamTitle;
|
|
set => SetProperty(ref _streamTitle, value);
|
|
}
|
|
|
|
public string StreamDescription
|
|
{
|
|
get => _streamDescription;
|
|
set => SetProperty(ref _streamDescription, value);
|
|
}
|
|
|
|
public string StreamVisibility
|
|
{
|
|
get => _streamVisibility;
|
|
set => SetProperty(ref _streamVisibility, value);
|
|
}
|
|
|
|
public string WindowTitle
|
|
{
|
|
get => _windowTitle;
|
|
set => SetProperty(ref _windowTitle, value);
|
|
}
|
|
|
|
public string TopBarBackground
|
|
{
|
|
get => _topBarBackground;
|
|
set => SetProperty(ref _topBarBackground, value);
|
|
}
|
|
|
|
public string PreviewGlowBrush
|
|
{
|
|
get => _previewGlowBrush;
|
|
set => SetProperty(ref _previewGlowBrush, value);
|
|
}
|
|
|
|
public Thickness PreviewGlowThickness
|
|
{
|
|
get => _previewGlowThickness;
|
|
set => SetProperty(ref _previewGlowThickness, value);
|
|
}
|
|
|
|
public string LiveElapsedText
|
|
{
|
|
get => _liveElapsedText;
|
|
set => SetProperty(ref _liveElapsedText, value);
|
|
}
|
|
|
|
public double LivePulseOpacity
|
|
{
|
|
get => _livePulseOpacity;
|
|
set => SetProperty(ref _livePulseOpacity, value);
|
|
}
|
|
|
|
// Commands
|
|
public ICommand AddSceneCommand { get; }
|
|
public ICommand RemoveSceneCommand { get; }
|
|
public ICommand StartStreamCommand { 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;
|
|
|
|
_liveTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
|
|
_liveTimer.Tick += OnLiveTimerTick;
|
|
|
|
AddSceneCommand = new RelayCommand(_ => AddScene());
|
|
RemoveSceneCommand = new RelayCommand(scene => RemoveScene(scene as Scene));
|
|
StartStreamCommand = new RelayCommand(_ => BeginGoLive());
|
|
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 void BeginGoLive()
|
|
{
|
|
var dialog = new GoLiveViewModel();
|
|
var window = new ytLive.GoLiveWindow(dialog) { Owner = System.Windows.Application.Current.MainWindow };
|
|
if (window.ShowDialog() == true)
|
|
{
|
|
StreamTitle = dialog.StreamTitle;
|
|
StreamDescription = dialog.StreamDescription;
|
|
StreamVisibility = dialog.Visibility;
|
|
WindowTitle = string.IsNullOrWhiteSpace(dialog.StreamTitle)
|
|
? "ytLive"
|
|
: $"{dialog.StreamTitle} — ytLive";
|
|
StreamStatus = StreamStatus.Streaming;
|
|
}
|
|
}
|
|
|
|
private void StopStream()
|
|
{
|
|
StreamStatus = StreamStatus.Offline;
|
|
WindowTitle = "ytLive";
|
|
}
|
|
|
|
private void UpdateLiveVisuals()
|
|
{
|
|
var live = IsLive;
|
|
TopBarBackground = live ? "#e94560" : "#16213e";
|
|
PreviewGlowBrush = live ? "#e94560" : "Transparent";
|
|
PreviewGlowThickness = live ? new Thickness(3) : new Thickness(0);
|
|
|
|
if (live)
|
|
{
|
|
_liveElapsed = TimeSpan.Zero;
|
|
LiveElapsedText = "00:00:00";
|
|
LivePulseOpacity = 1.0;
|
|
_liveTimer.Start();
|
|
}
|
|
else
|
|
{
|
|
_liveTimer.Stop();
|
|
LiveElapsedText = "00:00:00";
|
|
LivePulseOpacity = 1.0;
|
|
}
|
|
}
|
|
|
|
private void OnLiveTimerTick(object? sender, EventArgs e)
|
|
{
|
|
_liveElapsed = _liveElapsed.Add(TimeSpan.FromSeconds(1));
|
|
LiveElapsedText = _liveElapsed.ToString(@"hh\:mm\:ss");
|
|
LivePulseOpacity = LivePulseOpacity > 0.5 ? 0.35 : 1.0;
|
|
}
|
|
}
|