Branding flash monetization: full-frame 'made with ytLlive!' every 300s replaces the always-on watermark
This commit is contained in:
@@ -56,6 +56,14 @@ public class MainViewModel : ViewModelBase
|
||||
private DispatcherTimer? _saveDebounce;
|
||||
private bool _isLoading;
|
||||
|
||||
// Branding flash (monetization): a full-frame "made with ytLlive!" shown
|
||||
// for ~1s every 300s on the live output, ~25% opacity. Paid unlock sets
|
||||
// BrandFlashEnabled = false. See ai.md "Monetization".
|
||||
private readonly DispatcherTimer _brandFlashTimer;
|
||||
private readonly DispatcherTimer _brandFlashOffTimer;
|
||||
private bool _brandFlashEnabled = true;
|
||||
private bool _brandFlashActive;
|
||||
|
||||
private const string SupportEmail = "gramps@llamachile.shop";
|
||||
private const string ChannelUrl = "https://youtube.com/@llamachileshop";
|
||||
public static string AppVersionLabel => $"Version {typeof(MainViewModel).Assembly.GetName().Version?.ToString(3)}";
|
||||
@@ -135,6 +143,33 @@ public class MainViewModel : ViewModelBase
|
||||
public bool ShowPreviewPlaceholder => !ShowEmptySceneHint && ActiveBackgroundImage == null;
|
||||
public bool ShowSourcesEmptyHint => ActiveScene == null || ActiveScene.Sources.Count == 0;
|
||||
|
||||
// Paid unlock flips this off (see ai.md "Monetization"). When disabled the
|
||||
// cadence timer is stopped and any active flash is hidden immediately.
|
||||
public bool BrandFlashEnabled
|
||||
{
|
||||
get => _brandFlashEnabled;
|
||||
set
|
||||
{
|
||||
if (!SetProperty(ref _brandFlashEnabled, value)) return;
|
||||
if (value)
|
||||
{
|
||||
if (IsLive) StartBrandFlashTimer();
|
||||
}
|
||||
else
|
||||
{
|
||||
_brandFlashTimer.Stop();
|
||||
_brandFlashOffTimer.Stop();
|
||||
BrandFlashActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool BrandFlashActive
|
||||
{
|
||||
get => _brandFlashActive;
|
||||
private set => SetProperty(ref _brandFlashActive, value);
|
||||
}
|
||||
|
||||
private void UpdateActiveBackground()
|
||||
{
|
||||
var background = ActiveScene?.Sources.FirstOrDefault(s => s.Type == SourceType.Background);
|
||||
@@ -356,6 +391,12 @@ public class MainViewModel : ViewModelBase
|
||||
|
||||
_saveDebounce = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(1500) };
|
||||
_saveDebounce.Tick += (_, _) => SaveLayoutNow();
|
||||
|
||||
_brandFlashTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(300) };
|
||||
_brandFlashTimer.Tick += OnBrandFlashTimerTick;
|
||||
_brandFlashOffTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(750) };
|
||||
_brandFlashOffTimer.Tick += (_, _) => { _brandFlashOffTimer.Stop(); BrandFlashActive = false; };
|
||||
|
||||
Scenes.CollectionChanged += OnScenesChanged;
|
||||
|
||||
AddSceneCommand = new RelayCommand(_ => AddScene());
|
||||
@@ -852,15 +893,44 @@ public class MainViewModel : ViewModelBase
|
||||
LiveElapsedText = "00:00:00";
|
||||
LivePulseOpacity = 1.0;
|
||||
_liveTimer.Start();
|
||||
if (BrandFlashEnabled) StartBrandFlashTimer();
|
||||
}
|
||||
else
|
||||
{
|
||||
_liveTimer.Stop();
|
||||
_brandFlashTimer.Stop();
|
||||
_brandFlashOffTimer.Stop();
|
||||
BrandFlashActive = false;
|
||||
LiveElapsedText = "00:00:00";
|
||||
LivePulseOpacity = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
// First flash shortly after go-live, then every 300s (the cadence resets on
|
||||
// the first tick so the interval is 5s only for that one shot).
|
||||
private void StartBrandFlashTimer()
|
||||
{
|
||||
_brandFlashTimer.Stop();
|
||||
_brandFlashTimer.Interval = TimeSpan.FromSeconds(5);
|
||||
_brandFlashTimer.Start();
|
||||
}
|
||||
|
||||
private void OnBrandFlashTimerTick(object? sender, EventArgs e)
|
||||
{
|
||||
_brandFlashTimer.Stop();
|
||||
_brandFlashTimer.Interval = TimeSpan.FromSeconds(300);
|
||||
_brandFlashTimer.Start();
|
||||
ShowBrandFlash();
|
||||
}
|
||||
|
||||
private void ShowBrandFlash()
|
||||
{
|
||||
if (!IsLive || !BrandFlashEnabled) return;
|
||||
BrandFlashActive = true;
|
||||
_brandFlashOffTimer.Stop();
|
||||
_brandFlashOffTimer.Start();
|
||||
}
|
||||
|
||||
private void OnLiveTimerTick(object? sender, EventArgs e)
|
||||
{
|
||||
_liveElapsed = _liveElapsed.Add(TimeSpan.FromSeconds(1));
|
||||
|
||||
Reference in New Issue
Block a user