< Summary

Information
Class: MyNet.UI.Theming.ThemeManager
Assembly: MyNet.UI
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.UI/Theming/ThemeManager.cs
Tag: 323_28699572109
Line coverage
54%
Covered lines: 30
Uncovered lines: 25
Coverable lines: 55
Total lines: 207
Line coverage: 54.5%
Branch coverage
44%
Covered branches: 8
Total branches: 18
Branch coverage: 44.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
get_IsConfigured()100%11100%
get_CurrentTheme()50%22100%
Configure(...)75%4492.3%
add_ThemeChanged(...)50%4475%
remove_ThemeChanged(...)0%2040%
get_Dark()100%210%
get_Light()100%210%
get_HighContrast()100%210%
get_AvailableBases()100%210%
GetBase(...)100%210%
Register(...)100%210%
ApplyBase(...)100%11100%
ApplyPrimaryColor(...)100%210%
ApplyPrimaryColor(...)100%210%
ApplyAccentColor(...)100%210%
ApplyAccentColor(...)100%210%
ApplyTheme(...)100%210%
UpdateTheme(...)100%210%
GetThemeService()100%22100%
GetThemeBaseRegistry()0%620%
ResetForTesting()100%11100%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.UI/Theming/ThemeManager.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="ThemeManager.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System;
 8using System.Collections.Generic;
 9using System.Threading;
 10
 11namespace MyNet.UI.Theming;
 12
 13/// <summary>
 14/// Static bridge to <see cref="IThemeService"/> and <see cref="IThemeBaseRegistry"/> for legacy or view-layer code
 15/// that cannot receive dependencies. Prefer injecting <see cref="IThemeService"/> in new code.
 16/// Configure once at startup via <see cref="Configure"/> or <see cref="ServiceCollectionExtensions.UseThemeManager"/>.
 17/// </summary>
 18public static class ThemeManager
 19{
 320    private static readonly List<EventHandler<ThemeChangedEventArgs>> PendingThemeChangedHandlers = [];
 21    private static int _configured;
 22    private static IThemeService? _themeService;
 23    private static IThemeBaseRegistry? _themeBaseRegistry;
 24
 25    /// <summary>
 26    /// Gets a value indicating whether <see cref="Configure"/> has been called.
 27    /// </summary>
 1228    public static bool IsConfigured => Volatile.Read(ref _configured) == 1;
 29
 30    /// <summary>
 31    /// Gets the current theme applied to the application.
 32    /// </summary>
 333    public static Theme? CurrentTheme => IsConfigured ? GetThemeService().CurrentTheme : null;
 34
 35    /// <summary>
 36    /// Configures the static bridge with services resolved from dependency injection.
 37    /// </summary>
 38    /// <param name="themeService">The service used to manage themes.</param>
 39    /// <param name="themeBaseRegistry">The registry used to manage theme bases.</param>
 40    /// <exception cref="ArgumentNullException">Thrown when a required argument is null.</exception>
 41    public static void Configure(IThemeService themeService, IThemeBaseRegistry themeBaseRegistry)
 42    {
 943        ArgumentNullException.ThrowIfNull(themeService);
 944        ArgumentNullException.ThrowIfNull(themeBaseRegistry);
 45
 946        if (Interlocked.Exchange(ref _configured, 1) == 1)
 047            return;
 48
 949        _themeService = themeService;
 950        _themeBaseRegistry = themeBaseRegistry;
 51
 52        EventHandler<ThemeChangedEventArgs>[] pending;
 953        lock (PendingThemeChangedHandlers)
 54        {
 955            pending = [.. PendingThemeChangedHandlers];
 956            PendingThemeChangedHandlers.Clear();
 957        }
 58
 2459        foreach (var handler in pending)
 360            themeService.ThemeChanged += handler;
 961    }
 62
 63    /// <summary>
 64    /// Occurs when the theme is changed.
 65    /// </summary>
 66    public static event EventHandler<ThemeChangedEventArgs>? ThemeChanged
 67    {
 68        add
 69        {
 370            if (value is null)
 71            {
 072                return;
 73            }
 74
 375            if (_themeService is not null)
 76            {
 077                _themeService.ThemeChanged += value;
 78            }
 79            else
 80            {
 381                lock (PendingThemeChangedHandlers)
 82                {
 383                    PendingThemeChangedHandlers.Add(value);
 384                }
 85            }
 386        }
 87
 88        remove
 89        {
 090            if (value is null)
 91            {
 092                return;
 93            }
 94
 095            if (_themeService is not null)
 96            {
 097                _themeService.ThemeChanged -= value;
 98            }
 99            else
 100            {
 0101                lock (PendingThemeChangedHandlers)
 102                {
 0103                    PendingThemeChangedHandlers.Remove(value);
 0104                }
 105            }
 0106        }
 107    }
 108
 109    /// <summary>
 110    /// Gets the default dark base theme.
 111    /// </summary>
 0112    public static IThemeBase Dark => GetThemeBaseRegistry().Dark;
 113
 114    /// <summary>
 115    /// Gets the default light base theme.
 116    /// </summary>
 0117    public static IThemeBase Light => GetThemeBaseRegistry().Light;
 118
 119    /// <summary>
 120    /// Gets the default high contrast base theme.
 121    /// </summary>
 0122    public static IThemeBase HighContrast => GetThemeBaseRegistry().HighContrast;
 123
 124    /// <summary>
 125    /// Gets the collection of registered theme bases.
 126    /// </summary>
 0127    public static IReadOnlyCollection<IThemeBase> AvailableBases => GetThemeBaseRegistry().AvailableBases;
 128
 129    /// <summary>
 130    /// Gets the base theme with the specified name.
 131    /// </summary>
 132    /// <param name="name">The name of the base theme to retrieve.</param>
 133    /// <returns>The base theme with the specified name, or null if not found.</returns>
 0134    public static IThemeBase? GetBase(string name) => GetThemeBaseRegistry().Get(name);
 135
 136    /// <summary>
 137    /// Registers the specified theme base.
 138    /// </summary>
 139    /// <param name="themeBase">The theme base to register.</param>
 0140    public static void Register(IThemeBase themeBase) => GetThemeBaseRegistry().Register(themeBase);
 141
 142    /// <summary>
 143    /// Applies the specified base theme.
 144    /// </summary>
 145    /// <param name="themeBase">The base theme to apply.</param>
 3146    public static void ApplyBase(IThemeBase themeBase) => GetThemeService().ApplyBaseTheme(themeBase);
 147
 148    /// <summary>
 149    /// Applies the specified primary color.
 150    /// </summary>
 151    /// <param name="color">The primary color to apply.</param>
 0152    public static void ApplyPrimaryColor(string color) => ApplyPrimaryColor(color, null);
 153
 154    /// <summary>
 155    /// Applies the specified primary color and foreground color.
 156    /// </summary>
 157    /// <param name="color">The primary color to apply.</param>
 158    /// <param name="foreground">The foreground color for the primary color.</param>
 159    public static void ApplyPrimaryColor(string color, string? foreground)
 0160        => GetThemeService().ApplyPrimary(color, foreground);
 161
 162    /// <summary>
 163    /// Applies the specified accent color.
 164    /// </summary>
 165    /// <param name="color">The accent color to apply.</param>
 0166    public static void ApplyAccentColor(string color) => ApplyAccentColor(color, null);
 167
 168    /// <summary>
 169    /// Applies the specified accent color and foreground color.
 170    /// </summary>
 171    /// <param name="color">The accent color to apply.</param>
 172    /// <param name="foreground">The foreground color for the accent color.</param>
 173    public static void ApplyAccentColor(string color, string? foreground)
 0174        => GetThemeService().ApplyAccent(color, foreground);
 175
 176    /// <summary>
 177    /// Applies the specified theme configuration.
 178    /// </summary>
 179    /// <param name="theme">The theme to apply.</param>
 0180    public static void ApplyTheme(Theme theme) => GetThemeService().ApplyTheme(theme);
 181
 182    /// <summary>
 183    /// Updates the current theme using the specified transform and applies the result.
 184    /// </summary>
 185    /// <param name="update">Transforms the current theme into the theme to apply.</param>
 0186    public static void UpdateTheme(Func<Theme, Theme> update) => GetThemeService().UpdateTheme(update);
 187
 6188    private static IThemeService GetThemeService() => _themeService ?? throw new InvalidOperationException(
 6189        "ThemeManager is not configured. Register IThemeService and IThemeBaseRegistry, then call ThemeManager.Configure
 190
 0191    private static IThemeBaseRegistry GetThemeBaseRegistry() => _themeBaseRegistry ?? throw new InvalidOperationExceptio
 0192        "ThemeManager is not configured. Register IThemeService and IThemeBaseRegistry, then call ThemeManager.Configure
 193
 194    /// <summary>
 195    /// Resets configuration. For unit tests only.
 196    /// </summary>
 197    internal static void ResetForTesting()
 198    {
 30199        Interlocked.Exchange(ref _configured, 0);
 30200        _themeService = null;
 30201        _themeBaseRegistry = null;
 202
 30203        lock (PendingThemeChangedHandlers)
 30204            PendingThemeChangedHandlers.Clear();
 30205    }
 206}
 207