using ytLive.Services; namespace ytLive.ViewModels; public partial class MainViewModel { /// Test seam (mirrors CameraEnumeratorOverride): tests inject a fake /// stats service before constructing the VM so refresh never hits the network. internal static Func? ChannelStatsFactoryOverride { get; set; } /// The YPP pull-out backing VM — the drawer below Stream Settings /// on the Live screen's right edge (TASK 39). public Services.YppTrackerViewModel Ypp { get; private set; } = null!; /// The Test Stream pull-out backing VM — the TEST drawer at the /// bottom of the right rail (TASK 41): mock chat input (real insert → /// poll round-trip) + locally-simulated member / SuperChat / subscriber rows. public Services.TestSessionViewModel TestSession { get; private set; } = null!; private void InitYpp() { Ypp = new YppTrackerViewModel( () => _layoutStore, () => ChannelStatsFactoryOverride?.Invoke() ?? new ChannelStatsService(_youtubeAuth), () => IsConnected, () => _youtubeAuth.CurrentChannel?.DisplayName); TestSession = new TestSessionViewModel( _youtubeStream, _youtubeChat, onEndStream: StopStream); // One drawer at a time: the three pull-outs share the preview's right edge, // so opening one collapses the other two (all directions). BroadcastForm.PropertyChanged += (_, e) => { if (e.PropertyName == nameof(LiveBroadcastFormViewModel.IsDrawerOpen) && BroadcastForm.IsDrawerOpen) { Ypp.IsDrawerOpen = false; TestSession.IsDrawerOpen = false; } }; Ypp.PropertyChanged += (_, e) => { if (e.PropertyName == nameof(YppTrackerViewModel.IsDrawerOpen) && Ypp.IsDrawerOpen) { BroadcastForm.IsDrawerOpen = false; TestSession.IsDrawerOpen = false; } }; TestSession.PropertyChanged += (_, e) => { if (e.PropertyName == nameof(TestSessionViewModel.IsDrawerOpen) && TestSession.IsDrawerOpen) { BroadcastForm.IsDrawerOpen = false; Ypp.IsDrawerOpen = false; } }; } }