Broadcast Text pull-out (Live screen) + launch geometry 1920x1040/1366x768 with restore
This commit is contained in:
+29
-14
@@ -84,8 +84,6 @@ public class MainViewModel : ViewModelBase
|
||||
private bool _isAboutOpen;
|
||||
private bool _isLicensesOpen;
|
||||
private string _overlayTitle = string.Empty;
|
||||
private string _defaultStreamTitle = string.Empty;
|
||||
private string _defaultStreamDescription = string.Empty;
|
||||
private string _bugReportText = string.Empty;
|
||||
private string _bugReportEmail = string.Empty;
|
||||
private string _featureRequestText = string.Empty;
|
||||
@@ -465,6 +463,7 @@ public class MainViewModel : ViewModelBase
|
||||
OnPropertyChanged(nameof(IsOffline));
|
||||
OnPropertyChanged(nameof(IsLive));
|
||||
OnPropertyChanged(nameof(IsEditMode));
|
||||
OnPropertyChanged(nameof(IsBroadcastMetadataVisible));
|
||||
OnPropertyChanged(nameof(RecDotBrush));
|
||||
OnPropertyChanged(nameof(RecTextBrush));
|
||||
OnPropertyChanged(nameof(RecDotOpacity));
|
||||
@@ -1242,17 +1241,23 @@ public class MainViewModel : ViewModelBase
|
||||
private set => SetProperty(ref _overlayTitle, value);
|
||||
}
|
||||
|
||||
public string DefaultStreamTitle
|
||||
{
|
||||
get => _defaultStreamTitle;
|
||||
set => SetProperty(ref _defaultStreamTitle, value);
|
||||
}
|
||||
// ─── Broadcast metadata pull-out (the "Text" tab on the Live screen) ───
|
||||
|
||||
public string DefaultStreamDescription
|
||||
{
|
||||
get => _defaultStreamDescription;
|
||||
set => SetProperty(ref _defaultStreamDescription, value);
|
||||
}
|
||||
/// <summary>The broadcast id of the current/last session; null until Go Live
|
||||
/// succeeds. Gates the pull-out's Update button (nothing remote to patch).</summary>
|
||||
public string? CurrentBroadcastId => _currentBroadcastId;
|
||||
|
||||
/// <summary>The pull-out exists on the Live screen only — visible while streaming.</summary>
|
||||
public bool IsBroadcastMetadataVisible => IsLive;
|
||||
|
||||
public Services.LiveBroadcastFormViewModel BroadcastForm { get; }
|
||||
|
||||
// Window geometry pass-through (code-behind owns the WPF specifics).
|
||||
public (double Left, double Top, double Width, double Height, string State)? RestoreWindowState()
|
||||
=> _layoutStore.LoadWindowState();
|
||||
|
||||
public void PersistWindowState(double left, double top, double width, double height, string state)
|
||||
=> _layoutStore.SaveWindowState(left, top, width, height, state);
|
||||
|
||||
// ─── Resolution quality dropdown (bottom bar) ───
|
||||
// Tiers offered to the creator before going live. First = default. The
|
||||
@@ -1561,6 +1566,11 @@ public class MainViewModel : ViewModelBase
|
||||
_layoutStore = new LayoutStore(LayoutPathOverride ?? DefaultLayoutPath);
|
||||
_activeLayoutPath = _layoutStore.ActivePath;
|
||||
|
||||
BroadcastForm = new Services.LiveBroadcastFormViewModel(
|
||||
() => _layoutStore,
|
||||
() => _youtubeStream,
|
||||
() => CurrentBroadcastId);
|
||||
|
||||
// Restore the last picked mic so the mixer's first capture attaches to
|
||||
// the same, already-vetted device (green dot) or reports it missing
|
||||
// (yellow) instead of silently falling back to the default.
|
||||
@@ -1849,6 +1859,8 @@ public class MainViewModel : ViewModelBase
|
||||
SelectedTransitionType = parsed;
|
||||
TransitionDurationMs = transDur;
|
||||
|
||||
BroadcastForm.Load();
|
||||
|
||||
ScheduleSave();
|
||||
AppLog.Write("LoadLayout end");
|
||||
}
|
||||
@@ -2899,8 +2911,8 @@ public class MainViewModel : ViewModelBase
|
||||
{
|
||||
var dialog = new GoLiveViewModel(() => SignInAsync(), _youtubeAuth.CurrentChannel)
|
||||
{
|
||||
StreamTitle = DefaultStreamTitle,
|
||||
StreamDescription = DefaultStreamDescription,
|
||||
StreamTitle = BroadcastForm.Title,
|
||||
StreamDescription = BroadcastForm.Description,
|
||||
};
|
||||
var window = new ytLive.GoLiveWindow(dialog) { Owner = System.Windows.Application.Current.MainWindow };
|
||||
if (window.ShowDialog() == true)
|
||||
@@ -2908,6 +2920,7 @@ public class MainViewModel : ViewModelBase
|
||||
StreamTitle = dialog.StreamTitle;
|
||||
StreamDescription = dialog.StreamDescription;
|
||||
StreamVisibility = dialog.Visibility; // always "Private" (ship step 7)
|
||||
BroadcastForm.CaptureGoLive(dialog.StreamTitle, dialog.StreamDescription, DateTime.UtcNow);
|
||||
WindowTitle = string.IsNullOrWhiteSpace(dialog.StreamTitle)
|
||||
? "LlamaCasty"
|
||||
: $"{dialog.StreamTitle} — LlamaCasty";
|
||||
@@ -2950,6 +2963,7 @@ public class MainViewModel : ViewModelBase
|
||||
return;
|
||||
}
|
||||
AppLog.Write($"Broadcast created: {_currentBroadcastId}");
|
||||
OnPropertyChanged(nameof(CurrentBroadcastId));
|
||||
|
||||
// Start chat polling (TASK 9.4): fetch the liveChatId from the broadcast's
|
||||
// contentDetails, then start the poll loop. Chat is non-fatal — if it fails,
|
||||
@@ -3048,6 +3062,7 @@ public class MainViewModel : ViewModelBase
|
||||
_audioMixer.StopLive();
|
||||
_ = _framePump.StopAsync();
|
||||
_currentBroadcastId = null;
|
||||
OnPropertyChanged(nameof(CurrentBroadcastId));
|
||||
// Graceful end completes the session = signs out (the DPAPI token is
|
||||
// cleared so the next Start Stream requires a fresh sign-in). A crash
|
||||
// never runs this, so the token survives and the creator stays signed in.
|
||||
|
||||
Reference in New Issue
Block a user