Right rail, top bar, bottom bar and chat border: Socials slide-out drawer, tab icons and colors, EDIT toggle, stream readouts moved to the top-left cell, webcam border restored, chat border controls, 30fps vertical tier

- Socials: the dialog is a right-rail drawer (same pattern as Stream Info/YPP/TEST); the live-screen button is removed
- Right rail: Stream Info (was Stream Settings) and YPP show the YouTube logo; Socials and TEST get icons; tab colors and label colors per spec
- Top bar: EDIT toggle beside REC (orange when on, blue when off); going live on YouTube turns it off
- Stream readouts (bitrate, FPS, dropped n (x.y%), Live hh:mm:ss, health) and the resolution dropdown moved to the top-left cell; bottom bar emptied at the same height
- Webcam border drawing restored (it was removed with the CRT bezel change)
- YouTube chat layer: border color, thickness, and opacity controls
- Vertical 1080p30 tier added

Not related to the fps gate yet; no gating is enforced.
This commit is contained in:
2026-10-26 18:24:09 -07:00
parent a8814b42d0
commit 7ae30d4cfc
13 changed files with 341 additions and 102 deletions
+23
View File
@@ -0,0 +1,23 @@
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace ytLive.Helpers;
public class DroppedFramesToBrushConverter : IValueConverter
{
private static readonly SolidColorBrush Attention = new(Color.FromRgb(0xff, 0x8c, 0x3a));
private static readonly SolidColorBrush Clean = new(Colors.White);
static DroppedFramesToBrushConverter()
{
Attention.Freeze();
Clean.Freeze();
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
=> value is int dropped && dropped > 0 ? Attention : Clean;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
+20
View File
@@ -0,0 +1,20 @@
using System.Globalization;
using System.Windows.Data;
namespace ytLive.Helpers;
public class DroppedPercentConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var dropped = values.Length > 0 && values[0] is int d ? d : 0;
var fps = values.Length > 1 && values[1] is double f ? f : 0;
var duration = values.Length > 2 && values[2] is TimeSpan t ? t : TimeSpan.Zero;
var total = fps * duration.TotalSeconds;
var percent = total > 0 ? dropped / total * 100 : 0;
return $"{dropped} ({percent.ToString("0.0", CultureInfo.InvariantCulture)}%)";
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}