using ytLive.Services;
namespace ytLive.ViewModels;
public partial class MainViewModel
{
/// The alert announcement strip as the preview pane shows it: a
/// full-master-width bitmap, or null when no alert is playing (or a Flash is in
/// its off half). Mirrors the social bar's global-overlay pattern — the strip is
/// NOT a per-source frame, so it can't ride the alert box's
/// VideoImageSource.
private System.Windows.Media.Imaging.WriteableBitmap? _alertTickerBitmap;
public System.Windows.Media.Imaging.WriteableBitmap? AlertTickerImageSource
{
get => _alertTickerBitmap;
private set
{
_alertTickerBitmap = value;
OnPropertyChanged(nameof(AlertTickerImageSource));
}
}
public bool AlertTickerVisible => _alertTickerBitmap != null;
/// Publishes one ticker frame to the preview pane. Called on the UI
/// thread from the alert layer's own tick, so the WPF bitmap write is legal.
/// Reuses one and
/// overwrites its back buffer — a fresh bitmap every tick would churn the
/// render cache for no reason.
internal void PublishAlertTickerPreview(VideoFrame? frame)
{
if (frame == null)
{
if (_alertTickerBitmap != null)
{
AlertTickerImageSource = null;
OnPropertyChanged(nameof(AlertTickerVisible));
}
return;
}
if (_alertTickerBitmap == null
|| _alertTickerBitmap.PixelWidth != frame.Width
|| _alertTickerBitmap.PixelHeight != frame.Height)
{
AlertTickerImageSource = new System.Windows.Media.Imaging.WriteableBitmap(
frame.Width, frame.Height, 96, 96,
System.Windows.Media.PixelFormats.Bgra32, null);
OnPropertyChanged(nameof(AlertTickerVisible));
}
var target = _alertTickerBitmap!;
target.WritePixels(
new System.Windows.Int32Rect(0, 0, frame.Width, frame.Height),
frame.BgraPixels, frame.Stride, 0);
// The bitmap instance is unchanged, so the pane's Source binding still
// points at it — nudge it so WPF re-reads the back buffer this tick.
OnPropertyChanged(nameof(AlertTickerImageSource));
}
}