mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
fix.修复设置页面
This commit is contained in:
@@ -0,0 +1,276 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using LanMountainDesktop.Appearance;
|
||||||
|
using LanMountainDesktop.Models;
|
||||||
|
using LanMountainDesktop.PluginSdk;
|
||||||
|
using LanMountainDesktop.Services;
|
||||||
|
using LanMountainDesktop.Services.Settings;
|
||||||
|
using LanMountainDesktop.Settings.Core;
|
||||||
|
using LanMountainDesktop.Shared.Contracts;
|
||||||
|
using LanMountainDesktop.ViewModels;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace LanMountainDesktop.Tests;
|
||||||
|
|
||||||
|
public sealed class MaterialColorSettingsPageViewModelTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Load_SelectsSavedNoneMaterialMode()
|
||||||
|
{
|
||||||
|
var facade = new FakeSettingsFacade(CreateThemeState(ThemeAppearanceValues.MaterialNone));
|
||||||
|
var materialService = new FakeMaterialColorService(CreateSnapshot(ThemeAppearanceValues.MaterialNone));
|
||||||
|
|
||||||
|
var viewModel = new MaterialColorSettingsPageViewModel(facade, materialService);
|
||||||
|
|
||||||
|
Assert.Equal(ThemeAppearanceValues.MaterialNone, viewModel.SelectedSystemMaterialMode.Value);
|
||||||
|
Assert.Contains(viewModel.SystemMaterialModes, option => option.Value == ThemeAppearanceValues.MaterialAuto);
|
||||||
|
Assert.Contains(viewModel.SystemMaterialModes, option => option.Value == ThemeAppearanceValues.MaterialNone);
|
||||||
|
Assert.Contains(viewModel.SystemMaterialModes, option => option.Value == ThemeAppearanceValues.MaterialMica);
|
||||||
|
Assert.Contains(viewModel.SystemMaterialModes, option => option.Value == ThemeAppearanceValues.MaterialAcrylic);
|
||||||
|
Assert.Equal(0, facade.ThemeSaveCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MaterialSnapshotRefresh_KeepsExplicitNoneSelection()
|
||||||
|
{
|
||||||
|
var facade = new FakeSettingsFacade(CreateThemeState(ThemeAppearanceValues.MaterialNone));
|
||||||
|
var materialService = new FakeMaterialColorService(CreateSnapshot(ThemeAppearanceValues.MaterialNone));
|
||||||
|
var viewModel = new MaterialColorSettingsPageViewModel(facade, materialService);
|
||||||
|
|
||||||
|
materialService.RaiseChanged(CreateSnapshot(ThemeAppearanceValues.MaterialAuto));
|
||||||
|
|
||||||
|
Assert.Equal(ThemeAppearanceValues.MaterialNone, viewModel.SelectedSystemMaterialMode.Value);
|
||||||
|
Assert.Equal(0, facade.ThemeSaveCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(ThemeAppearanceValues.MaterialNone)]
|
||||||
|
[InlineData(ThemeAppearanceValues.MaterialAuto)]
|
||||||
|
[InlineData(ThemeAppearanceValues.MaterialMica)]
|
||||||
|
[InlineData(ThemeAppearanceValues.MaterialAcrylic)]
|
||||||
|
public void UserSelection_SavesRequestedMaterialMode(string targetMode)
|
||||||
|
{
|
||||||
|
var initialMode = targetMode == ThemeAppearanceValues.MaterialNone
|
||||||
|
? ThemeAppearanceValues.MaterialAuto
|
||||||
|
: ThemeAppearanceValues.MaterialNone;
|
||||||
|
var facade = new FakeSettingsFacade(CreateThemeState(initialMode));
|
||||||
|
var materialService = new FakeMaterialColorService(CreateSnapshot(initialMode));
|
||||||
|
var viewModel = new MaterialColorSettingsPageViewModel(facade, materialService);
|
||||||
|
|
||||||
|
viewModel.SelectedSystemMaterialMode = viewModel.SystemMaterialModes.Single(option =>
|
||||||
|
option.Value == targetMode);
|
||||||
|
|
||||||
|
Assert.Equal(targetMode, facade.ThemeState.SystemMaterialMode);
|
||||||
|
Assert.Equal(1, facade.ThemeSaveCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ThemeAppearanceSettingsState CreateThemeState(string materialMode)
|
||||||
|
{
|
||||||
|
return new ThemeAppearanceSettingsState(
|
||||||
|
IsNightMode: false,
|
||||||
|
ThemeColor: "#FF445566",
|
||||||
|
UseSystemChrome: false,
|
||||||
|
CornerRadiusStyle: GlobalAppearanceSettings.CornerRadiusStyleRounded,
|
||||||
|
ThemeColorMode: ThemeAppearanceValues.ColorModeDefaultNeutral,
|
||||||
|
SystemMaterialMode: materialMode,
|
||||||
|
SelectedWallpaperSeed: null,
|
||||||
|
ThemeMode: ThemeAppearanceValues.ThemeModeLight,
|
||||||
|
ThemeWallpaperColorSource: ThemeAppearanceValues.WallpaperColorSourceAuto,
|
||||||
|
UseNativeWallpaperChangeEvents: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MaterialColorSnapshot CreateSnapshot(string materialMode)
|
||||||
|
{
|
||||||
|
var seed = Color.Parse("#FF3B82F6");
|
||||||
|
var palette = new LanMountainDesktop.Models.MaterialColorPalette(
|
||||||
|
seed,
|
||||||
|
Color.Parse("#FF64748B"),
|
||||||
|
seed,
|
||||||
|
Colors.White,
|
||||||
|
Color.Parse("#FF60A5FA"),
|
||||||
|
Color.Parse("#FF93C5FD"),
|
||||||
|
Color.Parse("#FFBFDBFE"),
|
||||||
|
Color.Parse("#FF2563EB"),
|
||||||
|
Color.Parse("#FF1D4ED8"),
|
||||||
|
Color.Parse("#FF1E40AF"),
|
||||||
|
Color.Parse("#FFF8FAFC"),
|
||||||
|
Color.Parse("#FFFFFFFF"),
|
||||||
|
Color.Parse("#FFF1F5F9"),
|
||||||
|
Color.Parse("#FF0F172A"),
|
||||||
|
Color.Parse("#FF334155"),
|
||||||
|
Color.Parse("#FF64748B"),
|
||||||
|
seed,
|
||||||
|
Color.Parse("#FF0F172A"),
|
||||||
|
Colors.White,
|
||||||
|
seed,
|
||||||
|
Color.Parse("#22000000"),
|
||||||
|
Color.Parse("#33000000"),
|
||||||
|
Color.Parse("#443B82F6"),
|
||||||
|
seed,
|
||||||
|
Color.Parse("#4464748B"),
|
||||||
|
Color.Parse("#663B82F6"));
|
||||||
|
var surface = new MaterialSurfaceSnapshot(
|
||||||
|
MaterialSurfaceRole.SettingsWindowBackground,
|
||||||
|
Color.Parse("#FFF8FAFC"),
|
||||||
|
Color.Parse("#22000000"),
|
||||||
|
0,
|
||||||
|
1);
|
||||||
|
var surfaces = new Dictionary<MaterialSurfaceRole, MaterialSurfaceSnapshot>
|
||||||
|
{
|
||||||
|
[MaterialSurfaceRole.SettingsWindowBackground] = surface,
|
||||||
|
[MaterialSurfaceRole.DockBackground] = surface with { Role = MaterialSurfaceRole.DockBackground },
|
||||||
|
[MaterialSurfaceRole.DesktopComponentHost] = surface with { Role = MaterialSurfaceRole.DesktopComponentHost },
|
||||||
|
[MaterialSurfaceRole.OverlayPanel] = surface with { Role = MaterialSurfaceRole.OverlayPanel }
|
||||||
|
};
|
||||||
|
|
||||||
|
return new MaterialColorSnapshot(
|
||||||
|
IsNightMode: false,
|
||||||
|
ThemeColorMode: ThemeAppearanceValues.ColorModeDefaultNeutral,
|
||||||
|
ThemeWallpaperColorSource: ThemeAppearanceValues.WallpaperColorSourceAuto,
|
||||||
|
ColorSourceKind: MaterialColorSourceKind.Neutral,
|
||||||
|
ResolvedSeedSource: "neutral",
|
||||||
|
CornerRadiusTokens: new AppearanceCornerRadiusTokens(
|
||||||
|
new CornerRadius(2),
|
||||||
|
new CornerRadius(4),
|
||||||
|
new CornerRadius(6),
|
||||||
|
new CornerRadius(8),
|
||||||
|
new CornerRadius(10),
|
||||||
|
new CornerRadius(12),
|
||||||
|
new CornerRadius(14),
|
||||||
|
new CornerRadius(8)),
|
||||||
|
UserThemeColor: seed.ToString(),
|
||||||
|
SelectedWallpaperSeed: null,
|
||||||
|
EffectiveSeedColor: seed,
|
||||||
|
AccentColor: seed,
|
||||||
|
MonetPalette: new MonetPalette([seed], seed, seed, seed, seed, seed, seed),
|
||||||
|
Palette: palette,
|
||||||
|
WallpaperSeedCandidates: [seed],
|
||||||
|
SystemMaterialMode: materialMode,
|
||||||
|
AvailableSystemMaterialModes:
|
||||||
|
[
|
||||||
|
ThemeAppearanceValues.MaterialAuto,
|
||||||
|
ThemeAppearanceValues.MaterialNone,
|
||||||
|
ThemeAppearanceValues.MaterialMica,
|
||||||
|
ThemeAppearanceValues.MaterialAcrylic
|
||||||
|
],
|
||||||
|
CanChangeSystemMaterial: true,
|
||||||
|
UseSystemChrome: false,
|
||||||
|
ResolvedWallpaperPath: null,
|
||||||
|
UseNativeWallpaperChangeEvents: true,
|
||||||
|
NativeWallpaperChangeEventsActive: false,
|
||||||
|
WallpaperPollingActive: false,
|
||||||
|
Surfaces: surfaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class FakeSettingsFacade(ThemeAppearanceSettingsState themeState) : ISettingsFacadeService
|
||||||
|
{
|
||||||
|
private readonly FakeThemeAppearanceService _theme = new(themeState);
|
||||||
|
private readonly FakeRegionSettingsService _region = new();
|
||||||
|
private readonly FakeWallpaperSettingsService _wallpaper = new();
|
||||||
|
|
||||||
|
public ThemeAppearanceSettingsState ThemeState => _theme.State;
|
||||||
|
public int ThemeSaveCount => _theme.SaveCount;
|
||||||
|
|
||||||
|
public ISettingsService Settings => throw new NotSupportedException();
|
||||||
|
public ISettingsCatalog Catalog => throw new NotSupportedException();
|
||||||
|
public IGridSettingsService Grid => throw new NotSupportedException();
|
||||||
|
public IWallpaperSettingsService Wallpaper => _wallpaper;
|
||||||
|
public IWallpaperMediaService WallpaperMedia => throw new NotSupportedException();
|
||||||
|
public IThemeAppearanceService Theme => _theme;
|
||||||
|
public IStatusBarSettingsService StatusBar => throw new NotSupportedException();
|
||||||
|
public ITextCapsuleSettingsService TextCapsule => throw new NotSupportedException();
|
||||||
|
public IWeatherSettingsService Weather => throw new NotSupportedException();
|
||||||
|
public IRegionSettingsService Region => _region;
|
||||||
|
public IPrivacySettingsService Privacy => throw new NotSupportedException();
|
||||||
|
public IUpdateSettingsService Update => throw new NotSupportedException();
|
||||||
|
public ILauncherCatalogService LauncherCatalog => throw new NotSupportedException();
|
||||||
|
public ILauncherPolicyService LauncherPolicy => throw new NotSupportedException();
|
||||||
|
public IPluginManagementSettingsService PluginManagement => throw new NotSupportedException();
|
||||||
|
public IPluginCatalogSettingsService PluginCatalog => throw new NotSupportedException();
|
||||||
|
public IApplicationInfoService ApplicationInfo => throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class FakeThemeAppearanceService(ThemeAppearanceSettingsState state) : IThemeAppearanceService
|
||||||
|
{
|
||||||
|
public ThemeAppearanceSettingsState State { get; private set; } = state;
|
||||||
|
public int SaveCount { get; private set; }
|
||||||
|
|
||||||
|
public ThemeAppearanceSettingsState Get() => State;
|
||||||
|
|
||||||
|
public void Save(ThemeAppearanceSettingsState state)
|
||||||
|
{
|
||||||
|
SaveCount++;
|
||||||
|
State = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MonetPalette BuildPalette(bool nightMode, string? wallpaperPath, string? preferredSeedColor = null)
|
||||||
|
{
|
||||||
|
var seed = Color.Parse(preferredSeedColor ?? "#FF3B82F6");
|
||||||
|
return new MonetPalette([seed], seed, seed, seed, seed, seed, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class FakeRegionSettingsService : IRegionSettingsService
|
||||||
|
{
|
||||||
|
public RegionSettingsState Get() => new("en-US", null);
|
||||||
|
|
||||||
|
public void Save(RegionSettingsState state)
|
||||||
|
{
|
||||||
|
_ = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeZoneService GetTimeZoneService() => new();
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class FakeWallpaperSettingsService : IWallpaperSettingsService
|
||||||
|
{
|
||||||
|
public WallpaperSettingsState Get() => new(null, "SolidColor", "#FFFFFFFF", "Fill", 300);
|
||||||
|
|
||||||
|
public void Save(WallpaperSettingsState state)
|
||||||
|
{
|
||||||
|
_ = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class FakeMaterialColorService(MaterialColorSnapshot snapshot) : IMaterialColorService
|
||||||
|
{
|
||||||
|
private MaterialColorSnapshot _snapshot = snapshot;
|
||||||
|
|
||||||
|
public event EventHandler<MaterialColorSnapshot>? MaterialColorChanged;
|
||||||
|
|
||||||
|
public MaterialColorSnapshot GetMaterialColorSnapshot() => _snapshot;
|
||||||
|
|
||||||
|
public MaterialColorSnapshot BuildMaterialColorPreview(ThemeAppearanceSettingsState pendingState)
|
||||||
|
{
|
||||||
|
_ = pendingState;
|
||||||
|
return _snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyThemeResources(IResourceDictionary resources)
|
||||||
|
{
|
||||||
|
_ = resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MaterialSurfaceSnapshot GetSurface(MaterialSurfaceRole role)
|
||||||
|
{
|
||||||
|
return _snapshot.Surfaces[role];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyWindowMaterial(Window window, MaterialSurfaceRole role)
|
||||||
|
{
|
||||||
|
_ = window;
|
||||||
|
_ = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshWallpaperColors()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RaiseChanged(MaterialColorSnapshot snapshot)
|
||||||
|
{
|
||||||
|
_snapshot = snapshot;
|
||||||
|
MaterialColorChanged?.Invoke(this, snapshot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -54,6 +54,7 @@ public sealed partial class MaterialColorSettingsPageViewModel : ViewModelBase
|
|||||||
private readonly LocalizationService _localizationService = new();
|
private readonly LocalizationService _localizationService = new();
|
||||||
private readonly string _languageCode;
|
private readonly string _languageCode;
|
||||||
private bool _isInitializing;
|
private bool _isInitializing;
|
||||||
|
private bool _isSynchronizingSystemMaterialMode;
|
||||||
private string? _selectedWallpaperSeed;
|
private string? _selectedWallpaperSeed;
|
||||||
|
|
||||||
public MaterialColorSettingsPageViewModel(
|
public MaterialColorSettingsPageViewModel(
|
||||||
@@ -307,7 +308,7 @@ public sealed partial class MaterialColorSettingsPageViewModel : ViewModelBase
|
|||||||
|
|
||||||
partial void OnSelectedSystemMaterialModeChanged(SelectionOption value)
|
partial void OnSelectedSystemMaterialModeChanged(SelectionOption value)
|
||||||
{
|
{
|
||||||
if (_isInitializing || value is null)
|
if (_isInitializing || _isSynchronizingSystemMaterialMode || value is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -452,15 +453,33 @@ public sealed partial class MaterialColorSettingsPageViewModel : ViewModelBase
|
|||||||
|
|
||||||
private void RefreshMaterialModes(MaterialColorSnapshot snapshot)
|
private void RefreshMaterialModes(MaterialColorSnapshot snapshot)
|
||||||
{
|
{
|
||||||
SystemMaterialModes = snapshot.AvailableSystemMaterialModes
|
var selectedValue = ThemeAppearanceValues.NormalizeSystemMaterialMode(
|
||||||
|
SelectedSystemMaterialMode?.Value ?? snapshot.SystemMaterialMode);
|
||||||
|
var snapshotValue = ThemeAppearanceValues.NormalizeSystemMaterialMode(snapshot.SystemMaterialMode);
|
||||||
|
|
||||||
|
SystemMaterialModes = ThemeAppearanceValues.NormalizeAvailableMaterialModes(snapshot.AvailableSystemMaterialModes)
|
||||||
.Select(value => new SelectionOption(value, ResolveMaterialLabel(value)))
|
.Select(value => new SelectionOption(value, ResolveMaterialLabel(value)))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
if (!SystemMaterialModes.Any(option =>
|
var nextSelection = SystemMaterialModes.FirstOrDefault(option =>
|
||||||
string.Equals(option.Value, SelectedSystemMaterialMode?.Value, StringComparison.OrdinalIgnoreCase)))
|
string.Equals(option.Value, selectedValue, StringComparison.OrdinalIgnoreCase))
|
||||||
|
?? SystemMaterialModes.FirstOrDefault(option =>
|
||||||
|
string.Equals(option.Value, snapshotValue, StringComparison.OrdinalIgnoreCase))
|
||||||
|
?? SystemMaterialModes.FirstOrDefault()
|
||||||
|
?? new SelectionOption(ThemeAppearanceValues.MaterialNone, MaterialNoneText);
|
||||||
|
|
||||||
|
if (!string.Equals(SelectedSystemMaterialMode?.Value, nextSelection.Value, StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
!ReferenceEquals(SelectedSystemMaterialMode, nextSelection))
|
||||||
{
|
{
|
||||||
SelectedSystemMaterialMode = SystemMaterialModes.FirstOrDefault()
|
_isSynchronizingSystemMaterialMode = true;
|
||||||
?? new SelectionOption(ThemeAppearanceValues.MaterialNone, MaterialNoneText);
|
try
|
||||||
|
{
|
||||||
|
SelectedSystemMaterialMode = nextSelection;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isSynchronizingSystemMaterialMode = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user