diff --git a/.gitignore b/.gitignore
index a2037bb..56e5892 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,9 @@
# dotenv files
.env
+# Local NuGet global packages (NuGet.Config globalPackagesFolder)
+.nuget/packages/
+
# User-specific files
*.rsuser
*.suo
diff --git a/LanMountainDesktop/Services/AppearanceThemeService.cs b/LanMountainDesktop/Services/AppearanceThemeService.cs
index 805c365..7139342 100644
--- a/LanMountainDesktop/Services/AppearanceThemeService.cs
+++ b/LanMountainDesktop/Services/AppearanceThemeService.cs
@@ -353,6 +353,26 @@ internal sealed class MaterialSurfaceService : IMaterialSurfaceService
MaterialSurfaceRole role,
bool isNightMode)
{
+ // Settings 根层(如 RootGrid)叠在 Transparent + Mica/Acrylic 上:过高 alpha 会完全盖住系统 backdrop。
+ // 保持非 None 下较低 alpha;None 仍用不透明白底等价。BlurRadius=0(由 DWM 提供模糊)。
+ if (role == MaterialSurfaceRole.SettingsWindowBackground)
+ {
+ return materialMode switch
+ {
+ ThemeAppearanceValues.MaterialAcrylic => (
+ 0.20,
+ 0.14,
+ isNightMode ? (byte)0x8E : (byte)0x96,
+ 0),
+ ThemeAppearanceValues.MaterialMica => (
+ 0.14,
+ 0.08,
+ isNightMode ? (byte)0x9E : (byte)0xA6,
+ 0),
+ _ => (0.08, 0.05, (byte)0xFF, 0)
+ };
+ }
+
var isOverlay = role is MaterialSurfaceRole.DockBackground or MaterialSurfaceRole.StatusBarBackground or MaterialSurfaceRole.OverlayPanel;
return materialMode switch
{
@@ -491,7 +511,8 @@ internal sealed class AppearanceThemeService : IAppearanceThemeService, IDisposa
// Avoid hot-switching real backdrops on already-visible windows. This has been
// a stability hotspot when users flip theme source/material at runtime.
- if (window.IsVisible)
+ // SettingsWindowBackground 是唯一需要材质与资源同步热切换的宿主角色;其它窗口仍保持「仅创建时」应用以降低风险。
+ if (window.IsVisible && role != MaterialSurfaceRole.SettingsWindowBackground)
{
return;
}
diff --git a/LanMountainDesktop/Services/GlassEffectService.cs b/LanMountainDesktop/Services/GlassEffectService.cs
index 2f071b7..9c0b2fd 100644
--- a/LanMountainDesktop/Services/GlassEffectService.cs
+++ b/LanMountainDesktop/Services/GlassEffectService.cs
@@ -69,6 +69,15 @@ public static class GlassEffectService
resources["AdaptiveWindowBackgroundBrush"] = new SolidColorBrush(windowSurface.BackgroundColor);
resources["AdaptiveWindowBorderBrush"] = new SolidColorBrush(windowSurface.BorderColor);
resources["AdaptiveSettingsWindowBackgroundBrush"] = new SolidColorBrush(settingsWindowSurface.BackgroundColor);
+ // 可选:叠在内容区上的可读性 tint(半透明);不改变 AdaptiveSettingsWindowBackgroundBrush 的语义权重,供 P1 绑定内容层。
+ var settingsTintBase = settingsWindowSurface.BackgroundColor;
+ var settingsTintAlpha = ResolveSettingsWindowTintAlpha(context);
+ resources["AdaptiveSettingsWindowTintBrush"] = new SolidColorBrush(
+ Color.FromArgb(
+ settingsTintAlpha,
+ settingsTintBase.R,
+ settingsTintBase.G,
+ settingsTintBase.B));
resources["AdaptiveSettingsWindowBorderBrush"] = new SolidColorBrush(settingsWindowSurface.BorderColor);
resources["AdaptiveDockBackgroundBrush"] = new SolidColorBrush(dockSurface.BackgroundColor);
resources["AdaptiveDockBorderBrush"] = new SolidColorBrush(dockSurface.BorderColor);
@@ -100,4 +109,16 @@ public static class GlassEffectService
resources["AdaptiveDesktopComponentHostOpacity"] = desktopComponentSurface.Opacity;
resources["AdaptiveStatusBarComponentHostOpacity"] = statusBarComponentSurface.Opacity;
}
+
+ /// 可选内容叠层 alpha,与设置窗表面色相一致;None 为 0 避免重复染色。
+ private static byte ResolveSettingsWindowTintAlpha(ThemeColorContext context)
+ {
+ var mode = ThemeAppearanceValues.NormalizeSystemMaterialMode(context.SystemMaterialMode);
+ return mode switch
+ {
+ ThemeAppearanceValues.MaterialAcrylic => context.IsNightMode ? (byte)0x58 : (byte)0x4C,
+ ThemeAppearanceValues.MaterialMica => context.IsNightMode ? (byte)0x50 : (byte)0x44,
+ _ => (byte)0x00
+ };
+ }
}
diff --git a/LanMountainDesktop/Services/Settings/SettingsWindowService.cs b/LanMountainDesktop/Services/Settings/SettingsWindowService.cs
index edc0ad1..147e4d6 100644
--- a/LanMountainDesktop/Services/Settings/SettingsWindowService.cs
+++ b/LanMountainDesktop/Services/Settings/SettingsWindowService.cs
@@ -71,7 +71,7 @@ internal sealed class SettingsWindowService : ISettingsWindowService
_window ??= CreateWindow();
var appearanceSnapshot = _appearanceThemeService.GetCurrent();
_window.ApplyChromeMode(appearanceSnapshot.UseSystemChrome);
- ApplyTheme(_window);
+ ApplyThemeVariantAndResources(_window);
var targetPageId = request.PageId ?? _window.ViewModel.CurrentPageId;
_window.ReloadPages(targetPageId);
@@ -79,6 +79,7 @@ internal sealed class SettingsWindowService : ISettingsWindowService
if (!_window.IsVisible)
{
CenterWindow(_window, request);
+ _appearanceThemeService.ApplyWindowMaterial(_window, MaterialSurfaceRole.SettingsWindowBackground);
_window.Show();
NotifyStateChanged();
CenterWindowLater(_window, request);
@@ -90,6 +91,7 @@ internal sealed class SettingsWindowService : ISettingsWindowService
_window.WindowState = WindowState.Normal;
}
+ _appearanceThemeService.ApplyWindowMaterial(_window, MaterialSurfaceRole.SettingsWindowBackground);
_window.Activate();
}
@@ -113,7 +115,6 @@ internal sealed class SettingsWindowService : ISettingsWindowService
_pageRegistry,
_hostApplicationLifecycle,
useSystemChrome);
- ApplyTheme(window);
window.ShowInTaskbar = true;
window.Closed += (_, _) =>
{
@@ -285,13 +286,23 @@ internal sealed class SettingsWindowService : ISettingsWindowService
}, DispatcherPriority.Background);
}
- private void ApplyTheme(SettingsWindow window)
+ private static void ApplyThemeVariantAndResources(SettingsWindow window, IAppearanceThemeService appearanceThemeService)
{
- var appearanceSnapshot = _appearanceThemeService.GetCurrent();
+ var appearanceSnapshot = appearanceThemeService.GetCurrent();
window.RequestedThemeVariant = appearanceSnapshot.IsNightMode
? ThemeVariant.Dark
: ThemeVariant.Light;
- _appearanceThemeService.ApplyThemeResources(window.Resources);
+ appearanceThemeService.ApplyThemeResources(window.Resources);
+ }
+
+ private void ApplyThemeVariantAndResources(SettingsWindow window)
+ {
+ ApplyThemeVariantAndResources(window, _appearanceThemeService);
+ }
+
+ private void ApplyTheme(SettingsWindow window)
+ {
+ ApplyThemeVariantAndResources(window, _appearanceThemeService);
_appearanceThemeService.ApplyWindowMaterial(window, MaterialSurfaceRole.SettingsWindowBackground);
}
diff --git a/LanMountainDesktop/Views/SettingsPages/LauncherSettingsPage.axaml b/LanMountainDesktop/Views/SettingsPages/LauncherSettingsPage.axaml
index 8394886..c0a2455 100644
--- a/LanMountainDesktop/Views/SettingsPages/LauncherSettingsPage.axaml
+++ b/LanMountainDesktop/Views/SettingsPages/LauncherSettingsPage.axaml
@@ -1,7 +1,6 @@
-
-
-
-
diff --git a/LanMountainDesktop/Views/SettingsPages/UpdateSettingsPage.axaml b/LanMountainDesktop/Views/SettingsPages/UpdateSettingsPage.axaml
index e2c540a..5af4903 100644
--- a/LanMountainDesktop/Views/SettingsPages/UpdateSettingsPage.axaml
+++ b/LanMountainDesktop/Views/SettingsPages/UpdateSettingsPage.axaml
@@ -10,7 +10,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
@@ -81,6 +164,7 @@
FontWeight="SemiBold"
Margin="8,0,0,0"
VerticalAlignment="Center"
+ Foreground="{DynamicResource TextFillColorPrimaryBrush}"
IsHitTestVisible="False"
Text="{Binding Title}" />
@@ -119,80 +203,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/LanMountainDesktop/Views/SettingsWindow.axaml.cs b/LanMountainDesktop/Views/SettingsWindow.axaml.cs
index 83f1e66..845b0f6 100644
--- a/LanMountainDesktop/Views/SettingsWindow.axaml.cs
+++ b/LanMountainDesktop/Views/SettingsWindow.axaml.cs
@@ -87,7 +87,8 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
SyncPendingRestartState();
SyncTitleText();
UpdateChromeMetrics();
- UpdatePaneToggleIcon();
+ UpdatePaneFooterToggleVisibility();
+ UpdatePaneFooterToggleIcon();
UpdateResponsiveLayout();
RequestResponsiveLayoutRefresh();
}
@@ -104,6 +105,7 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
CloseDrawer();
RebuildNavigationItems();
NavigateTo(pageId ?? ViewModel.Pages.FirstOrDefault()?.PageId);
+ UpdatePaneFooterToggleVisibility();
}
public void RebuildAndNavigateToDevPage()
@@ -266,6 +268,7 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
ViewModel.IsPageTitleVisible = !descriptor.HidePageTitle;
TrySelectNavigationItem(descriptor.PageId);
SyncTitleText();
+ UpdatePaneFooterToggleVisibility();
UpdateResponsiveLayout();
RequestResponsiveLayoutRefresh();
if (!string.Equals(previousPageId, descriptor.PageId, StringComparison.OrdinalIgnoreCase))
@@ -523,7 +526,7 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
}
}
- private void OnTogglePaneButtonClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
+ private void OnPaneFooterToggleClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
_ = sender;
_ = e;
@@ -533,7 +536,7 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
}
RootNavigationView.IsPaneOpen = !RootNavigationView.IsPaneOpen;
- UpdatePaneToggleIcon();
+ UpdatePaneFooterToggleIcon();
UpdateResponsiveLayout();
RequestResponsiveLayoutRefresh();
}
@@ -544,13 +547,33 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
if (e.Property == FANavigationView.IsPaneOpenProperty ||
e.Property == FANavigationView.OpenPaneLengthProperty ||
- e.Property == FANavigationView.PaneDisplayModeProperty)
+ e.Property == FANavigationView.PaneDisplayModeProperty ||
+ e.Property == FANavigationView.IsPaneToggleButtonVisibleProperty)
{
- UpdatePaneToggleIcon();
+ if (e.Property == FANavigationView.IsPaneToggleButtonVisibleProperty)
+ {
+ UpdatePaneFooterToggleVisibility();
+ }
+
+ UpdatePaneFooterToggleIcon();
RequestResponsiveLayoutRefresh();
}
}
+ ///
+ /// 仅在 :minimal( 为 false)时显示侧栏底部备胎按钮。
+ /// 根 DataContext 为 ViewModel 时,对 #RootNavigationView 的绑定易失效,故用代码同步可见性。
+ ///
+ private void UpdatePaneFooterToggleVisibility()
+ {
+ if (PaneFooterToggleButton is null || RootNavigationView is null)
+ {
+ return;
+ }
+
+ PaneFooterToggleButton.IsVisible = !RootNavigationView.IsPaneToggleButtonVisible;
+ }
+
private void RequestResponsiveLayoutRefresh()
{
if (_isResponsiveRefreshPending)
@@ -580,14 +603,14 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
: compactPaneWidth;
}
- private void UpdatePaneToggleIcon()
+ private void UpdatePaneFooterToggleIcon()
{
- if (TogglePaneButtonIcon is null || RootNavigationView is null)
+ if (PaneFooterToggleButtonIcon is null || RootNavigationView is null)
{
return;
}
- TogglePaneButtonIcon.Icon = RootNavigationView.IsPaneOpen
+ PaneFooterToggleButtonIcon.Icon = RootNavigationView.IsPaneOpen
? FluentIcons.Common.Icon.LineHorizontal3
: FluentIcons.Common.Icon.Navigation;
}
@@ -604,8 +627,6 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
}
if (WindowTitleBarHost is null ||
- TogglePaneButton is null ||
- TogglePaneButtonIcon is null ||
WindowBrandIcon is null ||
WindowTitleTextBlock is null ||
RestartNowButton is null ||
@@ -622,8 +643,6 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
var layoutScale = Math.Clamp(Math.Min(width / 1120d, height / 760d), 0.90, 1.18);
const double titleBarHeight = 48d;
- var titleBarButtonWidth = Math.Clamp(40d * layoutScale, 36d, 48d);
- var titleBarButtonHeight = Math.Clamp(32d * layoutScale, 30d, 38d);
var titleFontSize = Math.Clamp(12d * layoutScale, 11d, 14d);
var titleBarIconSize = Math.Clamp(16d * layoutScale, 15d, 20d);
var drawerTitleFontSize = Math.Clamp(16d * layoutScale, 14d, 20d);
@@ -634,9 +653,6 @@ public partial class SettingsWindow : FAAppWindow, ISettingsPageHostContext
WindowTitleBarHost.Height = titleBarHeight;
- TogglePaneButton.Width = titleBarButtonWidth;
- TogglePaneButton.Height = titleBarButtonHeight;
- TogglePaneButtonIcon.FontSize = titleBarIconSize;
WindowBrandIcon.FontSize = titleBarIconSize + 2;
WindowTitleTextBlock.FontSize = titleFontSize;
diff --git a/NuGet.Config b/NuGet.Config
new file mode 100644
index 0000000..696b4d2
--- /dev/null
+++ b/NuGet.Config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+