Brand logo: one locked image layer per scene above the background, image from App Settings
- Source.IsBrandLogo persisted (additive migration); layer healed on load, removal blocked - Image stored as an asset; settings keep the asset id and file name - App Settings: Brand Logo file field with Browse - Default placement top-left; per-scene eye uses the existing element visibility Test: BrandLogoTests; layout/background tests pass (34). Not pushed.
This commit is contained in:
@@ -102,7 +102,7 @@ public partial class LayoutStore : IDisposable
|
||||
ChatShowTimestamps, ChatShowBadges, ChatMemberColor, ChatSuperChatColor,
|
||||
WebUri, MediaPath, MediaIsLooping, MediaVolume, MediaPlaybackState,
|
||||
AlertVideoAssetId, AlertVideoPath, AlertUseDefaultVideo, AlertShowTicker, AlertVideoVolume, SortOrder,
|
||||
AlertDisplayMethod
|
||||
AlertDisplayMethod, IsBrandLogo
|
||||
FROM Source ORDER BY SortOrder
|
||||
""";
|
||||
using var reader = cmd.ExecuteReader();
|
||||
@@ -154,6 +154,7 @@ public partial class LayoutStore : IDisposable
|
||||
AlertShowTicker = reader.IsDBNull(33) ? true : reader.GetInt32(33) != 0,
|
||||
AlertVideoVolume = reader.IsDBNull(34) ? 1.0 : reader.GetDouble(34),
|
||||
AlertDisplayMethod = reader.IsDBNull(36) ? AlertDisplayMethod.TickerScroll : (AlertDisplayMethod)reader.GetInt32(36),
|
||||
IsBrandLogo = reader.GetInt32(reader.GetOrdinal("IsBrandLogo")) != 0,
|
||||
};
|
||||
if (!sourcesByScene.TryGetValue(sceneId, out var list))
|
||||
sourcesByScene[sceneId] = list = new List<(Source, int)>();
|
||||
|
||||
@@ -199,6 +199,13 @@ public partial class LayoutStore : IDisposable
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
if (!columns.Contains("IsBrandLogo"))
|
||||
{
|
||||
using var cmd = _connection.CreateCommand();
|
||||
cmd.CommandText = "ALTER TABLE Source ADD COLUMN IsBrandLogo INTEGER NOT NULL DEFAULT 0;";
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
if (!columns.Contains("CaptureKey"))
|
||||
{
|
||||
using var cmd = _connection.CreateCommand();
|
||||
|
||||
@@ -92,7 +92,7 @@ public partial class LayoutStore : IDisposable
|
||||
ChatShowTimestamps, ChatShowBadges, ChatMemberColor, ChatSuperChatColor,
|
||||
WebUri, MediaPath, MediaIsLooping, MediaVolume, MediaPlaybackState,
|
||||
AlertVideoAssetId, AlertVideoPath, AlertUseDefaultVideo, AlertShowTicker, AlertVideoVolume,
|
||||
AlertDisplayMethod)
|
||||
AlertDisplayMethod, IsBrandLogo)
|
||||
VALUES ($id, $sceneId, $assetId, $type, $name, $isEnabled,
|
||||
$x, $y, $w, $h, $opacity, $monitor,
|
||||
$clip, $mirrored, $isBackground, $captureKey, $showDesktop, $sort,
|
||||
@@ -100,7 +100,7 @@ public partial class LayoutStore : IDisposable
|
||||
$chatTimestamps, $chatBadges, $chatMemberColor, $chatSuperChatColor,
|
||||
$webUri, $mediaPath, $mediaIsLooping, $mediaVolume, $mediaPlaybackState,
|
||||
$alertVideoAssetId, $alertVideoPath, $alertUseDefaultVideo, $alertShowTicker, $alertVideoVolume,
|
||||
$alertDisplayMethod)
|
||||
$alertDisplayMethod, $isBrandLogo)
|
||||
""";
|
||||
cmd.Transaction = tx;
|
||||
var idP = cmd.Parameters.Add("$id", SqliteType.Text);
|
||||
@@ -140,6 +140,7 @@ public partial class LayoutStore : IDisposable
|
||||
var alertShowTickerP = cmd.Parameters.Add("$alertShowTicker", SqliteType.Integer);
|
||||
var alertVideoVolumeP = cmd.Parameters.Add("$alertVideoVolume", SqliteType.Real);
|
||||
var alertDisplayMethodP = cmd.Parameters.Add("$alertDisplayMethod", SqliteType.Integer);
|
||||
var isBrandLogoP = cmd.Parameters.Add("$isBrandLogo", SqliteType.Integer);
|
||||
|
||||
// Source and WebcamSceneConfig share ONE z-order space per scene:
|
||||
// each element gets its index within scene.Elements regardless of
|
||||
@@ -188,6 +189,7 @@ public partial class LayoutStore : IDisposable
|
||||
alertShowTickerP.Value = source.AlertShowTicker ? 1 : 0;
|
||||
alertVideoVolumeP.Value = source.AlertVideoVolume;
|
||||
alertDisplayMethodP.Value = (int)source.AlertDisplayMethod;
|
||||
isBrandLogoP.Value = source.IsBrandLogo ? 1 : 0;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,4 +348,20 @@ public partial class LayoutStore : IDisposable
|
||||
|
||||
/// <summary>The stored on-air image's Asset id, or null when never stamped.</summary>
|
||||
public string? GetOnAirImageId() => GetSetting(OnAirImageKey);
|
||||
|
||||
private const string BrandLogoAssetKey = "BrandLogoAssetId";
|
||||
private const string BrandLogoNameKey = "BrandLogoFileName";
|
||||
|
||||
public string? GetBrandLogoAssetId() => GetSetting(BrandLogoAssetKey);
|
||||
|
||||
public string? GetBrandLogoFileName() => GetSetting(BrandLogoNameKey);
|
||||
|
||||
/// <summary>Stores the brand logo image as an asset and records its file name for display.</summary>
|
||||
public string SetBrandLogo(byte[] data, string fileName)
|
||||
{
|
||||
var id = UpsertAsset(data, 0, 0);
|
||||
UpsertSetting(BrandLogoAssetKey, id);
|
||||
UpsertSetting(BrandLogoNameKey, fileName);
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user