mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-23 01:44:26 +08:00
0.1.5
This commit is contained in:
62
LanMontainDesktop/Services/AppSettingsService.cs
Normal file
62
LanMontainDesktop/Services/AppSettingsService.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using LanMontainDesktop.Models;
|
||||
|
||||
namespace LanMontainDesktop.Services;
|
||||
|
||||
public sealed class AppSettingsService
|
||||
{
|
||||
private static readonly JsonSerializerOptions SerializerOptions = new()
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
private readonly string _settingsPath;
|
||||
|
||||
public AppSettingsService()
|
||||
{
|
||||
var appData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
var settingsDirectory = Path.Combine(appData, "LanMontainDesktop");
|
||||
_settingsPath = Path.Combine(settingsDirectory, "settings.json");
|
||||
}
|
||||
|
||||
public AppSettingsSnapshot Load()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(_settingsPath))
|
||||
{
|
||||
return new AppSettingsSnapshot();
|
||||
}
|
||||
|
||||
var json = File.ReadAllText(_settingsPath);
|
||||
var snapshot = JsonSerializer.Deserialize<AppSettingsSnapshot>(json, SerializerOptions);
|
||||
return snapshot ?? new AppSettingsSnapshot();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new AppSettingsSnapshot();
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(AppSettingsSnapshot snapshot)
|
||||
{
|
||||
try
|
||||
{
|
||||
var directory = Path.GetDirectoryName(_settingsPath);
|
||||
if (!string.IsNullOrWhiteSpace(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
var json = JsonSerializer.Serialize(snapshot, SerializerOptions);
|
||||
File.WriteAllText(_settingsPath, json);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Swallow persistence errors to keep UI interactions uninterrupted.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,50 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using LanMontainDesktop.Theme;
|
||||
|
||||
namespace LanMontainDesktop.Services;
|
||||
|
||||
public static class GlassEffectService
|
||||
{
|
||||
public static void ApplyGlassResources(IResourceDictionary resources, bool isLightBackground)
|
||||
{
|
||||
if (isLightBackground)
|
||||
{
|
||||
resources["AdaptiveButtonBackgroundBrush"] = new SolidColorBrush(Color.Parse("#80FFFFFF"));
|
||||
resources["AdaptiveButtonBorderBrush"] = new SolidColorBrush(Color.Parse("#80475569"));
|
||||
resources["AdaptiveButtonHoverBackgroundBrush"] = new SolidColorBrush(Color.Parse("#B3FFFFFF"));
|
||||
resources["AdaptiveButtonPressedBackgroundBrush"] = new SolidColorBrush(Color.Parse("#D9F8FAFC"));
|
||||
resources["AdaptiveGlassPanelBackgroundBrush"] = new SolidColorBrush(Color.Parse("#A6FFFFFF"));
|
||||
resources["AdaptiveGlassPanelBorderBrush"] = new SolidColorBrush(Color.Parse("#80475569"));
|
||||
resources["AdaptiveGlassStrongBackgroundBrush"] = new SolidColorBrush(Color.Parse("#CCFFFFFF"));
|
||||
resources["AdaptiveGlassStrongBorderBrush"] = new SolidColorBrush(Color.Parse("#80475569"));
|
||||
return;
|
||||
}
|
||||
private const double DayPanelBlurRadius = 40;
|
||||
private const double DayStrongBlurRadius = 60;
|
||||
private const double DayOverlayBlurRadius = 80;
|
||||
private const double NightPanelBlurRadius = 45;
|
||||
private const double NightStrongBlurRadius = 65;
|
||||
private const double NightOverlayBlurRadius = 85;
|
||||
|
||||
resources["AdaptiveButtonBackgroundBrush"] = new SolidColorBrush(Color.Parse("#66334155"));
|
||||
resources["AdaptiveButtonBorderBrush"] = new SolidColorBrush(Color.Parse("#80E2E8F0"));
|
||||
resources["AdaptiveButtonHoverBackgroundBrush"] = new SolidColorBrush(Color.Parse("#88475A74"));
|
||||
resources["AdaptiveButtonPressedBackgroundBrush"] = new SolidColorBrush(Color.Parse("#AA2A3B55"));
|
||||
resources["AdaptiveGlassPanelBackgroundBrush"] = new SolidColorBrush(Color.Parse("#70233448"));
|
||||
resources["AdaptiveGlassPanelBorderBrush"] = new SolidColorBrush(Color.Parse("#70475569"));
|
||||
resources["AdaptiveGlassStrongBackgroundBrush"] = new SolidColorBrush(Color.Parse("#A01E293B"));
|
||||
resources["AdaptiveGlassStrongBorderBrush"] = new SolidColorBrush(Color.Parse("#80475569"));
|
||||
public static void ApplyGlassResources(IResourceDictionary resources, ThemeColorContext context)
|
||||
{
|
||||
var neutralBase = context.IsNightMode ? Color.Parse("#FF0B1220") : Color.Parse("#FFF8FAFC");
|
||||
var neutralElevated = context.IsNightMode ? Color.Parse("#FF1E293B") : Color.Parse("#FFFFFFFF");
|
||||
var tintMix = context.IsNightMode ? 0.15 : 0.08;
|
||||
var panelTone = ColorMath.Blend(neutralElevated, context.AccentColor, tintMix);
|
||||
var strongTone = ColorMath.Blend(neutralBase, context.AccentColor, context.IsNightMode ? 0.18 : 0.12);
|
||||
var overlayTone = ColorMath.Blend(neutralBase, context.AccentColor, context.IsNightMode ? 0.25 : 0.15);
|
||||
|
||||
resources["AdaptiveButtonBackgroundBrush"] = new SolidColorBrush(
|
||||
ColorMath.WithAlpha(panelTone, context.IsNightMode ? (byte)0x66 : (byte)0x80));
|
||||
resources["AdaptiveButtonBorderBrush"] = new SolidColorBrush(ColorMath.WithAlpha(neutralElevated, 0x1A));
|
||||
resources["AdaptiveButtonHoverBackgroundBrush"] = new SolidColorBrush(
|
||||
ColorMath.WithAlpha(ColorMath.Blend(panelTone, context.AccentColor, 0.15), context.IsNightMode ? (byte)0x7A : (byte)0x99));
|
||||
resources["AdaptiveButtonPressedBackgroundBrush"] = new SolidColorBrush(
|
||||
ColorMath.WithAlpha(ColorMath.Blend(panelTone, context.AccentColor, 0.28), context.IsNightMode ? (byte)0x8C : (byte)0xB3));
|
||||
|
||||
resources["AdaptiveGlassPanelBackgroundBrush"] = new SolidColorBrush(
|
||||
ColorMath.WithAlpha(panelTone, context.IsNightMode ? (byte)0x4D : (byte)0x66));
|
||||
resources["AdaptiveGlassPanelBorderBrush"] = new SolidColorBrush(ColorMath.WithAlpha(neutralElevated, 0x26));
|
||||
resources["AdaptiveGlassStrongBackgroundBrush"] = new SolidColorBrush(
|
||||
ColorMath.WithAlpha(strongTone, context.IsNightMode ? (byte)0x66 : (byte)0x80));
|
||||
resources["AdaptiveGlassStrongBorderBrush"] = new SolidColorBrush(ColorMath.WithAlpha(neutralElevated, 0x33));
|
||||
resources["AdaptiveGlassOverlayBackgroundBrush"] = new SolidColorBrush(
|
||||
ColorMath.WithAlpha(overlayTone, context.IsNightMode ? (byte)0x59 : (byte)0x73));
|
||||
|
||||
resources["AdaptiveGlassPanelBlurRadius"] = context.IsNightMode ? NightPanelBlurRadius : DayPanelBlurRadius;
|
||||
resources["AdaptiveGlassStrongBlurRadius"] = context.IsNightMode ? NightStrongBlurRadius : DayStrongBlurRadius;
|
||||
resources["AdaptiveGlassOverlayBlurRadius"] = context.IsNightMode ? NightOverlayBlurRadius : DayOverlayBlurRadius;
|
||||
resources["AdaptiveGlassPanelOpacity"] = context.IsNightMode ? 0.85 : 0.80;
|
||||
resources["AdaptiveGlassStrongOpacity"] = context.IsNightMode ? 0.90 : 0.85;
|
||||
resources["AdaptiveGlassOverlayOpacity"] = context.IsNightMode ? 0.75 : 0.70;
|
||||
resources["AdaptiveGlassNoiseOpacity"] = context.IsNightMode ? 0.03 : 0.02;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using LanMontainDesktop.Theme;
|
||||
@@ -7,21 +6,50 @@ namespace LanMontainDesktop.Services;
|
||||
|
||||
public static class ThemeColorSystemService
|
||||
{
|
||||
private const double WcagNormalTextContrast = 4.5;
|
||||
private const double WcagLargeTextContrast = 3.0;
|
||||
|
||||
public static void ApplyThemeResources(
|
||||
IResourceDictionary resources,
|
||||
ThemeColorContext context)
|
||||
{
|
||||
var palette = BuildPalette(context);
|
||||
|
||||
resources["AdaptivePrimaryBrush"] = new SolidColorBrush(palette.Primary);
|
||||
resources["AdaptiveSecondaryBrush"] = new SolidColorBrush(palette.Secondary);
|
||||
resources["AdaptiveAccentBrush"] = new SolidColorBrush(palette.Accent);
|
||||
resources["AdaptiveOnAccentBrush"] = new SolidColorBrush(palette.OnAccent);
|
||||
resources["AdaptiveSurfaceBaseBrush"] = new SolidColorBrush(palette.SurfaceBase);
|
||||
resources["AdaptiveSurfaceRaisedBrush"] = new SolidColorBrush(palette.SurfaceRaised);
|
||||
resources["AdaptiveSurfaceOverlayBrush"] = new SolidColorBrush(palette.SurfaceOverlay);
|
||||
resources["AdaptiveTextPrimaryBrush"] = new SolidColorBrush(palette.TextPrimary);
|
||||
resources["AdaptiveTextSecondaryBrush"] = new SolidColorBrush(palette.TextSecondary);
|
||||
resources["AdaptiveTextMutedBrush"] = new SolidColorBrush(palette.TextMuted);
|
||||
resources["AdaptiveTextAccentBrush"] = new SolidColorBrush(palette.TextAccent);
|
||||
resources["AdaptiveNavTextBrush"] = new SolidColorBrush(palette.NavText);
|
||||
resources["AdaptiveNavSelectedTextBrush"] = new SolidColorBrush(palette.NavSelectedText);
|
||||
resources["AdaptiveNavSelectionIndicatorBrush"] = new SolidColorBrush(palette.NavSelectionIndicator);
|
||||
resources["AdaptiveNavItemBackgroundBrush"] = new SolidColorBrush(palette.NavItemBackground);
|
||||
resources["AdaptiveNavItemHoverBackgroundBrush"] = new SolidColorBrush(palette.NavItemHoverBackground);
|
||||
resources["AdaptiveNavItemSelectedBackgroundBrush"] = new SolidColorBrush(palette.NavItemSelectedBackground);
|
||||
resources["AdaptiveToggleOnBrush"] = new SolidColorBrush(palette.ToggleOn);
|
||||
resources["AdaptiveToggleOffBrush"] = new SolidColorBrush(palette.ToggleOff);
|
||||
resources["AdaptiveToggleBorderBrush"] = new SolidColorBrush(palette.ToggleBorder);
|
||||
|
||||
resources["SystemAccentColor"] = palette.Accent;
|
||||
resources["SystemAccentColorLight1"] = palette.AccentLight1;
|
||||
resources["SystemAccentColorLight2"] = palette.AccentLight2;
|
||||
resources["SystemAccentColorLight3"] = palette.AccentLight3;
|
||||
resources["SystemAccentColorDark1"] = palette.AccentDark1;
|
||||
resources["SystemAccentColorDark2"] = palette.AccentDark2;
|
||||
resources["SystemAccentColorDark3"] = palette.AccentDark3;
|
||||
resources["SystemAccentColorLight1Brush"] = new SolidColorBrush(palette.AccentLight1);
|
||||
resources["SystemAccentColorLight2Brush"] = new SolidColorBrush(palette.AccentLight2);
|
||||
resources["SystemAccentColorLight3Brush"] = new SolidColorBrush(palette.AccentLight3);
|
||||
resources["SystemAccentColorDark1Brush"] = new SolidColorBrush(palette.AccentDark1);
|
||||
resources["SystemAccentColorDark2Brush"] = new SolidColorBrush(palette.AccentDark2);
|
||||
resources["SystemAccentColorDark3Brush"] = new SolidColorBrush(palette.AccentDark3);
|
||||
resources["SystemAccentColorBrush"] = new SolidColorBrush(palette.Accent);
|
||||
}
|
||||
|
||||
public static void ApplyThemeResources(
|
||||
@@ -39,42 +67,81 @@ public static class ThemeColorSystemService
|
||||
|
||||
private static AppThemePalette BuildPalette(ThemeColorContext context)
|
||||
{
|
||||
var textPrimary = context.IsLightBackground ? Color.Parse("#FF0B1220") : Color.Parse("#FFF8FAFC");
|
||||
var textSecondary = context.IsLightBackground ? Color.Parse("#FF1E293B") : Color.Parse("#FFE2E8F0");
|
||||
var textMuted = context.IsLightBackground ? Color.Parse("#FF475569") : Color.Parse("#FF94A3B8");
|
||||
var textAccent = context.IsLightBackground
|
||||
? BlendColor(context.AccentColor, Color.Parse("#FF0B1220"), 0.20)
|
||||
: BlendColor(context.AccentColor, Color.Parse("#FFFFFFFF"), 0.16);
|
||||
var accent = context.AccentColor;
|
||||
var accentLight1 = ColorMath.Blend(accent, Color.Parse("#FFFFFFFF"), 0.22);
|
||||
var accentLight2 = ColorMath.Blend(accent, Color.Parse("#FFFFFFFF"), 0.38);
|
||||
var accentLight3 = ColorMath.Blend(accent, Color.Parse("#FFFFFFFF"), 0.54);
|
||||
var accentDark1 = ColorMath.Blend(accent, Color.Parse("#FF0B1220"), 0.16);
|
||||
var accentDark2 = ColorMath.Blend(accent, Color.Parse("#FF0B1220"), 0.28);
|
||||
var accentDark3 = ColorMath.Blend(accent, Color.Parse("#FF020617"), 0.40);
|
||||
|
||||
var navText = context.IsLightNavBackground ? Color.Parse("#FF0B1220") : Color.Parse("#FFF8FAFC");
|
||||
var navSelectedText = Color.Parse("#FFFFFFFF");
|
||||
var navItemBackground = context.IsLightNavBackground ? Color.Parse("#40FFFFFF") : Color.Parse("#220F172A");
|
||||
var navItemHoverBackground = context.IsLightNavBackground ? Color.Parse("#66E2E8F0") : Color.Parse("#40334155");
|
||||
var navItemSelectedBackground = Color.FromArgb(
|
||||
0xCC,
|
||||
context.AccentColor.R,
|
||||
context.AccentColor.G,
|
||||
context.AccentColor.B);
|
||||
var primary = context.IsNightMode ? accentLight1 : accentDark1;
|
||||
var secondary = context.IsNightMode ? accentLight2 : accentDark2;
|
||||
|
||||
var surfaceBase = context.IsNightMode ? Color.Parse("#FF0B1220") : Color.Parse("#FFF3F7FB");
|
||||
var surfaceRaised = context.IsNightMode ? Color.Parse("#FF1E293B") : Color.Parse("#FFFFFFFF");
|
||||
var surfaceOverlay = context.IsNightMode ? Color.Parse("#CC0B1220") : Color.Parse("#CCE2E8F0");
|
||||
|
||||
var textPrimaryPreferred = context.IsLightBackground ? Color.Parse("#FF0B1220") : Color.Parse("#FFF8FAFC");
|
||||
var textPrimary = ColorMath.EnsureContrast(textPrimaryPreferred, surfaceRaised, WcagNormalTextContrast);
|
||||
var textSecondary = ColorMath.EnsureContrast(
|
||||
ColorMath.Blend(textPrimary, surfaceRaised, context.IsNightMode ? 0.24 : 0.44),
|
||||
surfaceRaised,
|
||||
WcagLargeTextContrast);
|
||||
var textMuted = ColorMath.EnsureContrast(
|
||||
ColorMath.Blend(textPrimary, surfaceRaised, context.IsNightMode ? 0.40 : 0.58),
|
||||
surfaceRaised,
|
||||
WcagLargeTextContrast);
|
||||
var textAccent = context.IsLightBackground
|
||||
? ColorMath.EnsureContrast(ColorMath.Blend(accent, Color.Parse("#FF0B1220"), 0.20), surfaceRaised, WcagNormalTextContrast)
|
||||
: ColorMath.EnsureContrast(ColorMath.Blend(accent, Color.Parse("#FFFFFFFF"), 0.16), surfaceRaised, WcagNormalTextContrast);
|
||||
|
||||
var navSurface = context.IsLightNavBackground ? surfaceRaised : Color.Parse("#FF111827");
|
||||
var navText = ColorMath.EnsureContrast(
|
||||
context.IsLightNavBackground ? Color.Parse("#FF0B1220") : Color.Parse("#FFF8FAFC"),
|
||||
navSurface,
|
||||
WcagNormalTextContrast);
|
||||
|
||||
var selectedSurfaceForContrast = ColorMath.Blend(accent, navSurface, 0.18);
|
||||
var navSelectedText = ColorMath.EnsureContrast(Color.Parse("#FFFFFFFF"), selectedSurfaceForContrast, WcagNormalTextContrast);
|
||||
var navItemBackground = context.IsLightNavBackground ? Color.Parse("#33FFFFFF") : Color.Parse("#2A0F172A");
|
||||
var navItemHoverBackground = context.IsLightNavBackground
|
||||
? ColorMath.WithAlpha(ColorMath.Blend(accentLight2, Color.Parse("#FFFFFFFF"), 0.48), 0x66)
|
||||
: ColorMath.WithAlpha(ColorMath.Blend(accentDark1, Color.Parse("#33111827"), 0.32), 0x78);
|
||||
var navItemSelectedBackground = ColorMath.WithAlpha(accent, context.IsNightMode ? (byte)0xCE : (byte)0xD9);
|
||||
var navSelectionIndicator = ColorMath.EnsureContrast(accentLight1, navSurface, WcagLargeTextContrast);
|
||||
|
||||
var toggleOn = context.IsNightMode ? accent : accentDark1;
|
||||
var toggleOff = context.IsNightMode ? Color.Parse("#66475569") : Color.Parse("#66CBD5E1");
|
||||
var toggleBorder = context.IsNightMode ? Color.Parse("#80E2E8F0") : Color.Parse("#8094A3B8");
|
||||
var onAccent = ColorMath.EnsureContrast(Color.Parse("#FFFFFFFF"), accent, WcagNormalTextContrast);
|
||||
|
||||
return new AppThemePalette(
|
||||
primary,
|
||||
secondary,
|
||||
accent,
|
||||
onAccent,
|
||||
accentLight1,
|
||||
accentLight2,
|
||||
accentLight3,
|
||||
accentDark1,
|
||||
accentDark2,
|
||||
accentDark3,
|
||||
surfaceBase,
|
||||
surfaceRaised,
|
||||
surfaceOverlay,
|
||||
textPrimary,
|
||||
textSecondary,
|
||||
textMuted,
|
||||
textAccent,
|
||||
navText,
|
||||
navSelectedText,
|
||||
navSelectionIndicator,
|
||||
navItemBackground,
|
||||
navItemHoverBackground,
|
||||
navItemSelectedBackground);
|
||||
}
|
||||
|
||||
private static Color BlendColor(Color from, Color to, double ratio)
|
||||
{
|
||||
ratio = Math.Clamp(ratio, 0, 1);
|
||||
var inverse = 1 - ratio;
|
||||
var red = (byte)Math.Round((from.R * inverse) + (to.R * ratio));
|
||||
var green = (byte)Math.Round((from.G * inverse) + (to.G * ratio));
|
||||
var blue = (byte)Math.Round((from.B * inverse) + (to.B * ratio));
|
||||
return Color.FromRgb(red, green, blue);
|
||||
navItemSelectedBackground,
|
||||
toggleOn,
|
||||
toggleOff,
|
||||
toggleBorder);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user