Initial scaffold: ytLive C# WPF project

- MVVM architecture (Models, ViewModels, Views, Services, Helpers)
- Models: Scene, Source, StreamConfig, StreamHealth, YouTubeChannel, ChatMessage
- Services: YouTubeAuthService (OAuth2), YouTubeStreamService (broadcasts/stream health),
  YouTubeChatService (live chat polling)
- ViewModels: MainViewModel with scene management, stream controls, chat
- MainWindow with dark theme: scene/source panel, preview area, chat panel, status bar
- Version roadmap: v0.1 (scenes, RTMP, OAuth2, chat, health) -> 1.0
This commit is contained in:
2026-08-04 09:09:52 -07:00
commit 9103ff1fb7
16 changed files with 943 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
using System.Windows.Input;
namespace ytLive.Helpers;
public class RelayCommand : ICommand
{
private readonly Action<object?> _execute;
private readonly Func<object?, bool>? _canExecute;
public RelayCommand(Action<object?> execute, Func<object?, bool>? canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public event EventHandler? CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object? parameter) => _canExecute?.Invoke(parameter) ?? true;
public void Execute(object? parameter) => _execute(parameter);
}
+23
View File
@@ -0,0 +1,23 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace ytLive.Helpers;
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}