The state colours the view-models hand to bindings — top bar, REC/ON-AIR dots, health banner, meter bands, toast tints — were hex literals in C#. They now resolve from Themes/Tokens.xaml through `Helpers/ThemeBrush`, so the values live in one place. Without an Application (unit tests) the helper returns a neutral grey: visibly wrong rather than silently plausible. Four tokens the code needed and the document lacked, added to DESIGN.md (so the doc-is-the-contract guard demanded their brushes): info-container #3a3b52, success-container #1d5c38, warning-container #b8860b, test-container #9c6f1c (the test-stream gold bar). Also fixed by this: the top bar still painted the RETIRED brand red #e94560 when live — the standard's #ff5451 now, and `OnAirSignTests` (which pinned the old value) says so. BarOn/BarOff became properties rather than static fields, because a static field would resolve tokens before the Application exists. Verified: DesignTokensTests, GameMeterHonestyTests, NotificationAreaIntegrationTests, OnAirSignTests, SessionTeardownTests — 38 tests green.
41 lines
1.7 KiB
C#
41 lines
1.7 KiB
C#
using System.Windows;
|
|
using System.Windows.Media;
|
|
|
|
namespace ytLive.Helpers;
|
|
|
|
/// <summary>Resolves a design token for code that cannot bind — view-model state colours (the
|
|
/// top bar, the health banner, the meters, toast tints). The values live once, in
|
|
/// <c>Themes/Tokens.xaml</c>; this reads them from the application resources.
|
|
///
|
|
/// <para>Why not a Brush field per colour: a second list in C# would drift from the theme. Why not
|
|
/// OutputPalette: that one exists for the frame-pump thread, which must not touch resources; these
|
|
/// properties are read by bindings on the UI thread.</para>
|
|
///
|
|
/// <para>Without an Application (unit tests, design-time) a neutral grey comes back: visibly wrong
|
|
/// rather than silently plausible, and never a crash.</para></summary>
|
|
internal static class ThemeBrush
|
|
{
|
|
private static readonly SolidColorBrush Missing = Frozen(Color.FromRgb(0x80, 0x80, 0x80));
|
|
|
|
/// <summary>The brush for a token key, e.g. <c>ThemeBrush.Get("Brush.Primary")</c>.</summary>
|
|
public static SolidColorBrush Get(string key)
|
|
=> Application.Current?.TryFindResource(key) as SolidColorBrush ?? Missing;
|
|
|
|
/// <summary>The token's colour as a browser-style hex string, for APIs that take one
|
|
/// (Notification.Wpf's <c>NotificationColor.FromHex</c>, for instance).</summary>
|
|
public static string Hex(string key)
|
|
{
|
|
var c = Get(key).Color;
|
|
return c.A == 255
|
|
? $"#{c.R:x2}{c.G:x2}{c.B:x2}"
|
|
: $"#{c.A:x2}{c.R:x2}{c.G:x2}{c.B:x2}";
|
|
}
|
|
|
|
private static SolidColorBrush Frozen(Color colour)
|
|
{
|
|
var brush = new SolidColorBrush(colour);
|
|
brush.Freeze();
|
|
return brush;
|
|
}
|
|
}
|