diff --git a/App.xaml b/App.xaml index 2bf3cea..0c688a0 100644 --- a/App.xaml +++ b/App.xaml @@ -4,6 +4,10 @@ xmlns:local="clr-namespace:ytLive" StartupUri="MainWindow.xaml"> - + + + + + diff --git a/App.xaml.cs b/App.xaml.cs index 1ff0ff3..462beaa 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -1,13 +1,34 @@ -using System.Configuration; -using System.Data; -using System.Windows; - -namespace ytLive; - -/// -/// Interaction logic for App.xaml -/// -public partial class App : Application -{ -} - +using System.Windows; +using System.Windows.Threading; +using ytLive.Helpers; + +namespace ytLive; + +/// +/// Interaction logic for App.xaml +/// +public partial class App : Application +{ + public App() + { + AppLog.Write("App ctor"); + } + + protected override void OnStartup(StartupEventArgs e) + { + // The app is a WinExe (no visible console) and is often debugged from + // WSL where it can't even run, so startup checkpoints and any unhandled + // exception are written to %APPDATA%\ytLlive\startup.log via AppLog. + AppDomain.CurrentDomain.UnhandledException += (_, args) => + AppLog.Write(args.ExceptionObject is Exception ex + ? "AppDomain unhandled exception: " + ex + : "AppDomain unhandled exception object: " + args.ExceptionObject); + + DispatcherUnhandledException += (_, args) => + AppLog.Write(args.Exception, "Dispatcher unhandled exception"); + + AppLog.Write("App OnStartup begin"); + base.OnStartup(e); + AppLog.Write("App OnStartup end"); + } +} diff --git a/GoLiveWindow.xaml b/GoLiveWindow.xaml index 5ec4d72..a662e23 100644 --- a/GoLiveWindow.xaml +++ b/GoLiveWindow.xaml @@ -7,58 +7,9 @@ ShowInTaskbar="False" Background="#1a1a2e"> - - - - - - - - - - - + + + @@ -77,17 +28,17 @@ - - + - - + - - + @@ -95,9 +46,9 @@ - - - - + @@ -326,7 +251,7 @@ - + @@ -347,18 +272,18 @@ - - - - + @@ -379,7 +304,7 @@ - + @@ -567,7 +493,14 @@ Foreground="#e94560" Margin="20,0,0,0"/> - + + @@ -638,16 +572,6 @@ - - - - - - - diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 07d1f1f..e204418 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -4,6 +4,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; +using ytLive.Helpers; using ytLive.Models; using ytLive.ViewModels; @@ -15,11 +16,21 @@ public partial class MainWindow : Window public MainWindow() { + AppLog.Write("MainWindow ctor: before InitializeComponent"); InitializeComponent(); + AppLog.Write("MainWindow ctor: after InitializeComponent"); _viewModel = (MainViewModel)DataContext; _viewModel.PropertyChanged += OnViewModelPropertyChanged; + // When a focused scene is deleted, never land focus on a hidden scene. + SceneList.IsSelectable = item => item is Scene { IsHidden: false }; UpdateTaskbarOverlay(); UpdateSelectionOverlay(); + AppLog.Write("MainWindow ctor: end"); + } + + private void MainWindow_Loaded(object sender, RoutedEventArgs e) + { + AppLog.Write("MainWindow loaded"); } private void OnViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e) diff --git a/Models/QualityOption.cs b/Models/QualityOption.cs new file mode 100644 index 0000000..229626e --- /dev/null +++ b/Models/QualityOption.cs @@ -0,0 +1,10 @@ +namespace ytLive.Models; + +/// +/// A resolution tier offered by the bottom-bar dropdown. Bitrate is Mbps. +/// +public sealed record QualityOption(string Display, int Fps, double Bitrate) +{ + /// Self-documenting label, e.g. "1080p60 (8Mbps)". + public string Label => $"{Display} ({Bitrate:0.#}Mbps)"; +} diff --git a/Models/index.md b/Models/index.md new file mode 100644 index 0000000..66768db --- /dev/null +++ b/Models/index.md @@ -0,0 +1,15 @@ +# Models — index + +Plain data types. No logic beyond what a property can carry. See +[`schema.md`](../schema.md) for the memory-map conventions. + +| File | Purpose | +|------|---------| +| `Scene.cs` | A scene: `Name`, `IsHidden`, `IsChatScene`, `IsEditing`, `Sources` collection | +| `Source.cs` | A source: `SourceType` enum (Image/Webcam/Screen/Background/Text), `X`/`Y`/`Width`/`Height`, `Opacity`, `IsEnabled`, `ImageSource`, asset identity | +| `QualityOption.cs` | Resolution tier record `(Display, Fps, Bitrate)`; `Label` formats as `1080p60 (8Mbps)` — drives the bottom-bar dropdown | +| `StreamConfig.cs` | `StreamConfig` (note: `TargetBitrate`/`Resolution` defaults are stale — not yet wired to the dropdown), `StreamHealth` (bitrate/FPS/dropped/duration), `StreamStatus` enum | +| `YouTube.cs` | `YouTubeChannel` and `ChatMessage` (chat feed) | + +Related: [`ViewModels/index.md`](../ViewModels/index.md) consume these; +[`Services/LayoutStore.cs`](../Services/LayoutStore.cs) persists `Scene`/`Source`. diff --git a/README.md b/README.md index c5feed6..7843bcf 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,14 @@ dotnet run | Path | Role | |------|------| -| `Models/` | Scene, Source, StreamConfig, StreamHealth, YouTube channel/chat | -| `ViewModels/` | MainViewModel — scenes, stream controls, chat | -| `Services/` | YouTubeAuthService (OAuth2), YouTubeStreamService (broadcast/health), YouTubeChatService (chat polling) | -| `Helpers/` | ViewModelBase, RelayCommand | +| `Models/` | Scene, Source, QualityOption, StreamConfig, StreamHealth, YouTube channel/chat | +| `ViewModels/` | MainViewModel — scenes, stream controls, chat; GoLiveViewModel, ReuseImageViewModel | +| `Services/` | YouTubeAuthService (OAuth2), YouTubeStreamService (broadcast/health), YouTubeChatService (chat polling), LayoutStore (SQLite) | +| `Helpers/` | ViewModelBase, RelayCommand, ImageCache, AppLog, FocusPreservingListBox, OAuthCredentials | +| `Themes/` | `Controls.xaml` — the dark-theme control styles, merged once in `App.xaml` | | `MainWindow.xaml` | Dark-theme main UI: scene/source panel, preview, chat, status bar | + +## Docs (memory map) + +`schema.md` defines the conventions; `ai.md` is the AI/session guide; +`TASKS.md` is the task queue. Each code directory carries an `index.md`. diff --git a/ReuseImageDialog.xaml b/ReuseImageDialog.xaml index 8c55755..930c372 100644 --- a/ReuseImageDialog.xaml +++ b/ReuseImageDialog.xaml @@ -7,30 +7,7 @@ ShowInTaskbar="False" Background="#1a1a2e"> - - - + + @@ -95,11 +73,11 @@