v0.3.0: CI dotnet 8.0.424 pinned with isolated install
- Pin .NET SDK to 8.0.424 in all CI jobs to avoid floating channel drift - Install SDK to runner temp via DOTNET_INSTALL_DIR to bypass C:\\Program Files\\dotnet overwrite/extract conflicts on Gitea Windows runners - Simplify release job to dotnet publish + upload-artifact - Exclude memory-bank/ via .gitignore (internal dev memory stays local)
This commit is contained in:
18 files changed
+4122
No files matched your search
@@ -0,0 +1,140 @@
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using RgbLedStripController.Core;
|
||||
using MediaColor = System.Windows.Media.Color;
|
||||
|
||||
namespace RgbLedStripController.Services;
|
||||
|
||||
public sealed class SettingsStore
|
||||
{
|
||||
private readonly string _settingsPath;
|
||||
private readonly SemaphoreSlim _writeLock = new(1, 1);
|
||||
private readonly JsonSerializerOptions _jsonOptions = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
public SettingsStore()
|
||||
{
|
||||
var settingsDirectory = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"RgbLedStripController");
|
||||
|
||||
_settingsPath = Path.Combine(settingsDirectory, "settings.json");
|
||||
}
|
||||
|
||||
public async Task<SettingsSnapshot> LoadAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!File.Exists(_settingsPath))
|
||||
{
|
||||
return CreateDefaultSnapshot();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await using var stream = File.OpenRead(_settingsPath);
|
||||
var stored = await JsonSerializer.DeserializeAsync<StoredSettings>(stream, _jsonOptions, cancellationToken);
|
||||
|
||||
return new SettingsSnapshot(
|
||||
stored?.KnownDevices ?? [],
|
||||
new Dictionary<string, string>(stored?.DeviceAliases ?? new Dictionary<string, string>(), StringComparer.OrdinalIgnoreCase),
|
||||
ParseColor(stored?.SelectedColorHex),
|
||||
stored?.Brightness ?? 100,
|
||||
stored?.EffectSpeed ?? 50,
|
||||
stored?.CurrentMode ?? LightingMode.Rgb,
|
||||
stored?.GrayscaleLevel ?? 100,
|
||||
stored?.TemperatureLevel ?? 50,
|
||||
stored?.SelectedEffectId ?? 0,
|
||||
stored?.IsPoweredOn ?? false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return CreateDefaultSnapshot();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SaveAsync(SettingsSnapshot snapshot, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await _writeLock.WaitAsync(cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
var directory = Path.GetDirectoryName(_settingsPath);
|
||||
if (!string.IsNullOrWhiteSpace(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
await using var stream = File.Create(_settingsPath);
|
||||
var stored = new StoredSettings
|
||||
{
|
||||
KnownDevices = snapshot.KnownDevices.ToList(),
|
||||
DeviceAliases = new Dictionary<string, string>(snapshot.DeviceAliases, StringComparer.OrdinalIgnoreCase),
|
||||
SelectedColorHex = $"#{snapshot.SelectedColor.R:X2}{snapshot.SelectedColor.G:X2}{snapshot.SelectedColor.B:X2}",
|
||||
Brightness = snapshot.Brightness,
|
||||
EffectSpeed = snapshot.EffectSpeed,
|
||||
CurrentMode = snapshot.CurrentMode,
|
||||
GrayscaleLevel = snapshot.GrayscaleLevel,
|
||||
TemperatureLevel = snapshot.TemperatureLevel,
|
||||
SelectedEffectId = snapshot.SelectedEffectId,
|
||||
IsPoweredOn = snapshot.IsPoweredOn
|
||||
};
|
||||
|
||||
await JsonSerializer.SerializeAsync(stream, stored, _jsonOptions, cancellationToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_writeLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private static SettingsSnapshot CreateDefaultSnapshot()
|
||||
=> new(
|
||||
[],
|
||||
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase),
|
||||
MediaColor.FromRgb(255, 106, 78),
|
||||
100,
|
||||
50,
|
||||
LightingMode.Rgb,
|
||||
100,
|
||||
50,
|
||||
0,
|
||||
false);
|
||||
|
||||
private static MediaColor ParseColor(string? value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value) || value.Length != 7 || value[0] != '#')
|
||||
{
|
||||
return MediaColor.FromRgb(255, 106, 78);
|
||||
}
|
||||
|
||||
return MediaColor.FromRgb(
|
||||
Convert.ToByte(value.Substring(1, 2), 16),
|
||||
Convert.ToByte(value.Substring(3, 2), 16),
|
||||
Convert.ToByte(value.Substring(5, 2), 16));
|
||||
}
|
||||
|
||||
private sealed class StoredSettings
|
||||
{
|
||||
public List<DeviceProfile> KnownDevices { get; set; } = [];
|
||||
|
||||
public Dictionary<string, string> DeviceAliases { get; set; } = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public string? SelectedColorHex { get; set; }
|
||||
|
||||
public byte Brightness { get; set; }
|
||||
|
||||
public byte EffectSpeed { get; set; }
|
||||
|
||||
public LightingMode CurrentMode { get; set; }
|
||||
|
||||
public byte GrayscaleLevel { get; set; }
|
||||
|
||||
public byte TemperatureLevel { get; set; }
|
||||
|
||||
public byte SelectedEffectId { get; set; }
|
||||
|
||||
public bool IsPoweredOn { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user