mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 15:44:25 +08:00
0.6.9
改变无声
This commit is contained in:
8
Directory.Build.props
Normal file
8
Directory.Build.props
Normal file
@@ -0,0 +1,8 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>1.0.0</Version>
|
||||
<TargetFramework Condition="'$(TargetFramework)' == ''">net10.0</TargetFramework>
|
||||
<Nullable Condition="'$(Nullable)' == ''">enable</Nullable>
|
||||
<ImplicitUsings Condition="'$(ImplicitUsings)' == ''">enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,27 @@
|
||||
using Avalonia;
|
||||
using LanMountainDesktop.Settings.Core;
|
||||
using LanMountainDesktop.Shared.Contracts;
|
||||
|
||||
namespace LanMountainDesktop.Appearance;
|
||||
|
||||
public static class AppearanceCornerRadiusTokenFactory
|
||||
{
|
||||
public static AppearanceCornerRadiusTokens Create(double scale)
|
||||
{
|
||||
var normalizedScale = GlobalAppearanceSettings.NormalizeCornerRadiusScale(scale);
|
||||
return new AppearanceCornerRadiusTokens(
|
||||
Radius(6, normalizedScale),
|
||||
Radius(10, normalizedScale),
|
||||
Radius(14, normalizedScale),
|
||||
Radius(18, normalizedScale),
|
||||
Radius(24, normalizedScale),
|
||||
Radius(30, normalizedScale),
|
||||
Radius(36, normalizedScale));
|
||||
}
|
||||
|
||||
private static CornerRadius Radius(double value, double scale)
|
||||
{
|
||||
var scaled = Math.Round(value * scale * 2, MidpointRounding.AwayFromZero) / 2d;
|
||||
return new CornerRadius(scaled);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LanMountainDesktop.PluginSdk\LanMountainDesktop.PluginSdk.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Shared.Contracts\LanMountainDesktop.Shared.Contracts.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Settings.Core\LanMountainDesktop.Settings.Core.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Host.Abstractions\LanMountainDesktop.Host.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LanMountainDesktop.PluginSdk\LanMountainDesktop.PluginSdk.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Shared.Contracts\LanMountainDesktop.Shared.Contracts.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Settings.Core\LanMountainDesktop.Settings.Core.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Appearance\LanMountainDesktop.Appearance.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Host.Abstractions\LanMountainDesktop.Host.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
27
LanMountainDesktop.DesktopHost/DesktopBootstrap.cs
Normal file
27
LanMountainDesktop.DesktopHost/DesktopBootstrap.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
|
||||
namespace LanMountainDesktop.DesktopHost;
|
||||
|
||||
public static class DesktopBootstrap
|
||||
{
|
||||
public static void InitializeStartupServices(Action initializeDeviceId, Action initializeCrashReporting, Action initializeUserBehaviorAnalytics, Action scheduleStartupCleanup)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(initializeDeviceId);
|
||||
ArgumentNullException.ThrowIfNull(initializeCrashReporting);
|
||||
ArgumentNullException.ThrowIfNull(initializeUserBehaviorAnalytics);
|
||||
ArgumentNullException.ThrowIfNull(scheduleStartupCleanup);
|
||||
|
||||
initializeDeviceId();
|
||||
initializeCrashReporting();
|
||||
initializeUserBehaviorAnalytics();
|
||||
scheduleStartupCleanup();
|
||||
}
|
||||
|
||||
public static void InitializeApplication(Application application, Action initializeShell)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(application);
|
||||
ArgumentNullException.ThrowIfNull(initializeShell);
|
||||
initializeShell();
|
||||
}
|
||||
}
|
||||
55
LanMountainDesktop.DesktopHost/DesktopShellHost.cs
Normal file
55
LanMountainDesktop.DesktopHost/DesktopShellHost.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using LanMountainDesktop.Host.Abstractions;
|
||||
|
||||
namespace LanMountainDesktop.DesktopHost;
|
||||
|
||||
public sealed class DesktopShellHost : IDesktopShellHost
|
||||
{
|
||||
private readonly Action _initializePluginRuntime;
|
||||
private readonly Action _initializeTrayIcon;
|
||||
private readonly Action<IClassicDesktopStyleApplicationLifetime> _createAndAssignMainWindow;
|
||||
private readonly Action _performExitCleanup;
|
||||
private readonly Action _startActivationListener;
|
||||
private readonly Action _startWeatherRefresh;
|
||||
|
||||
public DesktopShellHost(
|
||||
Action initializePluginRuntime,
|
||||
Action initializeTrayIcon,
|
||||
Action<IClassicDesktopStyleApplicationLifetime> createAndAssignMainWindow,
|
||||
Action performExitCleanup,
|
||||
Action startActivationListener,
|
||||
Action startWeatherRefresh)
|
||||
{
|
||||
_initializePluginRuntime = initializePluginRuntime;
|
||||
_initializeTrayIcon = initializeTrayIcon;
|
||||
_createAndAssignMainWindow = createAndAssignMainWindow;
|
||||
_performExitCleanup = performExitCleanup;
|
||||
_startActivationListener = startActivationListener;
|
||||
_startWeatherRefresh = startWeatherRefresh;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
throw new InvalidOperationException("An application instance is required to initialize the desktop shell.");
|
||||
}
|
||||
|
||||
public void Initialize(Application application)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(application);
|
||||
|
||||
_initializePluginRuntime();
|
||||
_initializeTrayIcon();
|
||||
|
||||
if (application.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.Exit += (_, _) => _performExitCleanup();
|
||||
_createAndAssignMainWindow(desktop);
|
||||
_startActivationListener();
|
||||
}
|
||||
|
||||
_startWeatherRefresh();
|
||||
}
|
||||
}
|
||||
15
LanMountainDesktop.DesktopHost/DesktopStartupCoordinator.cs
Normal file
15
LanMountainDesktop.DesktopHost/DesktopStartupCoordinator.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace LanMountainDesktop.DesktopHost;
|
||||
|
||||
public sealed class DesktopStartupCoordinator
|
||||
{
|
||||
private readonly Action _restoreWorkspaceState;
|
||||
|
||||
public DesktopStartupCoordinator(Action restoreWorkspaceState)
|
||||
{
|
||||
_restoreWorkspaceState = restoreWorkspaceState ?? throw new ArgumentNullException(nameof(restoreWorkspaceState));
|
||||
}
|
||||
|
||||
public void Restore() => _restoreWorkspaceState();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.3.12" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LanMountainDesktop.PluginSdk\LanMountainDesktop.PluginSdk.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Shared.Contracts\LanMountainDesktop.Shared.Contracts.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Settings.Core\LanMountainDesktop.Settings.Core.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Appearance\LanMountainDesktop.Appearance.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.DesktopComponents.Runtime\LanMountainDesktop.DesktopComponents.Runtime.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Host.Abstractions\LanMountainDesktop.Host.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
18
LanMountainDesktop.DesktopHost/SettingsWindowHost.cs
Normal file
18
LanMountainDesktop.DesktopHost/SettingsWindowHost.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
|
||||
namespace LanMountainDesktop.DesktopHost;
|
||||
|
||||
public sealed class SettingsWindowHost
|
||||
{
|
||||
private readonly Action<string, string?> _openSettingsWindow;
|
||||
|
||||
public SettingsWindowHost(Action<string, string?> openSettingsWindow)
|
||||
{
|
||||
_openSettingsWindow = openSettingsWindow ?? throw new ArgumentNullException(nameof(openSettingsWindow));
|
||||
}
|
||||
|
||||
public void Open(string source, string? pageId = null)
|
||||
{
|
||||
_openSettingsWindow(source, pageId);
|
||||
}
|
||||
}
|
||||
19
LanMountainDesktop.DesktopHost/ShutdownCoordinator.cs
Normal file
19
LanMountainDesktop.DesktopHost/ShutdownCoordinator.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace LanMountainDesktop.DesktopHost;
|
||||
|
||||
public sealed class ShutdownCoordinator
|
||||
{
|
||||
private readonly Action<bool, string> _prepareForShutdown;
|
||||
private readonly Action<string> _resetShutdownIntent;
|
||||
|
||||
public ShutdownCoordinator(Action<bool, string> prepareForShutdown, Action<string> resetShutdownIntent)
|
||||
{
|
||||
_prepareForShutdown = prepareForShutdown ?? throw new ArgumentNullException(nameof(prepareForShutdown));
|
||||
_resetShutdownIntent = resetShutdownIntent ?? throw new ArgumentNullException(nameof(resetShutdownIntent));
|
||||
}
|
||||
|
||||
public void Prepare(bool isRestart, string source) => _prepareForShutdown(isRestart, source);
|
||||
|
||||
public void Reset(string source) => _resetShutdownIntent(source);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Shared.Contracts;
|
||||
|
||||
namespace LanMountainDesktop.Host.Abstractions;
|
||||
|
||||
public sealed record ComponentChromeContext(
|
||||
string ComponentId,
|
||||
string? PlacementId,
|
||||
double CellSize,
|
||||
double GlobalCornerRadiusScale,
|
||||
AppearanceCornerRadiusTokens CornerRadiusTokens,
|
||||
SettingsScope Scope = SettingsScope.App);
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace LanMountainDesktop.Host.Abstractions;
|
||||
|
||||
public interface IDesktopShellHost
|
||||
{
|
||||
void Initialize();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LanMountainDesktop.PluginSdk\LanMountainDesktop.PluginSdk.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -12,6 +12,7 @@
|
||||
<PackageReference Include="Avalonia" Version="11.3.12" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.0" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Shared.Contracts\LanMountainDesktop.Shared.Contracts.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using LanMountainDesktop.Shared.Contracts;
|
||||
|
||||
namespace LanMountainDesktop.PluginSdk;
|
||||
|
||||
public sealed class PluginDesktopComponentContext
|
||||
@@ -11,6 +13,8 @@ public sealed class PluginDesktopComponentContext
|
||||
string componentId,
|
||||
string? placementId,
|
||||
double cellSize,
|
||||
double globalCornerRadiusScale,
|
||||
AppearanceCornerRadiusTokens cornerRadiusTokens,
|
||||
IPluginSettingsService? pluginSettings = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(manifest);
|
||||
@@ -19,6 +23,7 @@ public sealed class PluginDesktopComponentContext
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(componentId);
|
||||
ArgumentNullException.ThrowIfNull(services);
|
||||
ArgumentNullException.ThrowIfNull(properties);
|
||||
ArgumentNullException.ThrowIfNull(cornerRadiusTokens);
|
||||
|
||||
Manifest = manifest;
|
||||
PluginDirectory = pluginDirectory;
|
||||
@@ -28,6 +33,8 @@ public sealed class PluginDesktopComponentContext
|
||||
ComponentId = componentId.Trim();
|
||||
PlacementId = string.IsNullOrWhiteSpace(placementId) ? null : placementId.Trim();
|
||||
CellSize = Math.Max(1, cellSize);
|
||||
GlobalCornerRadiusScale = Math.Max(0.1d, globalCornerRadiusScale);
|
||||
CornerRadiusTokens = cornerRadiusTokens;
|
||||
PluginSettings = pluginSettings;
|
||||
}
|
||||
|
||||
@@ -47,8 +54,22 @@ public sealed class PluginDesktopComponentContext
|
||||
|
||||
public double CellSize { get; }
|
||||
|
||||
public double GlobalCornerRadiusScale { get; }
|
||||
|
||||
public AppearanceCornerRadiusTokens CornerRadiusTokens { get; }
|
||||
|
||||
public IPluginSettingsService? PluginSettings { get; }
|
||||
|
||||
public double ResolveScaledCornerRadius(double baseRadius, double? minimum = null, double? maximum = null)
|
||||
{
|
||||
var scaled = Math.Max(0d, baseRadius) * GlobalCornerRadiusScale;
|
||||
var scaledMin = minimum.HasValue ? minimum.Value * GlobalCornerRadiusScale : scaled;
|
||||
var scaledMax = maximum.HasValue ? maximum.Value * GlobalCornerRadiusScale : scaled;
|
||||
return minimum.HasValue || maximum.HasValue
|
||||
? Math.Clamp(scaled, scaledMin, scaledMax)
|
||||
: scaled;
|
||||
}
|
||||
|
||||
public T? GetService<T>()
|
||||
{
|
||||
return (T?)Services.GetService(typeof(T));
|
||||
|
||||
20
LanMountainDesktop.Settings.Core/GlobalAppearanceSettings.cs
Normal file
20
LanMountainDesktop.Settings.Core/GlobalAppearanceSettings.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace LanMountainDesktop.Settings.Core;
|
||||
|
||||
public static class GlobalAppearanceSettings
|
||||
{
|
||||
public const double DefaultCornerRadiusScale = 1.0;
|
||||
public const double MinimumCornerRadiusScale = 0.70;
|
||||
public const double MaximumCornerRadiusScale = 1.40;
|
||||
public const double CornerRadiusScaleStep = 0.05;
|
||||
|
||||
public static double NormalizeCornerRadiusScale(double value)
|
||||
{
|
||||
if (double.IsNaN(value) || double.IsInfinity(value))
|
||||
{
|
||||
return DefaultCornerRadiusScale;
|
||||
}
|
||||
|
||||
var clamped = Math.Clamp(value, MinimumCornerRadiusScale, MaximumCornerRadiusScale);
|
||||
return Math.Round(clamped / CornerRadiusScaleStep, MidpointRounding.AwayFromZero) * CornerRadiusScaleStep;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LanMountainDesktop.PluginSdk\LanMountainDesktop.PluginSdk.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Shared.Contracts\LanMountainDesktop.Shared.Contracts.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,12 @@
|
||||
using Avalonia;
|
||||
|
||||
namespace LanMountainDesktop.Shared.Contracts;
|
||||
|
||||
public sealed record AppearanceCornerRadiusTokens(
|
||||
CornerRadius Micro,
|
||||
CornerRadius Xs,
|
||||
CornerRadius Sm,
|
||||
CornerRadius Md,
|
||||
CornerRadius Lg,
|
||||
CornerRadius Xl,
|
||||
CornerRadius Island);
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.3.12" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,5 +1,11 @@
|
||||
<Solution>
|
||||
<Project Path="LanAirApp/tools/LanMountainDesktop.PluginPackager/LanMountainDesktop.PluginPackager.csproj" />
|
||||
<Project Path="LanMountainDesktop.Host.Abstractions/LanMountainDesktop.Host.Abstractions.csproj" />
|
||||
<Project Path="LanMountainDesktop.Shared.Contracts/LanMountainDesktop.Shared.Contracts.csproj" />
|
||||
<Project Path="LanMountainDesktop.Settings.Core/LanMountainDesktop.Settings.Core.csproj" />
|
||||
<Project Path="LanMountainDesktop.Appearance/LanMountainDesktop.Appearance.csproj" />
|
||||
<Project Path="LanMountainDesktop.DesktopComponents.Runtime/LanMountainDesktop.DesktopComponents.Runtime.csproj" />
|
||||
<Project Path="LanMountainDesktop.DesktopHost/LanMountainDesktop.DesktopHost.csproj" />
|
||||
<Project Path="LanMountainDesktop.PluginSdk/LanMountainDesktop.PluginSdk.csproj" />
|
||||
<Project Path="LanMountainDesktop.PluginsInstallHelper/LanMountainDesktop.PluginsInstallHelper.csproj" />
|
||||
<Project Path="LanMountainDesktop/LanMountainDesktop.csproj" />
|
||||
|
||||
@@ -15,6 +15,7 @@ using Avalonia.Styling;
|
||||
using Avalonia.Threading;
|
||||
using AvaloniaWebView;
|
||||
using LanMountainDesktop.ComponentSystem;
|
||||
using LanMountainDesktop.DesktopHost;
|
||||
using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Services;
|
||||
@@ -61,6 +62,7 @@ public partial class App : Application
|
||||
private MainWindow? _mainWindow;
|
||||
private bool _mainWindowClosed;
|
||||
private bool _uiUnhandledExceptionHooked;
|
||||
private DesktopShellHost? _desktopShellHost;
|
||||
|
||||
internal static SingleInstanceService? CurrentSingleInstanceService { get; set; }
|
||||
internal static (UserBehaviorAnalyticsService?, CrashReportService?) AnalyticsServices { get; set; }
|
||||
@@ -116,28 +118,32 @@ public partial class App : Application
|
||||
AppLogger.Info("App", "Framework initialization completed.");
|
||||
RegisterUiUnhandledExceptionGuard();
|
||||
LinuxDesktopEntryInstaller.EnsureInstalled();
|
||||
InitializePluginRuntime();
|
||||
InitializeTrayIcon();
|
||||
DesktopBootstrap.InitializeApplication(this, InitializeDesktopShell);
|
||||
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
|
||||
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
|
||||
DisableAvaloniaDataAnnotationValidation();
|
||||
desktop.ShutdownMode = Avalonia.Controls.ShutdownMode.OnExplicitShutdown;
|
||||
desktop.Exit += (_, _) =>
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
|
||||
private void InitializeDesktopShell()
|
||||
{
|
||||
_desktopShellHost ??= new DesktopShellHost(
|
||||
InitializePluginRuntime,
|
||||
InitializeTrayIcon,
|
||||
desktop =>
|
||||
{
|
||||
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
|
||||
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
|
||||
DisableAvaloniaDataAnnotationValidation();
|
||||
desktop.ShutdownMode = Avalonia.Controls.ShutdownMode.OnExplicitShutdown;
|
||||
CreateAndAssignMainWindow(desktop, "FrameworkInitialization");
|
||||
},
|
||||
() =>
|
||||
{
|
||||
AppLogger.Info("App", "Desktop lifetime exit triggered.");
|
||||
PerformExitCleanup();
|
||||
};
|
||||
|
||||
CreateAndAssignMainWindow(desktop, "FrameworkInitialization");
|
||||
CurrentSingleInstanceService?.StartActivationListener(ActivateMainWindow);
|
||||
}
|
||||
|
||||
StartWeatherLocationRefreshIfNeeded();
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
},
|
||||
() => CurrentSingleInstanceService?.StartActivationListener(ActivateMainWindow),
|
||||
StartWeatherLocationRefreshIfNeeded);
|
||||
_desktopShellHost.Initialize(this);
|
||||
}
|
||||
|
||||
private void OnTrayExitClick(object? sender, EventArgs e)
|
||||
@@ -493,6 +499,7 @@ public partial class App : Application
|
||||
refreshAll ||
|
||||
changedKeys.Contains(nameof(AppSettingsSnapshot.IsNightMode), StringComparer.OrdinalIgnoreCase) ||
|
||||
changedKeys.Contains(nameof(AppSettingsSnapshot.UseSystemChrome), StringComparer.OrdinalIgnoreCase) ||
|
||||
changedKeys.Contains(nameof(AppSettingsSnapshot.GlobalCornerRadiusScale), StringComparer.OrdinalIgnoreCase) ||
|
||||
(string.Equals(liveAppearance.ThemeColorMode, ThemeAppearanceValues.ColorModeSeedMonet, StringComparison.OrdinalIgnoreCase) &&
|
||||
changedKeys.Contains(nameof(AppSettingsSnapshot.ThemeColor), StringComparer.OrdinalIgnoreCase)) ||
|
||||
(string.Equals(liveAppearance.ThemeColorMode, ThemeAppearanceValues.ColorModeWallpaperMonet, StringComparison.OrdinalIgnoreCase) &&
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using LanMountainDesktop.Host.Abstractions;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Services.Settings;
|
||||
@@ -10,5 +11,6 @@ public sealed record DesktopComponentRuntimeContext(
|
||||
ISettingsFacadeService SettingsFacade,
|
||||
ISettingsService SettingsService,
|
||||
IAppearanceThemeService AppearanceTheme,
|
||||
ComponentChromeContext Chrome,
|
||||
IComponentSettingsAccessor ComponentSettingsAccessor,
|
||||
IComponentInstanceSettingsStore ComponentSettingsStore);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using LanMountainDesktop.Host.Abstractions;
|
||||
|
||||
namespace LanMountainDesktop.ComponentSystem;
|
||||
|
||||
public interface IComponentChromeContextAware
|
||||
{
|
||||
void SetComponentChromeContext(ComponentChromeContext context);
|
||||
}
|
||||
@@ -29,6 +29,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LanMountainDesktop.Host.Abstractions\LanMountainDesktop.Host.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Shared.Contracts\LanMountainDesktop.Shared.Contracts.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Settings.Core\LanMountainDesktop.Settings.Core.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.Appearance\LanMountainDesktop.Appearance.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.DesktopComponents.Runtime\LanMountainDesktop.DesktopComponents.Runtime.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.DesktopHost\LanMountainDesktop.DesktopHost.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.PluginSdk\LanMountainDesktop.PluginSdk.csproj" />
|
||||
<ProjectReference Include="..\LanMountainDesktop.PluginsInstallHelper\LanMountainDesktop.PluginsInstallHelper.csproj" ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"settings.nav.group_system": "System",
|
||||
"settings.nav.group_extensions": "Extensions",
|
||||
"settings.nav.wallpaper": "Wallpaper",
|
||||
"settings.nav.grid": "Grid",
|
||||
"settings.nav.grid": "Components",
|
||||
"settings.nav.color": "Color",
|
||||
"settings.nav.status_bar": "Status Bar",
|
||||
"settings.nav.weather": "Weather",
|
||||
@@ -303,8 +303,17 @@
|
||||
"settings.status_bar.clock_format.hm": "Hour:Minute",
|
||||
"settings.status_bar.clock_format.hms": "Hour:Minute:Second",
|
||||
"settings.components.title": "Components",
|
||||
"settings.components.description": "Adjust desktop grid density and widget placement.",
|
||||
"settings.components.grid_header": "Grid Layout",
|
||||
"settings.components.description": "Adjust component layout and corner design.",
|
||||
"settings.components.grid_header": "Grid Settings",
|
||||
"settings.components.header": "Grid Settings",
|
||||
"settings.components.short_side_label": "Short Side Cells",
|
||||
"settings.components.edge_inset_label": "Screen Inset",
|
||||
"settings.components.spacing_label": "Component Spacing",
|
||||
"settings.components.spacing_compact": "Compact",
|
||||
"settings.components.spacing_relaxed": "Relaxed",
|
||||
"settings.components.corner_radius.header": "Corner Design",
|
||||
"settings.components.corner_radius.label": "Component Corner Radius",
|
||||
"settings.components.corner_radius.description": "Adjust the shared corner radius used by component containers, and expand the internal safe area with it.",
|
||||
"settings.update.title": "Update",
|
||||
"settings.update.current_version_label": "Current Version",
|
||||
"settings.update.latest_version_label": "Latest Release",
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"settings.nav.group_system": "系统",
|
||||
"settings.nav.group_extensions": "扩展",
|
||||
"settings.nav.wallpaper": "壁纸",
|
||||
"settings.nav.grid": "网格",
|
||||
"settings.nav.grid": "组件",
|
||||
"settings.nav.color": "颜色",
|
||||
"settings.nav.status_bar": "状态栏",
|
||||
"settings.nav.weather": "天气",
|
||||
@@ -301,9 +301,18 @@
|
||||
"settings.status_bar.clock_format_label": "时钟格式",
|
||||
"settings.status_bar.clock_format.hm": "时:分",
|
||||
"settings.status_bar.clock_format.hms": "时:分:秒",
|
||||
"settings.components.title": "网格",
|
||||
"settings.components.description": "调整桌面网格与布局。",
|
||||
"settings.components.grid_header": "网格布局",
|
||||
"settings.components.title": "组件",
|
||||
"settings.components.description": "调整组件布局与圆角设计。",
|
||||
"settings.components.grid_header": "网格设置",
|
||||
"settings.components.header": "网格设置",
|
||||
"settings.components.short_side_label": "短边格数",
|
||||
"settings.components.edge_inset_label": "屏幕边距",
|
||||
"settings.components.spacing_label": "组件间距",
|
||||
"settings.components.spacing_compact": "紧凑",
|
||||
"settings.components.spacing_relaxed": "宽松",
|
||||
"settings.components.corner_radius.header": "圆角设计",
|
||||
"settings.components.corner_radius.label": "组件圆角",
|
||||
"settings.components.corner_radius.description": "统一调整组件容器圆角,并随圆角增大同步扩展内部安全区。",
|
||||
"settings.update.title": "更新",
|
||||
"settings.update.current_version_label": "当前版本",
|
||||
"settings.update.latest_version_label": "最新发布",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using LanMountainDesktop.Settings.Core;
|
||||
|
||||
namespace LanMountainDesktop.Models;
|
||||
|
||||
@@ -16,6 +17,8 @@ public sealed class AppSettingsSnapshot
|
||||
|
||||
public bool UseSystemChrome { get; set; }
|
||||
|
||||
public double GlobalCornerRadiusScale { get; set; } = GlobalAppearanceSettings.DefaultCornerRadiusScale;
|
||||
|
||||
public string ThemeColorMode { get; set; } = "default_neutral";
|
||||
|
||||
public string SystemMaterialMode { get; set; } = "none";
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Avalonia.WebView.Desktop;
|
||||
using LanMountainDesktop.DesktopHost;
|
||||
using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Services.Settings;
|
||||
@@ -20,9 +21,11 @@ sealed class Program
|
||||
{
|
||||
AppLogger.Initialize();
|
||||
RegisterGlobalExceptionLogging();
|
||||
InitializeDeviceId();
|
||||
InitializeCrashReporting();
|
||||
InitializeUserBehaviorAnalytics();
|
||||
DesktopBootstrap.InitializeStartupServices(
|
||||
InitializeDeviceId,
|
||||
InitializeCrashReporting,
|
||||
InitializeUserBehaviorAnalytics,
|
||||
ScheduleWhiteboardNoteStartupCleanup);
|
||||
var restartParentProcessId = AppRestartService.TryGetRestartParentProcessId(args);
|
||||
|
||||
using var singleInstance = AcquireSingleInstance(restartParentProcessId);
|
||||
@@ -43,7 +46,6 @@ sealed class Program
|
||||
|
||||
var diagnostics = StartupDiagnosticsService.Run(args);
|
||||
StartupDiagnosticsService.ShowLegacyExecutableWarningIfNeeded(diagnostics);
|
||||
ScheduleWhiteboardNoteStartupCleanup();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -11,9 +11,12 @@ using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
using Avalonia.Threading;
|
||||
using Avalonia.Media.Imaging;
|
||||
using LanMountainDesktop.Appearance;
|
||||
using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Services.Settings;
|
||||
using LanMountainDesktop.Settings.Core;
|
||||
using LanMountainDesktop.Shared.Contracts;
|
||||
using LanMountainDesktop.Theme;
|
||||
using Microsoft.Win32;
|
||||
|
||||
@@ -41,6 +44,8 @@ public sealed record AppearanceThemeSnapshot(
|
||||
string ThemeColorMode,
|
||||
string? UserThemeColor,
|
||||
string? SelectedWallpaperSeed,
|
||||
double GlobalCornerRadiusScale,
|
||||
AppearanceCornerRadiusTokens CornerRadiusTokens,
|
||||
string ResolvedSeedSource,
|
||||
MonetPalette MonetPalette,
|
||||
Color AccentColor,
|
||||
@@ -464,6 +469,13 @@ internal sealed class AppearanceThemeService : IAppearanceThemeService, IDisposa
|
||||
var context = CreateThemeContext(snapshot);
|
||||
ThemeColorSystemService.ApplyThemeResources(resources, context);
|
||||
GlassEffectService.ApplyGlassResources(resources, context);
|
||||
resources["DesignCornerRadiusMicro"] = snapshot.CornerRadiusTokens.Micro;
|
||||
resources["DesignCornerRadiusXs"] = snapshot.CornerRadiusTokens.Xs;
|
||||
resources["DesignCornerRadiusSm"] = snapshot.CornerRadiusTokens.Sm;
|
||||
resources["DesignCornerRadiusMd"] = snapshot.CornerRadiusTokens.Md;
|
||||
resources["DesignCornerRadiusLg"] = snapshot.CornerRadiusTokens.Lg;
|
||||
resources["DesignCornerRadiusXl"] = snapshot.CornerRadiusTokens.Xl;
|
||||
resources["DesignCornerRadiusIsland"] = snapshot.CornerRadiusTokens.Island;
|
||||
}
|
||||
|
||||
public AppearanceMaterialSurface GetMaterialSurface(MaterialSurfaceRole role)
|
||||
@@ -538,6 +550,7 @@ internal sealed class AppearanceThemeService : IAppearanceThemeService, IDisposa
|
||||
if (!refreshAll &&
|
||||
!changedKeys.Contains(nameof(AppSettingsSnapshot.IsNightMode), StringComparer.OrdinalIgnoreCase) &&
|
||||
!changedKeys.Contains(nameof(AppSettingsSnapshot.UseSystemChrome), StringComparer.OrdinalIgnoreCase) &&
|
||||
!changedKeys.Contains(nameof(AppSettingsSnapshot.GlobalCornerRadiusScale), StringComparer.OrdinalIgnoreCase) &&
|
||||
!(respondsToThemeColor &&
|
||||
changedKeys.Contains(nameof(AppSettingsSnapshot.ThemeColor), StringComparer.OrdinalIgnoreCase)) &&
|
||||
!(respondsToWallpaper &&
|
||||
@@ -559,6 +572,8 @@ internal sealed class AppearanceThemeService : IAppearanceThemeService, IDisposa
|
||||
bool queueWallpaperPaletteBuild)
|
||||
{
|
||||
var availableModes = _windowMaterialService.GetAvailableModes();
|
||||
var globalCornerRadiusScale = GlobalAppearanceSettings.NormalizeCornerRadiusScale(themeState.GlobalCornerRadiusScale);
|
||||
var cornerRadiusTokens = AppearanceCornerRadiusTokenFactory.Create(globalCornerRadiusScale);
|
||||
MonetPalette palette;
|
||||
IReadOnlyList<Color> wallpaperSeedCandidates;
|
||||
Color effectiveSeedColor;
|
||||
@@ -598,6 +613,8 @@ internal sealed class AppearanceThemeService : IAppearanceThemeService, IDisposa
|
||||
themeColorMode,
|
||||
themeState.ThemeColor,
|
||||
selectedWallpaperSeed,
|
||||
globalCornerRadiusScale,
|
||||
cornerRadiusTokens,
|
||||
resolvedSeedSource,
|
||||
palette,
|
||||
ResolveAccentColor(themeColorMode, themeState.ThemeColor, palette),
|
||||
|
||||
@@ -122,6 +122,7 @@ public static class DesktopComponentRegistryFactory
|
||||
var pluginSettings = new PluginScopedSettingsService(
|
||||
contribution.Plugin.Manifest.Id,
|
||||
settingsService);
|
||||
var appearanceSnapshot = HostAppearanceThemeProvider.GetOrCreate().GetCurrent();
|
||||
var pluginContext = new PluginDesktopComponentContext(
|
||||
contribution.Plugin.Manifest,
|
||||
contribution.Plugin.Context.PluginDirectory,
|
||||
@@ -131,6 +132,8 @@ public static class DesktopComponentRegistryFactory
|
||||
contribution.Registration.ComponentId,
|
||||
context.PlacementId,
|
||||
context.CellSize,
|
||||
appearanceSnapshot.GlobalCornerRadiusScale,
|
||||
appearanceSnapshot.CornerRadiusTokens,
|
||||
pluginSettings);
|
||||
|
||||
return contribution.Registration.ControlFactory(contribution.Plugin.Services, pluginContext);
|
||||
|
||||
@@ -20,6 +20,7 @@ public sealed record ComponentLibraryCategoryEntry(
|
||||
|
||||
public sealed record ComponentLibraryCreateContext(
|
||||
double CellSize,
|
||||
double GlobalCornerRadiusScale,
|
||||
TimeZoneService TimeZoneService,
|
||||
IWeatherInfoService WeatherInfoService,
|
||||
IRecommendationInfoService RecommendationInfoService,
|
||||
|
||||
@@ -17,7 +17,7 @@ internal sealed class SettingsCatalogService : ISettingsCatalog
|
||||
[
|
||||
new SettingsSectionDefinition("general", SettingsCategories.General, SettingsScope.App, "settings.general.title", iconKey: "Settings", sortOrder: 0),
|
||||
new SettingsSectionDefinition("appearance", SettingsCategories.Appearance, SettingsScope.App, "settings.appearance.title", iconKey: "DesignIdeas", sortOrder: 10),
|
||||
new SettingsSectionDefinition("components", SettingsCategories.Components, SettingsScope.ComponentInstance, "settings.components.title", iconKey: "GridDots", sortOrder: 20),
|
||||
new SettingsSectionDefinition("components", SettingsCategories.Components, SettingsScope.ComponentInstance, "settings.components.title", iconKey: "Apps", sortOrder: 20),
|
||||
new SettingsSectionDefinition("plugins", SettingsCategories.Plugins, SettingsScope.Plugin, "settings.plugins.title", iconKey: "PuzzlePiece", sortOrder: 30),
|
||||
new SettingsSectionDefinition("about", SettingsCategories.About, SettingsScope.App, "settings.about.title", iconKey: "Info", sortOrder: 40)
|
||||
]);
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Settings.Core;
|
||||
|
||||
namespace LanMountainDesktop.Services.Settings;
|
||||
|
||||
@@ -20,6 +21,7 @@ public sealed record ThemeAppearanceSettingsState(
|
||||
bool IsNightMode,
|
||||
string? ThemeColor,
|
||||
bool UseSystemChrome,
|
||||
double GlobalCornerRadiusScale = GlobalAppearanceSettings.DefaultCornerRadiusScale,
|
||||
string ThemeColorMode = ThemeAppearanceValues.ColorModeDefaultNeutral,
|
||||
string SystemMaterialMode = ThemeAppearanceValues.MaterialNone,
|
||||
string? SelectedWallpaperSeed = null);
|
||||
|
||||
@@ -10,6 +10,7 @@ using Avalonia.Media.Imaging;
|
||||
using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Settings.Core;
|
||||
using LanMountainDesktop.Services.PluginMarket;
|
||||
|
||||
namespace LanMountainDesktop.Services.Settings;
|
||||
@@ -242,6 +243,7 @@ internal sealed class ThemeAppearanceService : IThemeAppearanceService
|
||||
snapshot.IsNightMode ?? false,
|
||||
snapshot.ThemeColor,
|
||||
snapshot.UseSystemChrome,
|
||||
GlobalAppearanceSettings.NormalizeCornerRadiusScale(snapshot.GlobalCornerRadiusScale),
|
||||
ThemeAppearanceValues.NormalizeThemeColorMode(snapshot.ThemeColorMode, snapshot.ThemeColor),
|
||||
ThemeAppearanceValues.NormalizeSystemMaterialMode(snapshot.SystemMaterialMode),
|
||||
snapshot.SelectedWallpaperSeed);
|
||||
@@ -252,6 +254,7 @@ internal sealed class ThemeAppearanceService : IThemeAppearanceService
|
||||
var snapshot = _settingsService.Load();
|
||||
var changedKeys = new List<string>();
|
||||
var normalizedThemeColor = string.IsNullOrWhiteSpace(state.ThemeColor) ? null : state.ThemeColor;
|
||||
var normalizedCornerRadiusScale = GlobalAppearanceSettings.NormalizeCornerRadiusScale(state.GlobalCornerRadiusScale);
|
||||
var normalizedThemeColorMode = ThemeAppearanceValues.NormalizeThemeColorMode(state.ThemeColorMode, state.ThemeColor);
|
||||
var normalizedSystemMaterialMode = ThemeAppearanceValues.NormalizeSystemMaterialMode(state.SystemMaterialMode);
|
||||
var normalizedSelectedWallpaperSeed = string.IsNullOrWhiteSpace(state.SelectedWallpaperSeed)
|
||||
@@ -276,6 +279,12 @@ internal sealed class ThemeAppearanceService : IThemeAppearanceService
|
||||
changedKeys.Add(nameof(AppSettingsSnapshot.UseSystemChrome));
|
||||
}
|
||||
|
||||
if (Math.Abs(GlobalAppearanceSettings.NormalizeCornerRadiusScale(snapshot.GlobalCornerRadiusScale) - normalizedCornerRadiusScale) > 0.0001d)
|
||||
{
|
||||
snapshot.GlobalCornerRadiusScale = normalizedCornerRadiusScale;
|
||||
changedKeys.Add(nameof(AppSettingsSnapshot.GlobalCornerRadiusScale));
|
||||
}
|
||||
|
||||
if (!string.Equals(snapshot.ThemeColorMode, normalizedThemeColorMode, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
snapshot.ThemeColorMode = normalizedThemeColorMode;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<Setter Property="Background" Value="{DynamicResource EditorSelectFieldBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource EditorSelectOutlineBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="18" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusMd}" />
|
||||
<Setter Property="Padding" Value="16,14,12,14" />
|
||||
<Setter Property="MinHeight" Value="56" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
@@ -40,7 +40,7 @@
|
||||
<Setter Property="Background" Value="{DynamicResource EditorSelectFieldBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource EditorSelectOutlineBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="18" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusMd}" />
|
||||
<Setter Property="Padding" Value="16,14,12,14" />
|
||||
<Setter Property="MinHeight" Value="56" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ComponentEditorPrimaryTextBrush}" />
|
||||
@@ -61,7 +61,7 @@
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Padding" Value="16,12" />
|
||||
<Setter Property="Margin" Value="6,4" />
|
||||
<Setter Property="CornerRadius" Value="14" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusSm}" />
|
||||
<Setter Property="MinHeight" Value="44" />
|
||||
</Style>
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
<Setter Property="Background" Value="{DynamicResource EditorSurfaceContainerHighBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource EditorSelectOutlineBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="20" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusLg}" />
|
||||
<Setter Property="Padding" Value="4" />
|
||||
</Style>
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="16" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusSm}" />
|
||||
<Setter Property="Padding" Value="18,12" />
|
||||
<Setter Property="MinHeight" Value="48" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
@@ -139,14 +139,14 @@
|
||||
<Setter Property="Background" Value="{DynamicResource ComponentEditorHeroBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ComponentEditorCardBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="28" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusXl}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="Border.component-editor-card">
|
||||
<Setter Property="Background" Value="{DynamicResource ComponentEditorCardBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ComponentEditorCardBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="24" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusLg}" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="TextBlock.component-editor-headline">
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
|
||||
<Styles.Resources>
|
||||
<!-- Unified corner radius tokens used across settings and widget panels -->
|
||||
<CornerRadius x:Key="DesignCornerRadiusMicro">6</CornerRadius>
|
||||
<CornerRadius x:Key="DesignCornerRadiusXl">32</CornerRadius>
|
||||
<CornerRadius x:Key="DesignCornerRadiusLg">28</CornerRadius>
|
||||
<CornerRadius x:Key="DesignCornerRadiusMd">20</CornerRadius>
|
||||
<CornerRadius x:Key="DesignCornerRadiusSm">14</CornerRadius>
|
||||
<CornerRadius x:Key="DesignCornerRadiusXs">12</CornerRadius>
|
||||
<CornerRadius x:Key="DesignCornerRadiusIsland">36</CornerRadius>
|
||||
</Styles.Resources>
|
||||
|
||||
<Style Selector="TextBlock">
|
||||
@@ -19,7 +21,7 @@
|
||||
<Setter Property="Background" Value="{DynamicResource AdaptiveButtonBackgroundBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AdaptiveButtonBorderBrush}" />
|
||||
<Setter Property="CornerRadius" Value="20" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusMd}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource AdaptiveTextPrimaryBrush}" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="Padding" Value="16,10" />
|
||||
@@ -155,7 +157,7 @@
|
||||
|
||||
<Style Selector="Button.swatch-button">
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="16" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusXs}" />
|
||||
<Setter Property="Opacity" Value="0.88" />
|
||||
</Style>
|
||||
|
||||
@@ -175,7 +177,7 @@
|
||||
<Setter Property="Background" Value="{DynamicResource AdaptiveGlassPanelBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AdaptiveGlassPanelBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1.2" />
|
||||
<Setter Property="CornerRadius" Value="28" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusLg}" />
|
||||
<Setter Property="Opacity" Value="{DynamicResource AdaptiveGlassPanelOpacity}" />
|
||||
<Setter Property="BoxShadow" Value="0 4 12 #1A000000" />
|
||||
</Style>
|
||||
@@ -184,7 +186,7 @@
|
||||
<Setter Property="Background" Value="{DynamicResource AdaptiveGlassStrongBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AdaptiveGlassStrongBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1.5" />
|
||||
<Setter Property="CornerRadius" Value="32" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusXl}" />
|
||||
<Setter Property="Opacity" Value="{DynamicResource AdaptiveGlassStrongOpacity}" />
|
||||
<Setter Property="BoxShadow" Value="0 8 24 #26000000" />
|
||||
</Style>
|
||||
@@ -193,7 +195,7 @@
|
||||
<Setter Property="Background" Value="{DynamicResource AdaptiveDockGlassBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AdaptiveDockGlassBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1.5" />
|
||||
<Setter Property="CornerRadius" Value="36" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusIsland}" />
|
||||
<Setter Property="Opacity" Value="{DynamicResource AdaptiveGlassStrongOpacity}" />
|
||||
<Setter Property="BoxShadow" Value="0 12 32 #33000000" />
|
||||
<Setter Property="Transitions">
|
||||
@@ -206,7 +208,7 @@
|
||||
<Style Selector="Border.surface-solid-strong">
|
||||
<Setter Property="Background" Value="{DynamicResource AdaptiveGlassStrongBackgroundBrush}" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="36" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusIsland}" />
|
||||
<Setter Property="Opacity" Value="{DynamicResource AdaptiveGlassStrongOpacity}" />
|
||||
<Setter Property="BoxShadow" Value="0 8 22 #2A000000" />
|
||||
</Style>
|
||||
|
||||
@@ -48,21 +48,21 @@
|
||||
</Style>
|
||||
|
||||
<Style Selector="Border.settings-section-card">
|
||||
<Setter Property="CornerRadius" Value="18" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusLg}" />
|
||||
<Setter Property="Padding" Value="20" />
|
||||
<Setter Property="Margin" Value="0,0,0,14" />
|
||||
<Setter Property="BoxShadow" Value="0 2 8 #12000000" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="Border.settings-option-card">
|
||||
<Setter Property="CornerRadius" Value="14" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusSm}" />
|
||||
<Setter Property="Padding" Value="16" />
|
||||
<Setter Property="Margin" Value="0,0,0,12" />
|
||||
<Setter Property="BoxShadow" Value="0 1 4 #0F000000" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="Border.settings-list-item">
|
||||
<Setter Property="CornerRadius" Value="14" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusSm}" />
|
||||
<Setter Property="Padding" Value="16" />
|
||||
<Setter Property="Margin" Value="0,0,0,10" />
|
||||
<Setter Property="BoxShadow" Value="0 1 4 #0F000000" />
|
||||
@@ -77,7 +77,7 @@
|
||||
<Setter Property="Background" Value="{DynamicResource AdaptiveButtonBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AdaptiveButtonBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="12" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusXs}" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
</Style>
|
||||
@@ -201,7 +201,7 @@
|
||||
<Setter Property="Background" Value="{DynamicResource AdaptiveSurfaceRaisedBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AdaptiveGlassPanelBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="12" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusXs}" />
|
||||
<Setter Property="Padding" Value="14,12" />
|
||||
<Setter Property="Margin" Value="0,0,0,8" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
@@ -229,7 +229,7 @@
|
||||
<Setter Property="Background" Value="{DynamicResource AdaptiveAccentBrush}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource AdaptiveOnAccentBrush}" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="10" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusXs}" />
|
||||
<Setter Property="Padding" Value="16,10" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
</Style>
|
||||
@@ -254,7 +254,7 @@
|
||||
<Setter Property="Width" Value="36" />
|
||||
<Setter Property="Height" Value="36" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="10" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusXs}" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="Background" Value="{DynamicResource AdaptiveButtonBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource AdaptiveButtonBorderBrush}" />
|
||||
|
||||
@@ -12,6 +12,7 @@ using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Services.Settings;
|
||||
using LanMountainDesktop.Settings.Core;
|
||||
|
||||
namespace LanMountainDesktop.ViewModels;
|
||||
|
||||
@@ -481,6 +482,9 @@ public sealed partial class AppearanceSettingsPageViewModel : ViewModelBase
|
||||
[ObservableProperty]
|
||||
private bool _useSystemChrome;
|
||||
|
||||
[ObservableProperty]
|
||||
private double _globalCornerRadiusScale = GlobalAppearanceSettings.DefaultCornerRadiusScale;
|
||||
|
||||
[ObservableProperty]
|
||||
private SelectionOption _selectedThemeColorMode = new(ThemeAppearanceValues.ColorModeSeedMonet, "User theme color Monet");
|
||||
|
||||
@@ -547,6 +551,12 @@ public sealed partial class AppearanceSettingsPageViewModel : ViewModelBase
|
||||
[ObservableProperty]
|
||||
private string _systemMaterialLabel = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _globalCornerRadiusLabel = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _globalCornerRadiusDescription = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _themeHeader = string.Empty;
|
||||
|
||||
@@ -668,6 +678,32 @@ public sealed partial class AppearanceSettingsPageViewModel : ViewModelBase
|
||||
PersistCurrentState(restartRequired: false);
|
||||
}
|
||||
|
||||
partial void OnGlobalCornerRadiusScaleChanged(double value)
|
||||
{
|
||||
if (_isInitializing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var normalized = GlobalAppearanceSettings.NormalizeCornerRadiusScale(value);
|
||||
if (Math.Abs(normalized - value) > 0.0001d)
|
||||
{
|
||||
_isInitializing = true;
|
||||
try
|
||||
{
|
||||
GlobalCornerRadiusScale = normalized;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isInitializing = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PersistCurrentState(restartRequired: false);
|
||||
}
|
||||
|
||||
partial void OnSelectedThemeColorModeChanged(SelectionOption value)
|
||||
{
|
||||
if (_isInitializing || value is null)
|
||||
@@ -732,6 +768,8 @@ public sealed partial class AppearanceSettingsPageViewModel : ViewModelBase
|
||||
ThemeColorLabel = L("settings.color.theme_color_label", "Theme Accent Color");
|
||||
ThemeColorModeLabel = L("settings.appearance.theme_color_mode_label", "Theme color source");
|
||||
SystemMaterialLabel = L("settings.appearance.system_material_label", "System material");
|
||||
GlobalCornerRadiusLabel = L("settings.appearance.corner_radius.label", "Global corner radius");
|
||||
GlobalCornerRadiusDescription = L("settings.appearance.corner_radius.description", "Adjust the shared radius scale used by cards, panels, and component containers.");
|
||||
ThemeSourceNeutralText = L("settings.appearance.theme_color_mode.neutral", "Default neutral");
|
||||
ThemeSourceUserColorText = L("settings.appearance.theme_color_mode.user", "User theme color Monet");
|
||||
ThemeSourceWallpaperText = L("settings.appearance.theme_color_mode.wallpaper", "Wallpaper Monet");
|
||||
@@ -776,6 +814,7 @@ public sealed partial class AppearanceSettingsPageViewModel : ViewModelBase
|
||||
IsNightMode = theme.IsNightMode;
|
||||
ThemeColor = theme.ThemeColor ?? string.Empty;
|
||||
UseSystemChrome = theme.UseSystemChrome;
|
||||
GlobalCornerRadiusScale = GlobalAppearanceSettings.NormalizeCornerRadiusScale(theme.GlobalCornerRadiusScale);
|
||||
_selectedWallpaperSeed = theme.SelectedWallpaperSeed;
|
||||
SyncCustomSeedPickerWithSavedThemeColor();
|
||||
|
||||
@@ -825,6 +864,7 @@ public sealed partial class AppearanceSettingsPageViewModel : ViewModelBase
|
||||
IsNightMode,
|
||||
themeColor,
|
||||
UseSystemChrome,
|
||||
GlobalAppearanceSettings.NormalizeCornerRadiusScale(GlobalCornerRadiusScale),
|
||||
themeColorMode,
|
||||
ThemeAppearanceValues.NormalizeSystemMaterialMode(SelectedSystemMaterialMode?.Value),
|
||||
_selectedWallpaperSeed);
|
||||
@@ -956,7 +996,7 @@ public sealed partial class ComponentsSettingsPageViewModel : ViewModelBase
|
||||
private string _pageDescription = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _gridHeader = string.Empty;
|
||||
private string _componentsHeader = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _shortSideCellsLabel = string.Empty;
|
||||
@@ -967,6 +1007,18 @@ public sealed partial class ComponentsSettingsPageViewModel : ViewModelBase
|
||||
[ObservableProperty]
|
||||
private string _spacingPresetLabel = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private double _globalCornerRadiusScale = GlobalAppearanceSettings.DefaultCornerRadiusScale;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _componentRadiusHeader = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _globalCornerRadiusLabel = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _globalCornerRadiusDescription = string.Empty;
|
||||
|
||||
public void Load()
|
||||
{
|
||||
var state = _settingsFacade.Grid.Get();
|
||||
@@ -976,6 +1028,9 @@ public sealed partial class ComponentsSettingsPageViewModel : ViewModelBase
|
||||
SelectedSpacingPreset = SpacingPresets.FirstOrDefault(option =>
|
||||
string.Equals(option.Value, spacingPreset, StringComparison.OrdinalIgnoreCase))
|
||||
?? SpacingPresets[1];
|
||||
|
||||
var theme = _settingsFacade.Theme.Get();
|
||||
GlobalCornerRadiusScale = GlobalAppearanceSettings.NormalizeCornerRadiusScale(theme.GlobalCornerRadiusScale);
|
||||
}
|
||||
|
||||
partial void OnShortSideCellsChanged(int value)
|
||||
@@ -1008,6 +1063,32 @@ public sealed partial class ComponentsSettingsPageViewModel : ViewModelBase
|
||||
SaveGrid();
|
||||
}
|
||||
|
||||
partial void OnGlobalCornerRadiusScaleChanged(double value)
|
||||
{
|
||||
if (_isInitializing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var normalized = GlobalAppearanceSettings.NormalizeCornerRadiusScale(value);
|
||||
if (Math.Abs(normalized - value) > 0.0001d)
|
||||
{
|
||||
_isInitializing = true;
|
||||
try
|
||||
{
|
||||
GlobalCornerRadiusScale = normalized;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isInitializing = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SaveComponentCornerRadius();
|
||||
}
|
||||
|
||||
private void SaveGrid()
|
||||
{
|
||||
_settingsFacade.Grid.Save(new GridSettingsState(
|
||||
@@ -1016,23 +1097,39 @@ public sealed partial class ComponentsSettingsPageViewModel : ViewModelBase
|
||||
Math.Clamp(EdgeInsetPercent, 0, 30)));
|
||||
}
|
||||
|
||||
private void SaveComponentCornerRadius()
|
||||
{
|
||||
var theme = _settingsFacade.Theme.Get();
|
||||
_settingsFacade.Theme.Save(new ThemeAppearanceSettingsState(
|
||||
theme.IsNightMode,
|
||||
theme.ThemeColor,
|
||||
theme.UseSystemChrome,
|
||||
GlobalAppearanceSettings.NormalizeCornerRadiusScale(GlobalCornerRadiusScale),
|
||||
theme.ThemeColorMode,
|
||||
theme.SystemMaterialMode,
|
||||
theme.SelectedWallpaperSeed));
|
||||
}
|
||||
|
||||
private IReadOnlyList<SelectionOption> CreateSpacingPresets()
|
||||
{
|
||||
return
|
||||
[
|
||||
new SelectionOption("Compact", L("settings.grid.spacing_compact", "Compact")),
|
||||
new SelectionOption("Relaxed", L("settings.grid.spacing_relaxed", "Relaxed"))
|
||||
new SelectionOption("Compact", L("settings.components.spacing_compact", "Compact")),
|
||||
new SelectionOption("Relaxed", L("settings.components.spacing_relaxed", "Relaxed"))
|
||||
];
|
||||
}
|
||||
|
||||
private void RefreshLocalizedText()
|
||||
{
|
||||
PageTitle = L("settings.components.title", "Components");
|
||||
PageDescription = L("settings.components.description", "Desktop grid and widget placement density.");
|
||||
GridHeader = L("settings.components.grid_header", "Grid Layout");
|
||||
ShortSideCellsLabel = L("settings.grid.short_side_label", "Short Side Cells");
|
||||
EdgeInsetPercentLabel = L("settings.grid.edge_inset_label", "Screen Inset");
|
||||
SpacingPresetLabel = L("settings.grid.spacing_label", "Grid Spacing");
|
||||
PageDescription = L("settings.components.description", "Adjust component layout and corner design.");
|
||||
ComponentsHeader = L("settings.components.header", "Grid Settings");
|
||||
ShortSideCellsLabel = L("settings.components.short_side_label", "Short Side Cells");
|
||||
EdgeInsetPercentLabel = L("settings.components.edge_inset_label", "Screen Inset");
|
||||
SpacingPresetLabel = L("settings.components.spacing_label", "Component Spacing");
|
||||
ComponentRadiusHeader = L("settings.components.corner_radius.header", "Corner Design");
|
||||
GlobalCornerRadiusLabel = L("settings.components.corner_radius.label", "Component Corner Radius");
|
||||
GlobalCornerRadiusDescription = L("settings.components.corner_radius.description", "Adjust the shared corner radius used by component containers, and expand the internal safe area with it.");
|
||||
}
|
||||
|
||||
private string L(string key, string fallback)
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
<!-- MD3 Button Styles -->
|
||||
<Style Selector="Button.component-editor-footer-button">
|
||||
<Setter Property="CornerRadius" Value="20" />
|
||||
<Setter Property="CornerRadius" Value="{DynamicResource DesignCornerRadiusMd}" />
|
||||
<Setter Property="Background" Value="{DynamicResource EditorPrimaryBrush}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource EditorOnPrimaryBrush}" />
|
||||
<Setter Property="Height" Value="40" />
|
||||
@@ -118,7 +118,7 @@
|
||||
Height="64"
|
||||
Background="{DynamicResource EditorPrimaryBrush}"
|
||||
Foreground="{DynamicResource EditorOnPrimaryBrush}"
|
||||
CornerRadius="18"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusMd}"
|
||||
Classes="accent"
|
||||
Click="OnCloseClick">
|
||||
<Button.Styles>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
ColumnDefinitions="240,*"
|
||||
ColumnSpacing="12">
|
||||
<Border Classes="surface-translucent-panel"
|
||||
CornerRadius="24"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusLg}"
|
||||
Padding="10">
|
||||
<ListBox x:Name="CategoryListBox"
|
||||
Background="Transparent"
|
||||
@@ -50,7 +50,7 @@
|
||||
<DataTemplate x:DataType="vm:ComponentLibraryCategoryViewModel">
|
||||
<Border Padding="10"
|
||||
Margin="0,0,0,6"
|
||||
CornerRadius="14"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusSm}"
|
||||
Background="{DynamicResource AdaptiveNavItemBackgroundBrush}">
|
||||
<Grid ColumnDefinitions="Auto,*"
|
||||
ColumnSpacing="8">
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
<Border Grid.Column="1"
|
||||
Classes="surface-translucent-strong"
|
||||
CornerRadius="24"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusLg}"
|
||||
Padding="10">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled">
|
||||
@@ -87,14 +87,14 @@
|
||||
<Border Width="240"
|
||||
Height="220"
|
||||
Margin="6"
|
||||
CornerRadius="18"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusLg}"
|
||||
Padding="10"
|
||||
Background="{DynamicResource AdaptiveSurfaceRaisedBrush}"
|
||||
BorderBrush="{DynamicResource AdaptiveButtonBorderBrush}"
|
||||
BorderThickness="1">
|
||||
<Grid RowDefinitions="*,Auto,Auto"
|
||||
RowSpacing="8">
|
||||
<Border CornerRadius="12"
|
||||
<Border CornerRadius="{DynamicResource DesignCornerRadiusXs}"
|
||||
Background="{DynamicResource AdaptiveGlassPanelBackgroundBrush}"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{DynamicResource AdaptiveGlassPanelBorderBrush}"
|
||||
|
||||
@@ -326,7 +326,7 @@ public partial class AnalogClockWidget : UserControl, IDesktopComponentWidget, I
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = ResolveScale();
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(42 * scale, 16, 56));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(42 * scale, 16, 56);
|
||||
RootBorder.Padding = new Thickness(Math.Clamp(14 * scale, 8, 26));
|
||||
ApplyModeVisualIfNeeded();
|
||||
}
|
||||
|
||||
@@ -381,12 +381,12 @@ public partial class BaiduHotSearchWidget : UserControl, IDesktopComponentWidget
|
||||
var totalWidth = Bounds.Width > 1 ? Bounds.Width : _currentCellSize * BaseWidthCells;
|
||||
var totalHeight = Bounds.Height > 1 ? Bounds.Height : _currentCellSize * BaseHeightCells;
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(34 * softScale, 16, 52));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * softScale, 16, 52);
|
||||
RootBorder.Padding = new Thickness(0);
|
||||
|
||||
var horizontalPadding = Math.Clamp(16 * softScale, 8, 24);
|
||||
var verticalPadding = Math.Clamp(14 * softScale, 7, 20);
|
||||
CardBorder.CornerRadius = new CornerRadius(Math.Clamp(34 * softScale, 16, 52));
|
||||
CardBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * softScale, 16, 52);
|
||||
CardBorder.Padding = new Thickness(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
|
||||
|
||||
var innerWidth = Math.Max(120, totalWidth - (horizontalPadding * 2d));
|
||||
|
||||
@@ -386,12 +386,12 @@ public partial class BilibiliHotSearchWidget : UserControl, IDesktopComponentWid
|
||||
var totalWidth = Bounds.Width > 1 ? Bounds.Width : _currentCellSize * BaseWidthCells;
|
||||
var totalHeight = Bounds.Height > 1 ? Bounds.Height : _currentCellSize * BaseHeightCells;
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(34 * softScale, 16, 52));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * softScale, 16, 52);
|
||||
RootBorder.Padding = new Thickness(0);
|
||||
|
||||
var horizontalPadding = Math.Clamp(16 * softScale, 8, 24);
|
||||
var verticalPadding = Math.Clamp(14 * softScale, 7, 20);
|
||||
CardBorder.CornerRadius = new CornerRadius(Math.Clamp(34 * softScale, 16, 52));
|
||||
CardBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * softScale, 16, 52);
|
||||
CardBorder.Padding = new Thickness(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
|
||||
|
||||
var innerWidth = Math.Max(120, totalWidth - (horizontalPadding * 2d));
|
||||
|
||||
@@ -79,11 +79,11 @@ public partial class BrowserWidget : UserControl, IDesktopComponentWidget,
|
||||
{
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.34, 12, 28));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.34, 12, 28);
|
||||
RootBorder.Padding = new Thickness(Math.Clamp(_currentCellSize * 0.20, 8, 18));
|
||||
|
||||
WebViewHostBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.24, 10, 22));
|
||||
AddressBarBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.22, 10, 20));
|
||||
WebViewHostBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.24, 10, 22);
|
||||
AddressBarBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.22, 10, 20);
|
||||
AddressBarBorder.Padding = new Thickness(8, 6);
|
||||
|
||||
if (RootBorder.Child is Grid rootGrid)
|
||||
|
||||
@@ -613,18 +613,17 @@ public partial class ClassScheduleWidget : UserControl, IDesktopComponentWidget,
|
||||
? CreateBrush("#FF4FC3F7")
|
||||
: CreateBrush("#FF3250");
|
||||
|
||||
var cornerRadius = Math.Clamp(_currentCellSize * 0.45, 24, 44);
|
||||
RootBorder.CornerRadius = new CornerRadius(cornerRadius);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.45, 24, 44);
|
||||
RootBorder.Background = _isNightVisual
|
||||
? CreateGradientBrush("#171A21", "#0C0E14")
|
||||
: CreateGradientBrush("#F7F8FC", "#ECEFF6");
|
||||
RootBorder.BorderBrush = CreateBrush(_isNightVisual ? "#24FFFFFF" : "#15000000");
|
||||
|
||||
var rootPadding = new Thickness(
|
||||
Math.Clamp(16 * scale, 10, 24),
|
||||
Math.Clamp(14 * scale, 9, 20),
|
||||
Math.Clamp(16 * scale, 10, 24),
|
||||
Math.Clamp(14 * scale, 8, 20));
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(16 * scale, 10, 24),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(14 * scale, 9, 20),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(16 * scale, 10, 24),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(14 * scale, 8, 20));
|
||||
RootBorder.Padding = rootPadding;
|
||||
|
||||
LayoutGrid.RowSpacing = Math.Clamp(14 * scale, 6, 20);
|
||||
|
||||
@@ -480,7 +480,7 @@ public partial class CnrDailyNewsWidget : UserControl, IDesktopComponentWidget,
|
||||
{
|
||||
Width = 160,
|
||||
Height = 90,
|
||||
CornerRadius = new CornerRadius(16),
|
||||
CornerRadius = ComponentChromeCornerRadiusHelper.Scale(16, 8, 22),
|
||||
ClipToBounds = true,
|
||||
Background = new SolidColorBrush(Color.Parse("#E6E6E6")),
|
||||
IsHitTestVisible = false
|
||||
@@ -545,10 +545,10 @@ public partial class CnrDailyNewsWidget : UserControl, IDesktopComponentWidget,
|
||||
var scale = ResolveScale();
|
||||
var totalWidth = Bounds.Width > 1 ? Bounds.Width : _currentCellSize * BaseWidthCells;
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(34 * scale, 16, 52));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 16, 52);
|
||||
RootBorder.Padding = new Thickness(0);
|
||||
|
||||
CardBorder.CornerRadius = new CornerRadius(Math.Clamp(34 * scale, 16, 52));
|
||||
CardBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 16, 52);
|
||||
CardBorder.Padding = new Thickness(
|
||||
Math.Clamp(16 * scale, 8, 24),
|
||||
Math.Clamp(14 * scale, 7, 22),
|
||||
@@ -573,8 +573,8 @@ public partial class CnrDailyNewsWidget : UserControl, IDesktopComponentWidget,
|
||||
News1ImageHost.Height = imageHeight;
|
||||
News2ImageHost.Width = imageWidth;
|
||||
News2ImageHost.Height = imageHeight;
|
||||
News1ImageHost.CornerRadius = new CornerRadius(Math.Clamp(16 * scale, 8, 22));
|
||||
News2ImageHost.CornerRadius = new CornerRadius(Math.Clamp(16 * scale, 8, 22));
|
||||
News1ImageHost.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(16 * scale, 8, 22);
|
||||
News2ImageHost.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(16 * scale, 8, 22);
|
||||
|
||||
var columnGap = Math.Clamp(12 * scale, 6, 18);
|
||||
NewsItem1Grid.ColumnSpacing = columnGap;
|
||||
@@ -611,7 +611,7 @@ public partial class CnrDailyNewsWidget : UserControl, IDesktopComponentWidget,
|
||||
|
||||
row.ImageHost.Width = imageWidth;
|
||||
row.ImageHost.Height = imageHeight;
|
||||
row.ImageHost.CornerRadius = new CornerRadius(Math.Clamp(16 * scale, 8, 22));
|
||||
row.ImageHost.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(16 * scale, 8, 22);
|
||||
|
||||
row.TitleTextBlock.MaxWidth = availableTextWidth;
|
||||
row.TitleTextBlock.FontSize = Math.Clamp(19 * scale, 10, 25);
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using LanMountainDesktop.Host.Abstractions;
|
||||
using LanMountainDesktop.Services;
|
||||
|
||||
namespace LanMountainDesktop.Views.Components;
|
||||
|
||||
internal static class ComponentChromeCornerRadiusHelper
|
||||
{
|
||||
public static double ResolveScale(ComponentChromeContext? chromeContext = null)
|
||||
{
|
||||
if (chromeContext is not null)
|
||||
{
|
||||
return Math.Max(0.1d, chromeContext.GlobalCornerRadiusScale);
|
||||
}
|
||||
|
||||
return Math.Max(0.1d, HostAppearanceThemeProvider.GetOrCreate().GetCurrent().GlobalCornerRadiusScale);
|
||||
}
|
||||
|
||||
public static CornerRadius Scale(double baseRadius, double min, double max, ComponentChromeContext? chromeContext = null)
|
||||
{
|
||||
var scale = ResolveScale(chromeContext);
|
||||
return new CornerRadius(Math.Clamp(baseRadius * scale, min * scale, max * scale));
|
||||
}
|
||||
|
||||
public static void Apply(CornerRadius radius, params Border?[] chromeLayers)
|
||||
{
|
||||
foreach (var chromeLayer in chromeLayers)
|
||||
{
|
||||
if (chromeLayer is not null)
|
||||
{
|
||||
chromeLayer.CornerRadius = radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static CornerRadius ResolveToken(string key, double fallback)
|
||||
{
|
||||
var application = Application.Current;
|
||||
return application is not null &&
|
||||
application.Resources.TryGetResource(key, application.ActualThemeVariant, out var resource) &&
|
||||
resource is CornerRadius radius
|
||||
? radius
|
||||
: new CornerRadius(fallback);
|
||||
}
|
||||
|
||||
public static double ScaleValue(double value, ComponentChromeContext? chromeContext = null)
|
||||
{
|
||||
return value * ResolveScale(chromeContext);
|
||||
}
|
||||
|
||||
public static double ResolveContentSafetyScale(
|
||||
ComponentChromeContext? chromeContext = null,
|
||||
double responsiveness = 0.45d)
|
||||
{
|
||||
var scale = ResolveScale(chromeContext);
|
||||
var normalizedResponsiveness = Math.Clamp(responsiveness, 0d, 1d);
|
||||
return 1d + ((scale - 1d) * normalizedResponsiveness);
|
||||
}
|
||||
|
||||
public static double SafeValue(
|
||||
double baseValue,
|
||||
double min,
|
||||
double max,
|
||||
ComponentChromeContext? chromeContext = null,
|
||||
double responsiveness = 0.45d)
|
||||
{
|
||||
var safetyScale = ResolveContentSafetyScale(chromeContext, responsiveness);
|
||||
return Math.Clamp(baseValue * safetyScale, min * safetyScale, max * safetyScale);
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ public partial class DailyArtworkWidget : UserControl, IDesktopComponentWidget,
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = ResolveScale();
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(34 * scale, 16, 52));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 16, 52);
|
||||
|
||||
InfoPanel.Padding = new Thickness(
|
||||
Math.Clamp(18 * scale, 10, 28),
|
||||
|
||||
@@ -92,7 +92,7 @@ public partial class DailyPoetryWidget : UserControl, IDesktopComponentWidget, I
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = ResolveScale();
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(34 * scale, 16, 52));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 16, 52);
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(20 * scale, 10, 34),
|
||||
Math.Clamp(16 * scale, 8, 28),
|
||||
|
||||
@@ -328,7 +328,7 @@ public partial class DailyWord2x2Widget : UserControl, IDesktopComponentWidget,
|
||||
var totalWidth = Bounds.Width > 1 ? Bounds.Width : _currentCellSize * BaseWidthCells;
|
||||
var totalHeight = Bounds.Height > 1 ? Bounds.Height : _currentCellSize * BaseHeightCells;
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(30 * scale, 14, 40));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(30 * scale, 14, 40);
|
||||
CardBorder.CornerRadius = RootBorder.CornerRadius;
|
||||
CardBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale, 8, 18),
|
||||
|
||||
@@ -298,10 +298,11 @@ public partial class DailyWordWidget : UserControl, IDesktopComponentWidget, IRe
|
||||
isFourByThree = widthRatio >= 0.9 && heightRatio >= 1.35;
|
||||
}
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(34 * scale, 16, 52));
|
||||
var containerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 16, 52);
|
||||
RootBorder.CornerRadius = containerRadius;
|
||||
RootBorder.Padding = new Thickness(0);
|
||||
|
||||
CardBorder.CornerRadius = new CornerRadius(Math.Clamp(34 * scale, 16, 52));
|
||||
CardBorder.CornerRadius = containerRadius;
|
||||
CardBorder.Padding = new Thickness(
|
||||
Math.Clamp(16 * scale, 8, 24),
|
||||
Math.Clamp(14 * scale, 7, 22),
|
||||
|
||||
@@ -325,7 +325,7 @@ public partial class DateWidget : UserControl, IDesktopComponentWidget, ITimeZon
|
||||
{
|
||||
var scale = ResolveScale();
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(28 * scale, 16, 40));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(28 * scale, 16, 40);
|
||||
RootBorder.Padding = new Thickness(Math.Clamp(11 * scale, 7, 17));
|
||||
|
||||
LayoutRoot.ColumnSpacing = Math.Clamp(10 * scale, 6, 16);
|
||||
@@ -337,7 +337,7 @@ public partial class DateWidget : UserControl, IDesktopComponentWidget, ITimeZon
|
||||
Math.Clamp(2.4 * scale, 1, 4));
|
||||
CalendarGrid.Margin = new Thickness(0, 0, 0, Math.Clamp(0.8 * scale, 0, 2));
|
||||
|
||||
LunarCardBorder.CornerRadius = new CornerRadius(Math.Clamp(24 * scale, 14, 34));
|
||||
LunarCardBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(24 * scale, 14, 34);
|
||||
LunarCardBorder.Padding = new Thickness(Math.Clamp(14 * scale, 8, 20));
|
||||
RightPanelGrid.RowSpacing = Math.Clamp(7.5 * scale, 3.5, 11);
|
||||
DividerBorder.Margin = new Thickness(0, Math.Clamp(1 * scale, 0, 2), 0, Math.Clamp(1 * scale, 0, 2));
|
||||
|
||||
@@ -3,7 +3,9 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Avalonia.Controls;
|
||||
using LanMountainDesktop.Appearance;
|
||||
using LanMountainDesktop.ComponentSystem;
|
||||
using LanMountainDesktop.Host.Abstractions;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Services.Settings;
|
||||
@@ -30,7 +32,11 @@ public sealed class DesktopComponentRuntimeRegistration
|
||||
string? displayNameLocalizationKey,
|
||||
Func<Control> controlFactory,
|
||||
Func<double, double>? cornerRadiusResolver = null)
|
||||
: this(componentId, displayNameLocalizationKey, _ => controlFactory(), cornerRadiusResolver)
|
||||
: this(
|
||||
componentId,
|
||||
displayNameLocalizationKey,
|
||||
_ => controlFactory(),
|
||||
cornerRadiusResolver is null ? null : chromeContext => cornerRadiusResolver(chromeContext.CellSize))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -39,6 +45,19 @@ public sealed class DesktopComponentRuntimeRegistration
|
||||
string? displayNameLocalizationKey,
|
||||
Func<DesktopComponentControlFactoryContext, Control> controlFactory,
|
||||
Func<double, double>? cornerRadiusResolver = null)
|
||||
: this(
|
||||
componentId,
|
||||
displayNameLocalizationKey,
|
||||
controlFactory,
|
||||
cornerRadiusResolver is null ? null : chromeContext => cornerRadiusResolver(chromeContext.CellSize))
|
||||
{
|
||||
}
|
||||
|
||||
public DesktopComponentRuntimeRegistration(
|
||||
string componentId,
|
||||
string? displayNameLocalizationKey,
|
||||
Func<DesktopComponentControlFactoryContext, Control> controlFactory,
|
||||
Func<ComponentChromeContext, double>? cornerRadiusResolver = null)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(componentId);
|
||||
ArgumentNullException.ThrowIfNull(controlFactory);
|
||||
@@ -57,22 +76,27 @@ public sealed class DesktopComponentRuntimeRegistration
|
||||
|
||||
public Func<DesktopComponentControlFactoryContext, Control> ControlFactory { get; }
|
||||
|
||||
public Func<double, double>? CornerRadiusResolver { get; }
|
||||
public Func<ComponentChromeContext, double>? CornerRadiusResolver { get; }
|
||||
}
|
||||
|
||||
public sealed class DesktopComponentRuntimeDescriptor
|
||||
{
|
||||
private static readonly Func<double, double> DefaultCornerRadiusResolver =
|
||||
cellSize => Math.Clamp(cellSize * 0.22, 8, 18);
|
||||
private static readonly Func<ComponentChromeContext, double> DefaultCornerRadiusResolver =
|
||||
chromeContext =>
|
||||
{
|
||||
var scale = Math.Max(0.1d, chromeContext.GlobalCornerRadiusScale);
|
||||
var baseRadius = Math.Clamp(chromeContext.CellSize * 0.22, 8, 18);
|
||||
return Math.Clamp(baseRadius * scale, 8 * scale, 18 * scale);
|
||||
};
|
||||
|
||||
private readonly Func<DesktopComponentControlFactoryContext, Control> _controlFactory;
|
||||
private readonly Func<double, double> _cornerRadiusResolver;
|
||||
private readonly Func<ComponentChromeContext, double> _cornerRadiusResolver;
|
||||
|
||||
internal DesktopComponentRuntimeDescriptor(
|
||||
DesktopComponentDefinition definition,
|
||||
string? displayNameLocalizationKey,
|
||||
Func<DesktopComponentControlFactoryContext, Control> controlFactory,
|
||||
Func<double, double>? cornerRadiusResolver)
|
||||
Func<ComponentChromeContext, double>? cornerRadiusResolver)
|
||||
{
|
||||
Definition = definition;
|
||||
DisplayNameLocalizationKey = displayNameLocalizationKey;
|
||||
@@ -97,9 +121,16 @@ public sealed class DesktopComponentRuntimeDescriptor
|
||||
|
||||
var settingsService = settingsFacade.Settings;
|
||||
var appearanceTheme = HostAppearanceThemeProvider.GetOrCreate();
|
||||
var appearanceSnapshot = appearanceTheme.GetCurrent();
|
||||
var componentAccessor = settingsService.GetComponentAccessor(Definition.Id, placementId);
|
||||
var componentSettingsStore = new ComponentSettingsService(settingsService);
|
||||
componentSettingsStore.SetScopedComponentContext(Definition.Id, placementId);
|
||||
var chromeContext = new ComponentChromeContext(
|
||||
Definition.Id,
|
||||
placementId,
|
||||
cellSize,
|
||||
appearanceSnapshot.GlobalCornerRadiusScale,
|
||||
appearanceSnapshot.CornerRadiusTokens);
|
||||
var control = _controlFactory(new DesktopComponentControlFactoryContext(
|
||||
Definition,
|
||||
cellSize,
|
||||
@@ -118,6 +149,7 @@ public sealed class DesktopComponentRuntimeDescriptor
|
||||
settingsFacade,
|
||||
settingsService,
|
||||
appearanceTheme,
|
||||
chromeContext,
|
||||
componentAccessor,
|
||||
componentSettingsStore);
|
||||
|
||||
@@ -145,6 +177,11 @@ public sealed class DesktopComponentRuntimeDescriptor
|
||||
placementAwareComponent.SetComponentPlacementContext(Definition.Id, placementId);
|
||||
}
|
||||
|
||||
if (control is IComponentChromeContextAware chromeContextAwareComponent)
|
||||
{
|
||||
chromeContextAwareComponent.SetComponentChromeContext(chromeContext);
|
||||
}
|
||||
|
||||
if (control is IDesktopComponentWidget sizedComponent)
|
||||
{
|
||||
sizedComponent.ApplyCellSize(cellSize);
|
||||
@@ -173,9 +210,22 @@ public sealed class DesktopComponentRuntimeDescriptor
|
||||
return control;
|
||||
}
|
||||
|
||||
public double ResolveCornerRadius(ComponentChromeContext chromeContext)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(chromeContext);
|
||||
|
||||
var resolved = _cornerRadiusResolver(chromeContext with { CellSize = Math.Max(1, chromeContext.CellSize) });
|
||||
return double.IsFinite(resolved) ? Math.Max(0d, resolved) : DefaultCornerRadiusResolver(chromeContext);
|
||||
}
|
||||
|
||||
public double ResolveCornerRadius(double cellSize)
|
||||
{
|
||||
return _cornerRadiusResolver(Math.Max(1, cellSize));
|
||||
return ResolveCornerRadius(new ComponentChromeContext(
|
||||
Definition.Id,
|
||||
null,
|
||||
Math.Max(1, cellSize),
|
||||
1d,
|
||||
AppearanceCornerRadiusTokenFactory.Create(1d)));
|
||||
}
|
||||
|
||||
private static void ApplySettingsDependencies(
|
||||
|
||||
@@ -80,8 +80,8 @@ public partial class ExchangeRateCalculatorWidget : UserControl, IDesktopCompone
|
||||
{
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = ResolveScale();
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(34 * scale, 14, 48));
|
||||
RootBorder.Padding = new Thickness(Math.Clamp(12 * scale, 6, 18));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 14, 48);
|
||||
RootBorder.Padding = new Thickness(ComponentChromeCornerRadiusHelper.SafeValue(12 * scale, 6, 18));
|
||||
}
|
||||
|
||||
public void SetRecommendationInfoService(IRecommendationInfoService recommendationInfoService)
|
||||
|
||||
@@ -10,6 +10,7 @@ using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
using LanMountainDesktop.ComponentSystem;
|
||||
using LanMountainDesktop.Host.Abstractions;
|
||||
using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Services;
|
||||
@@ -18,7 +19,7 @@ using LanMountainDesktop.Theme;
|
||||
|
||||
namespace LanMountainDesktop.Views.Components;
|
||||
|
||||
public partial class ExtendedWeatherWidget : UserControl, IDesktopComponentWidget, IDesktopPageVisibilityAwareComponentWidget, ITimeZoneAwareComponentWidget, IWeatherInfoAwareComponentWidget, IComponentPlacementContextAware
|
||||
public partial class ExtendedWeatherWidget : UserControl, IDesktopComponentWidget, IDesktopPageVisibilityAwareComponentWidget, ITimeZoneAwareComponentWidget, IWeatherInfoAwareComponentWidget, IComponentPlacementContextAware, IComponentChromeContextAware
|
||||
{
|
||||
private static readonly IWeatherInfoService DefaultWeatherInfoService = new XiaomiWeatherService();
|
||||
private static readonly IReadOnlyList<int> SupportedAutoRefreshIntervalsMinutes = RefreshIntervalCatalog.SupportedIntervalsMinutes;
|
||||
@@ -34,6 +35,7 @@ public partial class ExtendedWeatherWidget : UserControl, IDesktopComponentWidge
|
||||
private TimeZoneService? _timeZoneService;
|
||||
private CancellationTokenSource? _refreshCts;
|
||||
private double _currentCellSize = 48;
|
||||
private ComponentChromeContext? _chromeContext;
|
||||
private double _phase;
|
||||
private bool _isAttached;
|
||||
private bool _isOnActivePage = true;
|
||||
@@ -122,21 +124,34 @@ public partial class ExtendedWeatherWidget : UserControl, IDesktopComponentWidge
|
||||
var metrics = HyperOS3WeatherTheme.ResolveMetrics(HyperOS3WeatherWidgetKind.Extended4x4);
|
||||
var width = Bounds.Width > 1 ? Bounds.Width : _currentCellSize * 4;
|
||||
var height = Bounds.Height > 1 ? Bounds.Height : _currentCellSize * 4;
|
||||
var radius = Math.Clamp(_currentCellSize * metrics.CornerRadiusScale, 28, 54);
|
||||
RootBorder.CornerRadius = new CornerRadius(radius);
|
||||
BackgroundImageLayer.CornerRadius = new CornerRadius(radius);
|
||||
BackgroundMotionLayer.CornerRadius = new CornerRadius(radius);
|
||||
BackgroundTintLayer.CornerRadius = new CornerRadius(radius);
|
||||
BackgroundLightLayer.CornerRadius = new CornerRadius(radius);
|
||||
BackgroundShadeLayer.CornerRadius = new CornerRadius(radius);
|
||||
var radius = ComponentChromeCornerRadiusHelper.Scale(
|
||||
_currentCellSize * metrics.CornerRadiusScale,
|
||||
28,
|
||||
54,
|
||||
_chromeContext);
|
||||
ComponentChromeCornerRadiusHelper.Apply(
|
||||
radius,
|
||||
RootBorder,
|
||||
BackgroundImageLayer,
|
||||
BackgroundMotionLayer,
|
||||
BackgroundTintLayer,
|
||||
BackgroundLightLayer,
|
||||
BackgroundShadeLayer);
|
||||
var horizontalPadding = Math.Clamp(Math.Min(width * metrics.HorizontalPaddingScale * 0.30, width * 0.11), 4, 34);
|
||||
var verticalPadding = Math.Clamp(Math.Min(height * metrics.VerticalPaddingScale * 0.30, height * 0.11), 4, 34);
|
||||
ContentPaddingBorder.Padding = new Thickness(
|
||||
horizontalPadding,
|
||||
verticalPadding);
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(horizontalPadding, 4, 34, _chromeContext),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(verticalPadding, 4, 34, _chromeContext));
|
||||
ApplyTypography(width, height);
|
||||
}
|
||||
|
||||
public void SetComponentChromeContext(ComponentChromeContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
_chromeContext = context;
|
||||
ApplyCellSize(_currentCellSize);
|
||||
}
|
||||
|
||||
public void SetTimeZoneService(TimeZoneService timeZoneService)
|
||||
{
|
||||
if (_timeZoneService is not null)
|
||||
|
||||
@@ -216,8 +216,8 @@ public partial class HolidayCalendarWidget : UserControl, IDesktopComponentWidge
|
||||
var titleNeedsTwoLines = isUltraCompact || titleUnits >= (isCompact ? 13 : 17);
|
||||
var dateNeedsTwoLines = isUltraCompact || dateUnits >= (isCompact ? 15 : 20);
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(shortSide * 0.13, 10, 46));
|
||||
var padding = Math.Clamp(shortSide * 0.05, 4.5, 21);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(shortSide * 0.13, 10, 46);
|
||||
var padding = ComponentChromeCornerRadiusHelper.SafeValue(shortSide * 0.05, 4.5, 21);
|
||||
RootBorder.Padding = new Thickness(padding);
|
||||
LayoutRoot.RowSpacing = Math.Clamp(shortSide * 0.028, 2.2, 12);
|
||||
var rowWeights = ApplyAdaptiveRowHeights(isCompact, isUltraCompact, titleNeedsTwoLines, dateNeedsTwoLines);
|
||||
|
||||
@@ -12,13 +12,14 @@ using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Threading;
|
||||
using LanMountainDesktop.ComponentSystem;
|
||||
using LanMountainDesktop.Host.Abstractions;
|
||||
using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Theme;
|
||||
|
||||
namespace LanMountainDesktop.Views.Components;
|
||||
|
||||
public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget, IDesktopPageVisibilityAwareComponentWidget, ITimeZoneAwareComponentWidget, IWeatherInfoAwareComponentWidget, IComponentPlacementContextAware
|
||||
public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget, IDesktopPageVisibilityAwareComponentWidget, ITimeZoneAwareComponentWidget, IWeatherInfoAwareComponentWidget, IComponentPlacementContextAware, IComponentChromeContextAware
|
||||
{
|
||||
private enum WeatherVisualKind
|
||||
{
|
||||
@@ -117,6 +118,7 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
|
||||
private WeatherSnapshot? _latestSnapshot;
|
||||
private string _languageCode = "zh-CN";
|
||||
private double _currentCellSize = 48;
|
||||
private ComponentChromeContext? _chromeContext;
|
||||
private WeatherVisualKind _activeVisualKind = WeatherVisualKind.ClearDay;
|
||||
private double _animationPhase;
|
||||
private int _activeParticleCount;
|
||||
@@ -254,6 +256,13 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
|
||||
}
|
||||
}
|
||||
|
||||
public void SetComponentChromeContext(ComponentChromeContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
_chromeContext = context;
|
||||
ApplyCellSize(_currentCellSize);
|
||||
}
|
||||
|
||||
public void ApplyCellSize(double cellSize)
|
||||
{
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
@@ -261,17 +270,23 @@ public partial class HourlyWeatherWidget : UserControl, IDesktopComponentWidget,
|
||||
var scale = ResolveScale();
|
||||
var hostWidth = Bounds.Width > 1 ? Bounds.Width : Math.Max(140, _currentCellSize * 4);
|
||||
var hostHeight = Bounds.Height > 1 ? Bounds.Height : Math.Max(78, _currentCellSize * 2);
|
||||
var cornerRadius = Math.Clamp(_currentCellSize * metrics.CornerRadiusScale, 24, 46);
|
||||
var cornerRadius = ComponentChromeCornerRadiusHelper.Scale(
|
||||
_currentCellSize * metrics.CornerRadiusScale,
|
||||
24,
|
||||
46,
|
||||
_chromeContext);
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundImageLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundMotionLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundTintLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundLightLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundShadeLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
ComponentChromeCornerRadiusHelper.Apply(
|
||||
cornerRadius,
|
||||
RootBorder,
|
||||
BackgroundImageLayer,
|
||||
BackgroundMotionLayer,
|
||||
BackgroundTintLayer,
|
||||
BackgroundLightLayer,
|
||||
BackgroundShadeLayer);
|
||||
ContentPaddingBorder.Padding = new Thickness(
|
||||
Math.Clamp(Math.Min((_currentCellSize * metrics.HorizontalPaddingScale) * scale, hostWidth * 0.034), 4, 22),
|
||||
Math.Clamp(Math.Min((_currentCellSize * metrics.VerticalPaddingScale) * scale, hostHeight * 0.068), 3, 18));
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(Math.Min((_currentCellSize * metrics.HorizontalPaddingScale) * scale, hostWidth * 0.034), 4, 22, _chromeContext),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(Math.Min((_currentCellSize * metrics.VerticalPaddingScale) * scale, hostHeight * 0.068), 3, 18, _chromeContext));
|
||||
ApplyAdaptiveTypography();
|
||||
ResetParticles();
|
||||
}
|
||||
|
||||
@@ -400,8 +400,8 @@ public partial class IfengNewsWidget : UserControl, IDesktopComponentWidget, IRe
|
||||
var totalWidth = Bounds.Width > 1 ? Bounds.Width : _currentCellSize * BaseWidthCells;
|
||||
var totalHeight = Bounds.Height > 1 ? Bounds.Height : _currentCellSize * BaseHeightCells;
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(32 * softScale, 16, 46));
|
||||
CardBorder.CornerRadius = new CornerRadius(Math.Clamp(32 * softScale, 16, 46));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(32 * softScale, 16, 46);
|
||||
CardBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(32 * softScale, 16, 46);
|
||||
|
||||
var horizontalPadding = Math.Clamp(14 * softScale, 8, 20);
|
||||
var verticalPadding = Math.Clamp(14 * softScale, 8, 20);
|
||||
@@ -452,7 +452,7 @@ public partial class IfengNewsWidget : UserControl, IDesktopComponentWidget, IRe
|
||||
|
||||
visual.ImageHost.Width = imageWidth;
|
||||
visual.ImageHost.Height = imageHeight;
|
||||
visual.ImageHost.CornerRadius = new CornerRadius(Math.Clamp(imageHeight * 0.15, 8, 16));
|
||||
visual.ImageHost.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(imageHeight * 0.15, 8, 16);
|
||||
|
||||
visual.TitleTextBlock.MaxWidth = textWidth;
|
||||
visual.TitleTextBlock.FontSize = titleFont;
|
||||
|
||||
@@ -182,8 +182,8 @@ public partial class LunarCalendarWidget : UserControl, IDesktopComponentWidget,
|
||||
{
|
||||
var scale = ResolveScale();
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(30 * scale, 16, 44));
|
||||
RootBorder.Padding = new Thickness(Math.Clamp(16 * scale, 8, 24));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(30 * scale, 16, 44);
|
||||
RootBorder.Padding = new Thickness(ComponentChromeCornerRadiusHelper.SafeValue(16 * scale, 8, 24));
|
||||
LayoutRoot.RowSpacing = Math.Clamp(10 * scale, 5, 18);
|
||||
DividerBorder.Margin = new Thickness(
|
||||
Math.Clamp(8 * scale, 3, 14),
|
||||
|
||||
@@ -217,8 +217,8 @@ public partial class MonthCalendarWidget : UserControl, IDesktopComponentWidget,
|
||||
{
|
||||
var scale = ResolveScale();
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(28 * scale, 14, 40));
|
||||
RootBorder.Padding = new Thickness(Math.Clamp(14 * scale, 8, 22));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(28 * scale, 14, 40);
|
||||
RootBorder.Padding = new Thickness(ComponentChromeCornerRadiusHelper.SafeValue(14 * scale, 8, 22));
|
||||
LayoutRoot.RowSpacing = Math.Clamp(10 * scale, 5, 16);
|
||||
LayoutRoot.Width = Math.Clamp(280 * scale, 220, 420);
|
||||
LayoutRoot.Height = Math.Clamp(280 * scale, 220, 420);
|
||||
|
||||
@@ -10,13 +10,14 @@ using Avalonia.Controls;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
using LanMountainDesktop.ComponentSystem;
|
||||
using LanMountainDesktop.Host.Abstractions;
|
||||
using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Theme;
|
||||
|
||||
namespace LanMountainDesktop.Views.Components;
|
||||
|
||||
public partial class MultiDayWeatherWidget : UserControl, IDesktopComponentWidget, IDesktopPageVisibilityAwareComponentWidget, ITimeZoneAwareComponentWidget, IWeatherInfoAwareComponentWidget, IComponentPlacementContextAware
|
||||
public partial class MultiDayWeatherWidget : UserControl, IDesktopComponentWidget, IDesktopPageVisibilityAwareComponentWidget, ITimeZoneAwareComponentWidget, IWeatherInfoAwareComponentWidget, IComponentPlacementContextAware, IComponentChromeContextAware
|
||||
{
|
||||
private enum WeatherVisualKind
|
||||
{
|
||||
@@ -115,6 +116,7 @@ public partial class MultiDayWeatherWidget : UserControl, IDesktopComponentWidge
|
||||
private WeatherSnapshot? _latestSnapshot;
|
||||
private string _languageCode = "zh-CN";
|
||||
private double _currentCellSize = 48;
|
||||
private ComponentChromeContext? _chromeContext;
|
||||
private WeatherVisualKind _activeVisualKind = WeatherVisualKind.ClearDay;
|
||||
private double _animationPhase;
|
||||
private int _activeParticleCount;
|
||||
@@ -252,6 +254,13 @@ public partial class MultiDayWeatherWidget : UserControl, IDesktopComponentWidge
|
||||
}
|
||||
}
|
||||
|
||||
public void SetComponentChromeContext(ComponentChromeContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
_chromeContext = context;
|
||||
ApplyCellSize(_currentCellSize);
|
||||
}
|
||||
|
||||
public void ApplyCellSize(double cellSize)
|
||||
{
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
@@ -259,17 +268,23 @@ public partial class MultiDayWeatherWidget : UserControl, IDesktopComponentWidge
|
||||
var scale = ResolveScale();
|
||||
var hostWidth = Bounds.Width > 1 ? Bounds.Width : Math.Max(140, _currentCellSize * 4);
|
||||
var hostHeight = Bounds.Height > 1 ? Bounds.Height : Math.Max(78, _currentCellSize * 2);
|
||||
var cornerRadius = Math.Clamp(_currentCellSize * metrics.CornerRadiusScale, 24, 46);
|
||||
var cornerRadius = ComponentChromeCornerRadiusHelper.Scale(
|
||||
_currentCellSize * metrics.CornerRadiusScale,
|
||||
24,
|
||||
46,
|
||||
_chromeContext);
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundImageLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundMotionLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundTintLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundLightLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundShadeLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
ComponentChromeCornerRadiusHelper.Apply(
|
||||
cornerRadius,
|
||||
RootBorder,
|
||||
BackgroundImageLayer,
|
||||
BackgroundMotionLayer,
|
||||
BackgroundTintLayer,
|
||||
BackgroundLightLayer,
|
||||
BackgroundShadeLayer);
|
||||
ContentPaddingBorder.Padding = new Thickness(
|
||||
Math.Clamp(Math.Min((_currentCellSize * metrics.HorizontalPaddingScale) * scale, hostWidth * 0.034), 4, 22),
|
||||
Math.Clamp(Math.Min((_currentCellSize * metrics.VerticalPaddingScale) * scale, hostHeight * 0.068), 3, 18));
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(Math.Min((_currentCellSize * metrics.HorizontalPaddingScale) * scale, hostWidth * 0.034), 4, 22, _chromeContext),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(Math.Min((_currentCellSize * metrics.VerticalPaddingScale) * scale, hostHeight * 0.068), 3, 18, _chromeContext));
|
||||
ApplyAdaptiveTypography();
|
||||
ResetParticles();
|
||||
}
|
||||
|
||||
@@ -63,15 +63,15 @@ public partial class RecordingWidget : UserControl, IDesktopComponentWidget, IDe
|
||||
var chromeScale = Math.Clamp(rawScale, 0.62, 2.0);
|
||||
var contentScale = Math.Clamp(rawScale, 0.74, 1.0);
|
||||
|
||||
var rootRadius = Math.Clamp(34 * chromeScale, 16, 56);
|
||||
RootBorder.CornerRadius = new CornerRadius(rootRadius);
|
||||
var rootRadius = ComponentChromeCornerRadiusHelper.Scale(34 * chromeScale, 16, 56);
|
||||
RootBorder.CornerRadius = rootRadius;
|
||||
RootBorder.Padding = new Thickness(0);
|
||||
RecorderCardBorder.CornerRadius = new CornerRadius(rootRadius);
|
||||
RecorderCardBorder.CornerRadius = rootRadius;
|
||||
RecorderContentGrid.Margin = new Thickness(
|
||||
Math.Clamp(24 * contentScale, 14, 26),
|
||||
Math.Clamp(18 * contentScale, 10, 22),
|
||||
Math.Clamp(24 * contentScale, 14, 26),
|
||||
Math.Clamp(18 * contentScale, 10, 24));
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(24 * contentScale, 14, 26),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(18 * contentScale, 10, 22),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(24 * contentScale, 14, 26),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(18 * contentScale, 10, 24));
|
||||
|
||||
var sideButtonSize = Math.Clamp(54 * contentScale, 34, 58);
|
||||
DiscardButtonBorder.Width = sideButtonSize;
|
||||
|
||||
@@ -347,13 +347,12 @@ public partial class RemovableStorageWidget : UserControl, IDesktopComponentWidg
|
||||
var scale = ResolveScale();
|
||||
var width = Bounds.Width > 1 ? Bounds.Width : _currentCellSize * 2;
|
||||
|
||||
var cornerRadius = Math.Clamp(_currentCellSize * 0.44, 18, 34);
|
||||
RootBorder.CornerRadius = new CornerRadius(cornerRadius);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.44, 18, 34);
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(16 * scale, 10, 24),
|
||||
Math.Clamp(15 * scale, 10, 22),
|
||||
Math.Clamp(16 * scale, 10, 24),
|
||||
Math.Clamp(15 * scale, 10, 22));
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(16 * scale, 10, 24),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(15 * scale, 10, 22),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(16 * scale, 10, 24),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(15 * scale, 10, 22));
|
||||
|
||||
LayoutGrid.RowSpacing = Math.Clamp(10 * scale, 8, 16);
|
||||
HeaderGrid.ColumnSpacing = Math.Clamp(12 * scale, 8, 16);
|
||||
|
||||
@@ -602,8 +602,8 @@ public partial class Stcn24ForumWidget : UserControl, IDesktopComponentWidget, I
|
||||
var totalWidth = Bounds.Width > 1 ? Bounds.Width : _currentCellSize * BaseWidthCells;
|
||||
var totalHeight = Bounds.Height > 1 ? Bounds.Height : _currentCellSize * BaseHeightCells;
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(30 * softScale, 14, 44));
|
||||
CardBorder.CornerRadius = new CornerRadius(Math.Clamp(30 * softScale, 14, 44));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(30 * softScale, 14, 44);
|
||||
CardBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(30 * softScale, 14, 44);
|
||||
CardBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * softScale, 8, 18),
|
||||
Math.Clamp(12 * softScale, 8, 18),
|
||||
@@ -628,7 +628,6 @@ public partial class Stcn24ForumWidget : UserControl, IDesktopComponentWidget, I
|
||||
var innerWidth = Math.Max(100, totalWidth - CardBorder.Padding.Left - CardBorder.Padding.Right);
|
||||
var rowPaddingHorizontal = Math.Clamp(8 * softScale, 5, 14);
|
||||
var rowPaddingVertical = Math.Clamp(6 * softScale, 3, 10);
|
||||
var itemCornerRadius = Math.Clamp(10 * softScale, 6, 14);
|
||||
var avatarSize = Math.Clamp(30 * softScale, 20, 40);
|
||||
var avatarFont = Math.Clamp(13 * softScale, 9, 18);
|
||||
var titleFont = Math.Clamp(14 * softScale, 10, 19);
|
||||
@@ -658,7 +657,7 @@ public partial class Stcn24ForumWidget : UserControl, IDesktopComponentWidget, I
|
||||
|
||||
foreach (var visual in _itemVisuals)
|
||||
{
|
||||
visual.Host.CornerRadius = new CornerRadius(itemCornerRadius);
|
||||
visual.Host.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(10 * softScale, 6, 14);
|
||||
visual.Host.Padding = new Thickness(rowPaddingHorizontal, rowPaddingVertical);
|
||||
visual.RowGrid.ColumnSpacing = Math.Clamp(8 * softScale, 4, 12);
|
||||
|
||||
|
||||
@@ -229,7 +229,7 @@ public partial class StudyDeductionReasonsWidget : UserControl, IDesktopComponen
|
||||
_isUltraCompactMode = scale < 0.72 || (Bounds.Width > 1 && Bounds.Width < 300) || (Bounds.Height > 1 && Bounds.Height < 145);
|
||||
|
||||
var compactMultiplier = _isUltraCompactMode ? 0.76 : _isCompactMode ? 0.88 : 1.0;
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.46, 12, 34));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.46, 12, 34);
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale * compactMultiplier, 6, 18),
|
||||
Math.Clamp(10 * scale * compactMultiplier, 5, 16));
|
||||
|
||||
@@ -52,7 +52,7 @@ public partial class StudyEnvironmentWidget : UserControl, IDesktopComponentWidg
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = Math.Clamp(_currentCellSize / 48d, 0.82, 2.2);
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.34, 10, 28));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.34, 10, 28);
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(14 * scale, 8, 20),
|
||||
Math.Clamp(10 * scale, 6, 16));
|
||||
|
||||
@@ -255,7 +255,7 @@ public partial class StudyInterruptDensityWidget : UserControl, IDesktopComponen
|
||||
_isUltraCompactMode = scale < 0.72 || (Bounds.Width > 1 && Bounds.Width < 295) || (Bounds.Height > 1 && Bounds.Height < 130);
|
||||
|
||||
var compactMultiplier = _isUltraCompactMode ? 0.76 : _isCompactMode ? 0.88 : 1.0;
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.46, 12, 34));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.46, 12, 34);
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale * compactMultiplier, 6, 18),
|
||||
Math.Clamp(9 * scale * compactMultiplier, 5, 16));
|
||||
|
||||
@@ -105,7 +105,7 @@ public partial class StudyNoiseCurveWidget : UserControl, IDesktopComponentWidge
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = Math.Clamp(_currentCellSize / 48d, 0.78, 2.4);
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.44, 14, 42));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.44, 14, 42);
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(14 * scale, 8, 22),
|
||||
Math.Clamp(10 * scale, 6, 16));
|
||||
|
||||
@@ -323,7 +323,7 @@ public partial class StudyNoiseDistributionWidget : UserControl, IDesktopCompone
|
||||
_isUltraCompactMode = scale < 0.74 || (Bounds.Width > 1 && Bounds.Width < 300) || (Bounds.Height > 1 && Bounds.Height < 142);
|
||||
|
||||
var compactMultiplier = _isUltraCompactMode ? 0.76 : _isCompactMode ? 0.88 : 1.0;
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.44, 12, 34));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.44, 12, 34);
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale * compactMultiplier, 6, 18),
|
||||
Math.Clamp(9 * scale * compactMultiplier, 5, 16));
|
||||
|
||||
@@ -258,7 +258,7 @@ public partial class StudyScoreOverviewWidget : UserControl, IDesktopComponentWi
|
||||
|
||||
var compactMultiplier = _isUltraCompactMode ? 0.76 : _isCompactMode ? 0.88 : 1.0;
|
||||
var expandedMultiplier = _isExpandedMode ? 1.12 : 1.0;
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.50, 14, 42));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.50, 14, 42);
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(16 * scale * compactMultiplier * expandedMultiplier, 8, 30),
|
||||
Math.Clamp(14 * scale * compactMultiplier * expandedMultiplier, 6, 26));
|
||||
@@ -305,7 +305,7 @@ public partial class StudyScoreOverviewWidget : UserControl, IDesktopComponentWi
|
||||
var cardPadding = new Thickness(
|
||||
Math.Clamp(10 * scale * compactMultiplier * expandedMultiplier, 6, 20),
|
||||
Math.Clamp(8 * scale * compactMultiplier * expandedMultiplier, 4, 16));
|
||||
var cardCornerRadius = new CornerRadius(Math.Clamp(10 * scale, 6, 18));
|
||||
var cardCornerRadius = ComponentChromeCornerRadiusHelper.Scale(10 * scale, 6, 18);
|
||||
AverageCardBorder.Padding = cardPadding;
|
||||
MinimumCardBorder.Padding = cardPadding;
|
||||
MaximumCardBorder.Padding = cardPadding;
|
||||
|
||||
@@ -268,7 +268,7 @@ public partial class StudySessionControlWidget : UserControl, IDesktopComponentW
|
||||
_isUltraCompactMode = scale < 0.74 || (Bounds.Width > 1 && Bounds.Width < 180) || (Bounds.Height > 1 && Bounds.Height < 76);
|
||||
|
||||
var compactMultiplier = _isUltraCompactMode ? 0.78 : _isCompactMode ? 0.90 : 1.0;
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.34, 10, 28));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.34, 10, 28);
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(14 * scale * compactMultiplier, 7, 22),
|
||||
Math.Clamp(10 * scale * compactMultiplier, 5, 16));
|
||||
|
||||
@@ -237,7 +237,7 @@ public partial class StudySessionHistoryWidget : UserControl, IDesktopComponentW
|
||||
|
||||
var rowBorder = new Border
|
||||
{
|
||||
CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.20, 8, 14)),
|
||||
CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.20, 8, 14),
|
||||
Background = new SolidColorBrush(rowBackground),
|
||||
BorderBrush = new SolidColorBrush(rowBorderColor),
|
||||
BorderThickness = new Thickness(1),
|
||||
@@ -588,7 +588,7 @@ public partial class StudySessionHistoryWidget : UserControl, IDesktopComponentW
|
||||
_isCompactMode = scale < 0.92 || (Bounds.Width > 1 && Bounds.Width < 320) || (Bounds.Height > 1 && Bounds.Height < 145);
|
||||
_isUltraCompactMode = scale < 0.78 || (Bounds.Width > 1 && Bounds.Width < 280) || (Bounds.Height > 1 && Bounds.Height < 120);
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.44, 12, 36));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.44, 12, 36);
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale, 7, 22),
|
||||
Math.Clamp(9 * scale, 5, 16));
|
||||
@@ -606,7 +606,7 @@ public partial class StudySessionHistoryWidget : UserControl, IDesktopComponentW
|
||||
DialogOverlayBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale, 8, 20),
|
||||
Math.Clamp(10 * scale, 8, 18));
|
||||
DialogCardBorder.CornerRadius = new CornerRadius(Math.Clamp(12 * scale, 10, 18));
|
||||
DialogCardBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(12 * scale, 10, 18);
|
||||
DialogCardBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale, 9, 20),
|
||||
Math.Clamp(11 * scale, 8, 18));
|
||||
|
||||
@@ -197,9 +197,9 @@ public partial class TimerWidget : UserControl, IDesktopComponentWidget
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = ResolveScale();
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(34 * scale, 12, 48));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 12, 48);
|
||||
RootBorder.Padding = new Thickness(Math.Clamp(14 * scale, 7, 22));
|
||||
TimerPanelBorder.CornerRadius = new CornerRadius(Math.Clamp(32 * scale, 12, 42));
|
||||
TimerPanelBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(32 * scale, 12, 42);
|
||||
|
||||
PlayButtonBorder.Width = Math.Clamp(42 * scale, 28, 58);
|
||||
PlayButtonBorder.Height = Math.Clamp(42 * scale, 28, 58);
|
||||
|
||||
@@ -11,12 +11,13 @@ using Avalonia.Media;
|
||||
using Avalonia.Styling;
|
||||
using Avalonia.Threading;
|
||||
using LanMountainDesktop.ComponentSystem;
|
||||
using LanMountainDesktop.Host.Abstractions;
|
||||
using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.Services;
|
||||
|
||||
namespace LanMountainDesktop.Views.Components;
|
||||
|
||||
public partial class WeatherClockWidget : UserControl, IDesktopComponentWidget, ITimeZoneAwareComponentWidget, IWeatherInfoAwareComponentWidget, IComponentPlacementContextAware
|
||||
public partial class WeatherClockWidget : UserControl, IDesktopComponentWidget, ITimeZoneAwareComponentWidget, IWeatherInfoAwareComponentWidget, IComponentPlacementContextAware, IComponentChromeContextAware
|
||||
{
|
||||
private sealed record WeatherClockConfig(
|
||||
string LanguageCode,
|
||||
@@ -52,6 +53,7 @@ public partial class WeatherClockWidget : UserControl, IDesktopComponentWidget,
|
||||
private TimeZoneService? _timeZoneService;
|
||||
private CancellationTokenSource? _refreshCts;
|
||||
private double _currentCellSize = 48;
|
||||
private ComponentChromeContext? _chromeContext;
|
||||
private bool _isAttached;
|
||||
private bool _dialInitialized;
|
||||
private bool _handsInitialized;
|
||||
@@ -128,6 +130,13 @@ public partial class WeatherClockWidget : UserControl, IDesktopComponentWidget,
|
||||
RefreshFromSettings();
|
||||
}
|
||||
|
||||
public void SetComponentChromeContext(ComponentChromeContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
_chromeContext = context;
|
||||
ApplyCellSize(_currentCellSize);
|
||||
}
|
||||
|
||||
public void ApplyCellSize(double cellSize)
|
||||
{
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
@@ -142,12 +151,24 @@ public partial class WeatherClockWidget : UserControl, IDesktopComponentWidget,
|
||||
var compactness = Math.Clamp((176 - targetWidth) / 86d, 0, 1);
|
||||
var ultraCompact = targetWidth < 126 || targetHeight < 46;
|
||||
var compactFactor = Lerp(1, ultraCompact ? 0.64 : 0.72, compactness);
|
||||
var cornerRadius = Math.Clamp(targetHeight * metrics.CornerRadiusScale, 15, 36);
|
||||
var cornerRadius = ComponentChromeCornerRadiusHelper.Scale(
|
||||
targetHeight * metrics.CornerRadiusScale,
|
||||
15,
|
||||
36,
|
||||
_chromeContext);
|
||||
|
||||
var horizontalPadding = Math.Clamp(targetHeight * Lerp(0.18, 0.12, compactness), 5, 30);
|
||||
var verticalPadding = Math.Clamp(targetHeight * Lerp(0.14, 0.10, compactness), 3, 20);
|
||||
var horizontalPadding = ComponentChromeCornerRadiusHelper.SafeValue(
|
||||
targetHeight * Lerp(0.18, 0.12, compactness),
|
||||
5,
|
||||
30,
|
||||
_chromeContext);
|
||||
var verticalPadding = ComponentChromeCornerRadiusHelper.SafeValue(
|
||||
targetHeight * Lerp(0.14, 0.10, compactness),
|
||||
3,
|
||||
20,
|
||||
_chromeContext);
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(cornerRadius);
|
||||
RootBorder.CornerRadius = cornerRadius;
|
||||
RootBorder.Padding = new Thickness(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
|
||||
|
||||
var columnSpacing = Math.Clamp(targetHeight * Lerp(0.16, 0.08, compactness), 2, 22);
|
||||
|
||||
@@ -12,13 +12,14 @@ using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Threading;
|
||||
using LanMountainDesktop.ComponentSystem;
|
||||
using LanMountainDesktop.Host.Abstractions;
|
||||
using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Theme;
|
||||
|
||||
namespace LanMountainDesktop.Views.Components;
|
||||
|
||||
public partial class WeatherWidget : UserControl, IDesktopComponentWidget, IDesktopPageVisibilityAwareComponentWidget, ITimeZoneAwareComponentWidget, IWeatherInfoAwareComponentWidget, IComponentPlacementContextAware
|
||||
public partial class WeatherWidget : UserControl, IDesktopComponentWidget, IDesktopPageVisibilityAwareComponentWidget, ITimeZoneAwareComponentWidget, IWeatherInfoAwareComponentWidget, IComponentPlacementContextAware, IComponentChromeContextAware
|
||||
{
|
||||
private enum WeatherVisualKind
|
||||
{
|
||||
@@ -111,6 +112,7 @@ public partial class WeatherWidget : UserControl, IDesktopComponentWidget, IDesk
|
||||
private WeatherSnapshot? _latestSnapshot;
|
||||
private string _languageCode = "zh-CN";
|
||||
private double _currentCellSize = 48;
|
||||
private ComponentChromeContext? _chromeContext;
|
||||
private WeatherVisualKind _activeVisualKind = WeatherVisualKind.ClearDay;
|
||||
private double _animationPhase;
|
||||
private int _activeParticleCount;
|
||||
@@ -197,6 +199,13 @@ public partial class WeatherWidget : UserControl, IDesktopComponentWidget, IDesk
|
||||
}
|
||||
}
|
||||
|
||||
public void SetComponentChromeContext(ComponentChromeContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
_chromeContext = context;
|
||||
ApplyCellSize(_currentCellSize);
|
||||
}
|
||||
|
||||
public void ApplyCellSize(double cellSize)
|
||||
{
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
@@ -204,19 +213,25 @@ public partial class WeatherWidget : UserControl, IDesktopComponentWidget, IDesk
|
||||
var metrics = HyperOS3WeatherTheme.ResolveMetrics(HyperOS3WeatherWidgetKind.Realtime2x2);
|
||||
var hostWidth = Bounds.Width > 1 ? Bounds.Width : Math.Max(80, _currentCellSize * 2);
|
||||
var hostHeight = Bounds.Height > 1 ? Bounds.Height : Math.Max(80, _currentCellSize * 2);
|
||||
var cornerRadius = Math.Clamp(_currentCellSize * metrics.CornerRadiusScale, 26, 46);
|
||||
var cornerRadius = ComponentChromeCornerRadiusHelper.Scale(
|
||||
_currentCellSize * metrics.CornerRadiusScale,
|
||||
26,
|
||||
46,
|
||||
_chromeContext);
|
||||
var horizontalPadding = Math.Clamp(_currentCellSize * metrics.HorizontalPaddingScale, 10, 24);
|
||||
var verticalPadding = Math.Clamp(_currentCellSize * metrics.VerticalPaddingScale, 10, 24);
|
||||
|
||||
RootBorder.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundImageLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundMotionLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundTintLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundLightLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
BackgroundShadeLayer.CornerRadius = new CornerRadius(cornerRadius);
|
||||
ComponentChromeCornerRadiusHelper.Apply(
|
||||
cornerRadius,
|
||||
RootBorder,
|
||||
BackgroundImageLayer,
|
||||
BackgroundMotionLayer,
|
||||
BackgroundTintLayer,
|
||||
BackgroundLightLayer,
|
||||
BackgroundShadeLayer);
|
||||
ContentPaddingBorder.Padding = new Thickness(
|
||||
Math.Clamp(Math.Min(horizontalPadding * scale, hostWidth * 0.12), 3, 24),
|
||||
Math.Clamp(Math.Min(verticalPadding * scale, hostHeight * 0.12), 3, 24));
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(Math.Min(horizontalPadding * scale, hostWidth * 0.12), 3, 24, _chromeContext),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(Math.Min(verticalPadding * scale, hostHeight * 0.12), 3, 24, _chromeContext));
|
||||
ApplyAdaptiveTypography();
|
||||
ResetParticles();
|
||||
}
|
||||
|
||||
@@ -117,11 +117,13 @@ public partial class WhiteboardWidget : UserControl, IDesktopComponentWidget, IC
|
||||
var toolbarPaddingHorizontal = Math.Clamp(buttonSize * 0.36, 6, 12);
|
||||
var toolbarPaddingVertical = Math.Clamp(buttonSize * 0.24, 4, 8);
|
||||
|
||||
RootBorder.Padding = new Thickness(Math.Clamp(_currentCellSize * 0.14, 6, 14));
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.34, 12, 28));
|
||||
CanvasBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.24, 10, 22));
|
||||
ToolbarBorder.CornerRadius = new CornerRadius(Math.Clamp(_currentCellSize * 0.22, 10, 20));
|
||||
ToolbarBorder.Padding = new Thickness(toolbarPaddingHorizontal, toolbarPaddingVertical);
|
||||
RootBorder.Padding = new Thickness(ComponentChromeCornerRadiusHelper.SafeValue(_currentCellSize * 0.14, 6, 14));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.34, 12, 28);
|
||||
CanvasBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.24, 10, 22);
|
||||
ToolbarBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.22, 10, 20);
|
||||
ToolbarBorder.Padding = new Thickness(
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(toolbarPaddingHorizontal, 6, 12),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(toolbarPaddingVertical, 4, 8));
|
||||
ToolbarButtonsPanel.Spacing = toolbarSpacing;
|
||||
|
||||
foreach (var button in new[] { PenButton, EraserButton, ClearButton, ExportButton })
|
||||
|
||||
@@ -170,7 +170,7 @@ public partial class WorldClockWidget : UserControl, IDesktopComponentWidget, IT
|
||||
var horizontalPadding = Math.Clamp(10 * scale, 4, 26);
|
||||
var verticalPadding = Math.Clamp(8 * scale, 3, 22);
|
||||
RootBorder.Padding = new Thickness(horizontalPadding, verticalPadding);
|
||||
RootBorder.CornerRadius = new CornerRadius(Math.Clamp(24 * scale, 10, 46));
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(24 * scale, 10, 46);
|
||||
|
||||
var usableWidth = Math.Max(48, totalWidth - horizontalPadding * 2);
|
||||
var usableHeight = Math.Max(28, totalHeight - verticalPadding * 2);
|
||||
|
||||
@@ -13,11 +13,13 @@ using Avalonia.VisualTree;
|
||||
using FluentIcons.Avalonia;
|
||||
using FluentIcons.Common;
|
||||
using LanMountainDesktop.ComponentSystem;
|
||||
using LanMountainDesktop.Host.Abstractions;
|
||||
using LanMountainDesktop.Models;
|
||||
using LanMountainDesktop.Services;
|
||||
using LanMountainDesktop.Services.Settings;
|
||||
using LanMountainDesktop.Theme;
|
||||
using LanMountainDesktop.Views.Components;
|
||||
using PathShape = Avalonia.Controls.Shapes.Path;
|
||||
|
||||
namespace LanMountainDesktop.Views;
|
||||
|
||||
@@ -579,13 +581,18 @@ public partial class MainWindow
|
||||
{
|
||||
var window = new ComponentLibraryWindow(
|
||||
_componentLibraryService,
|
||||
cellSize => new ComponentLibraryCreateContext(
|
||||
cellSize,
|
||||
_timeZoneService,
|
||||
_weatherDataService,
|
||||
_recommendationInfoService,
|
||||
_calculatorDataService,
|
||||
_settingsFacade),
|
||||
cellSize =>
|
||||
{
|
||||
var appearanceSnapshot = HostAppearanceThemeProvider.GetOrCreate().GetCurrent();
|
||||
return new ComponentLibraryCreateContext(
|
||||
cellSize,
|
||||
appearanceSnapshot.GlobalCornerRadiusScale,
|
||||
_timeZoneService,
|
||||
_weatherDataService,
|
||||
_recommendationInfoService,
|
||||
_calculatorDataService,
|
||||
_settingsFacade);
|
||||
},
|
||||
L);
|
||||
window.AddComponentRequested += OnDetachedComponentLibraryAddComponentRequested;
|
||||
window.Closed += OnDetachedComponentLibraryClosed;
|
||||
@@ -1258,7 +1265,7 @@ public partial class MainWindow
|
||||
Height = handleVisualSize,
|
||||
IsHitTestVisible = false
|
||||
};
|
||||
resizeHandleVisual.Children.Add(new Path
|
||||
resizeHandleVisual.Children.Add(new PathShape
|
||||
{
|
||||
Data = arcData,
|
||||
Stretch = Stretch.Fill,
|
||||
@@ -1266,7 +1273,7 @@ public partial class MainWindow
|
||||
StrokeThickness = arcThickness + 3,
|
||||
StrokeLineCap = PenLineCap.Round
|
||||
});
|
||||
resizeHandleVisual.Children.Add(new Path
|
||||
resizeHandleVisual.Children.Add(new PathShape
|
||||
{
|
||||
Data = arcData,
|
||||
Stretch = Stretch.Fill,
|
||||
@@ -1513,12 +1520,20 @@ public partial class MainWindow
|
||||
|
||||
private double GetComponentCornerRadius(string componentId)
|
||||
{
|
||||
var appearanceSnapshot = HostAppearanceThemeProvider.GetOrCreate().GetCurrent();
|
||||
|
||||
if (_componentRuntimeRegistry.TryGetDescriptor(componentId, out var runtimeDescriptor))
|
||||
{
|
||||
return runtimeDescriptor.ResolveCornerRadius(_currentDesktopCellSize);
|
||||
return runtimeDescriptor.ResolveCornerRadius(new ComponentChromeContext(
|
||||
componentId,
|
||||
null,
|
||||
_currentDesktopCellSize,
|
||||
appearanceSnapshot.GlobalCornerRadiusScale,
|
||||
appearanceSnapshot.CornerRadiusTokens));
|
||||
}
|
||||
|
||||
return Math.Clamp(_currentDesktopCellSize * 0.22, 8, 18);
|
||||
var scale = Math.Max(0.1d, appearanceSnapshot.GlobalCornerRadiusScale);
|
||||
return Math.Clamp(_currentDesktopCellSize * 0.22, 8, 18) * scale;
|
||||
}
|
||||
|
||||
private Thickness GetDesktopComponentVisualInset(int widthCells, int heightCells)
|
||||
@@ -1767,8 +1782,10 @@ public partial class MainWindow
|
||||
{
|
||||
try
|
||||
{
|
||||
var appearanceSnapshot = HostAppearanceThemeProvider.GetOrCreate().GetCurrent();
|
||||
var createContext = new ComponentLibraryCreateContext(
|
||||
cellSize,
|
||||
appearanceSnapshot.GlobalCornerRadiusScale,
|
||||
_timeZoneService,
|
||||
_weatherDataService,
|
||||
_recommendationInfoService,
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
Background="{Binding NeutralLightPreviewBrush}"
|
||||
BorderBrush="{DynamicResource AdaptiveGlassPanelBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14" />
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusSm}" />
|
||||
<TextBlock Text="{Binding PreviewNeutralLightLabel}"
|
||||
HorizontalAlignment="Center"
|
||||
TextAlignment="Center" />
|
||||
@@ -94,7 +94,7 @@
|
||||
Background="{Binding NeutralDarkPreviewBrush}"
|
||||
BorderBrush="{DynamicResource AdaptiveGlassPanelBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14" />
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusSm}" />
|
||||
<TextBlock Text="{Binding PreviewNeutralDarkLabel}"
|
||||
HorizontalAlignment="Center"
|
||||
TextAlignment="Center" />
|
||||
@@ -110,7 +110,7 @@
|
||||
Background="{Binding PrimarySwatchBrush}"
|
||||
BorderBrush="{DynamicResource AdaptiveGlassPanelBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14" />
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusSm}" />
|
||||
<TextBlock Text="{Binding PreviewPrimaryLabel}"
|
||||
HorizontalAlignment="Center"
|
||||
TextAlignment="Center" />
|
||||
@@ -122,7 +122,7 @@
|
||||
Background="{Binding SecondarySwatchBrush}"
|
||||
BorderBrush="{DynamicResource AdaptiveGlassPanelBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14" />
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusSm}" />
|
||||
<TextBlock Text="{Binding PreviewSecondaryLabel}"
|
||||
HorizontalAlignment="Center"
|
||||
TextAlignment="Center" />
|
||||
@@ -134,7 +134,7 @@
|
||||
Background="{Binding TertiarySwatchBrush}"
|
||||
BorderBrush="{DynamicResource AdaptiveGlassPanelBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14" />
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusSm}" />
|
||||
<TextBlock Text="{Binding PreviewTertiaryLabel}"
|
||||
HorizontalAlignment="Center"
|
||||
TextAlignment="Center" />
|
||||
@@ -146,7 +146,7 @@
|
||||
Background="{Binding NeutralSwatchBrush}"
|
||||
BorderBrush="{DynamicResource AdaptiveGlassPanelBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14" />
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusSm}" />
|
||||
<TextBlock Text="{Binding PreviewNeutralLabel}"
|
||||
HorizontalAlignment="Center"
|
||||
TextAlignment="Center" />
|
||||
@@ -177,7 +177,7 @@
|
||||
Background="{Binding SeedSwatchBrush}"
|
||||
BorderBrush="{DynamicResource AdaptiveGlassPanelBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14" />
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusSm}" />
|
||||
<TextBlock Text="{Binding PreviewSeedLabel}"
|
||||
HorizontalAlignment="Center"
|
||||
TextAlignment="Center" />
|
||||
@@ -217,7 +217,7 @@
|
||||
Background="{Binding Brush}"
|
||||
BorderBrush="{DynamicResource AdaptiveGlassPanelBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="12" />
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusXs}" />
|
||||
<TextBlock Text="{Binding Label}"
|
||||
HorizontalAlignment="Center"
|
||||
TextAlignment="Center"
|
||||
@@ -240,7 +240,7 @@
|
||||
Background="{Binding SeedSwatchBrush}"
|
||||
BorderBrush="{DynamicResource AdaptiveGlassPanelBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="14" />
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusSm}" />
|
||||
<TextBlock Text="{Binding PreviewSeedLabel}"
|
||||
HorizontalAlignment="Center"
|
||||
TextAlignment="Center" />
|
||||
|
||||
@@ -8,16 +8,14 @@
|
||||
x:DataType="vm:ComponentsSettingsPageViewModel">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Classes="settings-page-container">
|
||||
|
||||
<!-- 网格布局设置分组 -->
|
||||
<controls:IconText Icon="GridDots"
|
||||
Text="{Binding GridHeader}"
|
||||
<controls:IconText Icon="Apps"
|
||||
Text="{Binding ComponentsHeader}"
|
||||
Margin="0,0,0,4" />
|
||||
|
||||
<ui:SettingsExpander Header="{Binding GridHeader}"
|
||||
<ui:SettingsExpander Header="{Binding ComponentsHeader}"
|
||||
IsExpanded="True">
|
||||
<ui:SettingsExpander.IconSource>
|
||||
<fi:SymbolIconSource Symbol="GridDots" />
|
||||
<fi:SymbolIconSource Symbol="Apps" />
|
||||
</ui:SettingsExpander.IconSource>
|
||||
<ui:SettingsExpanderItem>
|
||||
<Grid ColumnDefinitions="Auto,*,Auto" ColumnSpacing="16">
|
||||
@@ -71,6 +69,33 @@
|
||||
</ui:SettingsExpanderItem>
|
||||
</ui:SettingsExpander>
|
||||
|
||||
<controls:IconText Icon="ShapeOrganic"
|
||||
Text="{Binding ComponentRadiusHeader}"
|
||||
Margin="0,12,0,4" />
|
||||
|
||||
<ui:SettingsExpander Header="{Binding GlobalCornerRadiusLabel}"
|
||||
Description="{Binding GlobalCornerRadiusDescription}">
|
||||
<ui:SettingsExpander.IconSource>
|
||||
<fi:SymbolIconSource Symbol="ShapeOrganic" />
|
||||
</ui:SettingsExpander.IconSource>
|
||||
<ui:SettingsExpanderItem>
|
||||
<Grid ColumnDefinitions="Auto,*,Auto" ColumnSpacing="16">
|
||||
<TextBlock Text="{Binding GlobalCornerRadiusLabel}"
|
||||
VerticalAlignment="Center" />
|
||||
<Slider Grid.Column="1"
|
||||
Minimum="0.7"
|
||||
Maximum="1.4"
|
||||
IsSnapToTickEnabled="True"
|
||||
TickFrequency="0.05"
|
||||
Value="{Binding GlobalCornerRadiusScale}" />
|
||||
<TextBlock Grid.Column="2"
|
||||
Width="48"
|
||||
Text="{Binding GlobalCornerRadiusScale, StringFormat={}{0:F2}x}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right" />
|
||||
</Grid>
|
||||
</ui:SettingsExpanderItem>
|
||||
</ui:SettingsExpander>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace LanMountainDesktop.Views.SettingsPages;
|
||||
"components",
|
||||
"Components",
|
||||
SettingsPageCategory.Components,
|
||||
IconKey = "GridDots",
|
||||
IconKey = "Apps",
|
||||
SortOrder = 20,
|
||||
TitleLocalizationKey = "settings.components.title",
|
||||
DescriptionLocalizationKey = "settings.components.description")]
|
||||
|
||||
@@ -515,7 +515,7 @@ internal sealed class PluginMarketEmbeddedView : UserControl, IDisposable
|
||||
Background = isSelected ? SelectedSurfaceBrush : SurfaceBrush,
|
||||
BorderBrush = isSelected ? SelectedBorderBrush : CardBorderBrush,
|
||||
BorderThickness = new Thickness(1),
|
||||
CornerRadius = new CornerRadius(18),
|
||||
CornerRadius = ResolveCornerRadiusResource("DesignCornerRadiusMd", 18),
|
||||
Padding = new Thickness(14),
|
||||
Child = layoutGrid
|
||||
};
|
||||
@@ -597,7 +597,7 @@ internal sealed class PluginMarketEmbeddedView : UserControl, IDisposable
|
||||
detailPanel.Children.Add(new Border
|
||||
{
|
||||
Background = new SolidColorBrush(Color.Parse("#24FFC42B1C")),
|
||||
CornerRadius = new CornerRadius(14),
|
||||
CornerRadius = ResolveCornerRadiusResource("DesignCornerRadiusSm", 14),
|
||||
Padding = new Thickness(12),
|
||||
Child = new TextBlock
|
||||
{
|
||||
@@ -617,7 +617,7 @@ internal sealed class PluginMarketEmbeddedView : UserControl, IDisposable
|
||||
Background = SurfaceBrush,
|
||||
BorderBrush = CardBorderBrush,
|
||||
BorderThickness = new Thickness(1),
|
||||
CornerRadius = new CornerRadius(16),
|
||||
CornerRadius = ResolveCornerRadiusResource("DesignCornerRadiusMd", 16),
|
||||
Padding = new Thickness(16),
|
||||
Child = new TextBlock
|
||||
{
|
||||
@@ -1011,7 +1011,7 @@ internal sealed class PluginMarketEmbeddedView : UserControl, IDisposable
|
||||
return new Border
|
||||
{
|
||||
Background = SurfaceBrush,
|
||||
CornerRadius = new CornerRadius(18),
|
||||
CornerRadius = ResolveCornerRadiusResource("DesignCornerRadiusMd", 18),
|
||||
Padding = new Thickness(padding)
|
||||
};
|
||||
}
|
||||
@@ -1021,7 +1021,7 @@ internal sealed class PluginMarketEmbeddedView : UserControl, IDisposable
|
||||
return new Border
|
||||
{
|
||||
Background = SurfaceBrush,
|
||||
CornerRadius = new CornerRadius(16),
|
||||
CornerRadius = ResolveCornerRadiusResource("DesignCornerRadiusMd", 16),
|
||||
BorderBrush = CardBorderBrush,
|
||||
BorderThickness = new Thickness(1),
|
||||
Padding = new Thickness(18),
|
||||
@@ -1124,7 +1124,7 @@ internal sealed class PluginMarketEmbeddedView : UserControl, IDisposable
|
||||
Background = SurfaceBrush,
|
||||
BorderBrush = CardBorderBrush,
|
||||
BorderThickness = new Thickness(1),
|
||||
CornerRadius = new CornerRadius(14),
|
||||
CornerRadius = ResolveCornerRadiusResource("DesignCornerRadiusSm", 14),
|
||||
Padding = new Thickness(14),
|
||||
Child = new StackPanel
|
||||
{
|
||||
@@ -1154,7 +1154,7 @@ internal sealed class PluginMarketEmbeddedView : UserControl, IDisposable
|
||||
Background = SurfaceBrush,
|
||||
BorderBrush = CardBorderBrush,
|
||||
BorderThickness = new Thickness(1),
|
||||
CornerRadius = new CornerRadius(14),
|
||||
CornerRadius = ResolveCornerRadiusResource("DesignCornerRadiusSm", 14),
|
||||
Padding = new Thickness(14),
|
||||
Child = new StackPanel
|
||||
{
|
||||
@@ -1257,4 +1257,11 @@ internal sealed class PluginMarketEmbeddedView : UserControl, IDisposable
|
||||
_ => "Install"
|
||||
};
|
||||
}
|
||||
|
||||
private static CornerRadius ResolveCornerRadiusResource(string key, double fallback)
|
||||
{
|
||||
return Application.Current?.TryFindResource(key, out var resource) == true && resource is CornerRadius radius
|
||||
? radius
|
||||
: new CornerRadius(fallback);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user