mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 15:44:25 +08:00
change.插件sdk更新
This commit is contained in:
109
LanMountainDesktop.PluginSdk/AppearanceChangedEvent.cs
Normal file
109
LanMountainDesktop.PluginSdk/AppearanceChangedEvent.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
namespace LanMountainDesktop.PluginSdk;
|
||||
|
||||
/// <summary>
|
||||
/// 外观变更事件参数,当主题、圆角或其他外观属性变化时触发。
|
||||
/// </summary>
|
||||
public sealed class AppearanceChangedEvent : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建外观变更事件实例。
|
||||
/// </summary>
|
||||
/// <param name="snapshot">当前外观快照</param>
|
||||
/// <param name="changedProperties">变更的属性集合</param>
|
||||
public AppearanceChangedEvent(
|
||||
PluginAppearanceSnapshot snapshot,
|
||||
IReadOnlyCollection<AppearanceProperty> changedProperties)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(snapshot);
|
||||
ArgumentNullException.ThrowIfNull(changedProperties);
|
||||
|
||||
Snapshot = snapshot;
|
||||
ChangedProperties = changedProperties;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前外观快照。
|
||||
/// </summary>
|
||||
public PluginAppearanceSnapshot Snapshot { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 变更的属性集合。
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<AppearanceProperty> ChangedProperties { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 圆角是否发生变化。
|
||||
/// </summary>
|
||||
public bool CornerRadiusChanged => ChangedProperties.Contains(AppearanceProperty.CornerRadius);
|
||||
|
||||
/// <summary>
|
||||
/// 主题变体(亮色/暗色)是否发生变化。
|
||||
/// </summary>
|
||||
public bool ThemeVariantChanged => ChangedProperties.Contains(AppearanceProperty.ThemeVariant);
|
||||
|
||||
/// <summary>
|
||||
/// 强调色是否发生变化。
|
||||
/// </summary>
|
||||
public bool AccentColorChanged => ChangedProperties.Contains(AppearanceProperty.AccentColor);
|
||||
|
||||
/// <summary>
|
||||
/// 圆角风格是否发生变化。
|
||||
/// </summary>
|
||||
public bool CornerRadiusStyleChanged => ChangedProperties.Contains(AppearanceProperty.CornerRadiusStyle);
|
||||
|
||||
/// <summary>
|
||||
/// 检查指定属性是否发生变化。
|
||||
/// </summary>
|
||||
/// <param name="property">要检查的属性</param>
|
||||
/// <returns>如果属性发生变化则返回 true</returns>
|
||||
public bool HasChanged(AppearanceProperty property)
|
||||
{
|
||||
return ChangedProperties.Contains(property);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否有任何外观属性发生变化。
|
||||
/// </summary>
|
||||
public bool HasAnyChanges => ChangedProperties.Count > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 可变更的外观属性枚举。
|
||||
/// </summary>
|
||||
public enum AppearanceProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// 圆角Token值发生变化。
|
||||
/// </summary>
|
||||
CornerRadius,
|
||||
|
||||
/// <summary>
|
||||
/// 主题变体(亮色/暗色)发生变化。
|
||||
/// </summary>
|
||||
ThemeVariant,
|
||||
|
||||
/// <summary>
|
||||
/// 强调色发生变化。
|
||||
/// </summary>
|
||||
AccentColor,
|
||||
|
||||
/// <summary>
|
||||
/// 圆角风格(Sharp/Balanced/Rounded/Open)发生变化。
|
||||
/// </summary>
|
||||
CornerRadiusStyle,
|
||||
|
||||
/// <summary>
|
||||
/// 壁纸发生变化。
|
||||
/// </summary>
|
||||
Wallpaper,
|
||||
|
||||
/// <summary>
|
||||
/// 系统材质模式发生变化。
|
||||
/// </summary>
|
||||
SystemMaterialMode,
|
||||
|
||||
/// <summary>
|
||||
/// 所有外观属性(用于批量更新)。
|
||||
/// </summary>
|
||||
All
|
||||
}
|
||||
@@ -1,10 +1,35 @@
|
||||
namespace LanMountainDesktop.PluginSdk;
|
||||
|
||||
/// <summary>
|
||||
/// 插件外观上下文接口,提供主题、圆角等外观资源的访问和变更通知。
|
||||
/// </summary>
|
||||
public interface IPluginAppearanceContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前外观快照。
|
||||
/// </summary>
|
||||
PluginAppearanceSnapshot Snapshot { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 外观变更事件。当主题、圆角或其他外观属性发生变化时触发。
|
||||
/// </summary>
|
||||
event EventHandler<AppearanceChangedEvent>? Changed;
|
||||
|
||||
/// <summary>
|
||||
/// 解析带缩放的圆角半径。
|
||||
/// </summary>
|
||||
/// <param name="baseRadius">基础圆角半径</param>
|
||||
/// <param name="minimum">最小值(可选)</param>
|
||||
/// <param name="maximum">最大值(可选)</param>
|
||||
/// <returns>解析后的圆角半径</returns>
|
||||
double ResolveScaledCornerRadius(double baseRadius, double? minimum = null, double? maximum = null);
|
||||
|
||||
/// <summary>
|
||||
/// 根据预设解析圆角半径。
|
||||
/// </summary>
|
||||
/// <param name="preset">圆角预设</param>
|
||||
/// <param name="minimum">最小值(可选)</param>
|
||||
/// <param name="maximum">最大值(可选)</param>
|
||||
/// <returns>解析后的圆角半径</returns>
|
||||
double ResolveCornerRadius(PluginCornerRadiusPreset preset, double? minimum = null, double? maximum = null);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
namespace LanMountainDesktop.PluginSdk;
|
||||
|
||||
/// <summary>
|
||||
/// 插件外观上下文实现,提供主题、圆角等外观资源的访问和变更通知。
|
||||
/// </summary>
|
||||
public sealed class PluginAppearanceContext : IPluginAppearanceContext
|
||||
{
|
||||
private PluginAppearanceSnapshot _snapshot;
|
||||
|
||||
/// <summary>
|
||||
/// 创建插件外观上下文实例。
|
||||
/// </summary>
|
||||
/// <param name="snapshot">初始外观快照</param>
|
||||
public PluginAppearanceContext(PluginAppearanceSnapshot snapshot)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(snapshot);
|
||||
ArgumentNullException.ThrowIfNull(snapshot.CornerRadiusTokens);
|
||||
|
||||
Snapshot = snapshot with
|
||||
_snapshot = snapshot with
|
||||
{
|
||||
ThemeVariant = string.IsNullOrWhiteSpace(snapshot.ThemeVariant)
|
||||
? "Unknown"
|
||||
@@ -15,8 +24,37 @@ public sealed class PluginAppearanceContext : IPluginAppearanceContext
|
||||
};
|
||||
}
|
||||
|
||||
public PluginAppearanceSnapshot Snapshot { get; }
|
||||
/// <inheritdoc />
|
||||
public PluginAppearanceSnapshot Snapshot => _snapshot;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<AppearanceChangedEvent>? Changed;
|
||||
|
||||
/// <summary>
|
||||
/// 更新外观快照并触发变更事件。
|
||||
/// 此方法由宿主调用,用于在主题、圆角等外观属性变化时通知插件。
|
||||
/// </summary>
|
||||
/// <param name="newSnapshot">新的外观快照</param>
|
||||
/// <param name="changedProperties">变更的属性集合</param>
|
||||
public void UpdateSnapshot(PluginAppearanceSnapshot newSnapshot, IReadOnlyCollection<AppearanceProperty> changedProperties)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(newSnapshot);
|
||||
ArgumentNullException.ThrowIfNull(changedProperties);
|
||||
|
||||
_snapshot = newSnapshot with
|
||||
{
|
||||
ThemeVariant = string.IsNullOrWhiteSpace(newSnapshot.ThemeVariant)
|
||||
? "Unknown"
|
||||
: newSnapshot.ThemeVariant.Trim()
|
||||
};
|
||||
|
||||
if (changedProperties.Count > 0)
|
||||
{
|
||||
Changed?.Invoke(this, new AppearanceChangedEvent(_snapshot, changedProperties));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public double ResolveScaledCornerRadius(double baseRadius, double? minimum = null, double? maximum = null)
|
||||
{
|
||||
var value = Math.Max(0d, baseRadius);
|
||||
@@ -30,16 +68,17 @@ public sealed class PluginAppearanceContext : IPluginAppearanceContext
|
||||
return Math.Clamp(value, clampedMin, clampedMax);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public double ResolveCornerRadius(PluginCornerRadiusPreset preset, double? minimum = null, double? maximum = null)
|
||||
{
|
||||
var resolved = Math.Max(0d, Snapshot.CornerRadiusTokens.Get(preset));
|
||||
var resolved = Math.Max(0d, _snapshot.CornerRadiusTokens.Get(preset));
|
||||
if (!minimum.HasValue && !maximum.HasValue)
|
||||
{
|
||||
return resolved;
|
||||
}
|
||||
|
||||
var clampedMin = minimum ?? resolved;
|
||||
var clampedMax = maximum ?? resolved;
|
||||
var clampedMin = minimum ?? 0d;
|
||||
var clampedMax = maximum ?? double.MaxValue;
|
||||
if (clampedMin > clampedMax)
|
||||
{
|
||||
(clampedMin, clampedMax) = (clampedMax, clampedMin);
|
||||
|
||||
137
LanMountainDesktop.PluginSdk/PluginAppearanceHelper.cs
Normal file
137
LanMountainDesktop.PluginSdk/PluginAppearanceHelper.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using Avalonia;
|
||||
|
||||
namespace LanMountainDesktop.PluginSdk;
|
||||
|
||||
/// <summary>
|
||||
/// 插件外观辅助方法,提供统一的圆角和主题资源访问。
|
||||
/// </summary>
|
||||
public static class PluginAppearanceHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取桌面组件主外壳圆角半径。
|
||||
/// 这是组件最外层边框应该使用的圆角值,对应 DesignCornerRadiusComponent 资源。
|
||||
/// </summary>
|
||||
/// <param name="context">外观上下文</param>
|
||||
/// <returns>主外壳圆角半径(像素)</returns>
|
||||
public static double GetShellCornerRadius(this IPluginAppearanceContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
return context.ResolveCornerRadius(PluginCornerRadiusPreset.Component);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取内部卡片圆角半径。
|
||||
/// 用于组件内部的次级卡片、内容区块等。
|
||||
/// </summary>
|
||||
/// <param name="context">外观上下文</param>
|
||||
/// <returns>内部卡片圆角半径(像素)</returns>
|
||||
public static double GetCardCornerRadius(this IPluginAppearanceContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
return context.ResolveCornerRadius(PluginCornerRadiusPreset.Sm);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取控件圆角半径。
|
||||
/// 用于按钮、输入框、标签等交互控件。
|
||||
/// </summary>
|
||||
/// <param name="context">外观上下文</param>
|
||||
/// <returns>控件圆角半径(像素)</returns>
|
||||
public static double GetControlCornerRadius(this IPluginAppearanceContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
return context.ResolveCornerRadius(PluginCornerRadiusPreset.Xs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取徽章/标签圆角半径。
|
||||
/// 用于小徽章、标签、角标等微元素。
|
||||
/// </summary>
|
||||
/// <param name="context">外观上下文</param>
|
||||
/// <returns>徽章圆角半径(像素)</returns>
|
||||
public static double GetBadgeCornerRadius(this IPluginAppearanceContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
return context.ResolveCornerRadius(PluginCornerRadiusPreset.Micro);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取中等面板圆角半径。
|
||||
/// 用于悬浮菜单、小提示框、子面板等。
|
||||
/// </summary>
|
||||
/// <param name="context">外观上下文</param>
|
||||
/// <returns>中等面板圆角半径(像素)</returns>
|
||||
public static double GetMediumPanelCornerRadius(this IPluginAppearanceContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
return context.ResolveCornerRadius(PluginCornerRadiusPreset.Md);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取大面板圆角半径。
|
||||
/// 用于对话框、设置面板等大型容器(非桌面组件)。
|
||||
/// </summary>
|
||||
/// <param name="context">外观上下文</param>
|
||||
/// <returns>大面板圆角半径(像素)</returns>
|
||||
public static double GetLargePanelCornerRadius(this IPluginAppearanceContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
return context.ResolveCornerRadius(PluginCornerRadiusPreset.Lg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将圆角预设转换为 Avalonia CornerRadius。
|
||||
/// </summary>
|
||||
/// <param name="context">外观上下文</param>
|
||||
/// <param name="preset">圆角预设</param>
|
||||
/// <returns>Avalonia CornerRadius 结构</returns>
|
||||
public static CornerRadius ToCornerRadius(this IPluginAppearanceContext context, PluginCornerRadiusPreset preset)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
var radius = context.ResolveCornerRadius(preset);
|
||||
return new CornerRadius(radius);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前主题变体(亮色/暗色)。
|
||||
/// </summary>
|
||||
/// <param name="context">外观上下文</param>
|
||||
/// <returns>是否为暗色主题</returns>
|
||||
public static bool IsDarkTheme(this IPluginAppearanceContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
return string.Equals(context.Snapshot.ThemeVariant, "Dark", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前主题变体字符串。
|
||||
/// </summary>
|
||||
/// <param name="context">外观上下文</param>
|
||||
/// <returns>主题变体字符串("Light" 或 "Dark")</returns>
|
||||
public static string GetThemeVariant(this IPluginAppearanceContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
return context.Snapshot.ThemeVariant;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 内部元素层级,用于区分不同层级的圆角需求。
|
||||
/// </summary>
|
||||
public enum InnerElementLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// 内部卡片:使用 Sm token(14px @ 1.0x)
|
||||
/// </summary>
|
||||
Card,
|
||||
|
||||
/// <summary>
|
||||
/// 交互控件:使用 Xs token(12px @ 1.0x)
|
||||
/// </summary>
|
||||
Control,
|
||||
|
||||
/// <summary>
|
||||
/// 微元素徽章:使用 Micro token(6px @ 1.0x)
|
||||
/// </summary>
|
||||
Badge
|
||||
}
|
||||
@@ -72,14 +72,11 @@ public sealed class PluginDesktopComponentRegistration
|
||||
var resolved = CornerRadiusResolver is not null
|
||||
? CornerRadiusResolver(appearance, Math.Max(1d, cellSize))
|
||||
: CornerRadiusPreset == PluginCornerRadiusPreset.Default
|
||||
? appearance.ResolveScaledCornerRadius(
|
||||
Math.Clamp(Math.Max(1d, cellSize) * 0.22, 8, 18),
|
||||
8,
|
||||
18)
|
||||
? appearance.ResolveCornerRadius(PluginCornerRadiusPreset.Component)
|
||||
: appearance.ResolveCornerRadius(CornerRadiusPreset);
|
||||
|
||||
return double.IsFinite(resolved)
|
||||
? Math.Max(0d, resolved)
|
||||
: appearance.ResolveCornerRadius(PluginCornerRadiusPreset.Default);
|
||||
: appearance.ResolveCornerRadius(PluginCornerRadiusPreset.Component);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,10 +35,11 @@ public sealed class CornerRadiusStyleTests
|
||||
Component: 24d),
|
||||
ThemeVariant: "Light"));
|
||||
|
||||
// Preset resolution should return fixed values from tokens regardless of any legacy scale
|
||||
// Preset resolution should return fixed values from tokens
|
||||
Assert.Equal(20d, context.ResolveCornerRadius(PluginCornerRadiusPreset.Md), 3);
|
||||
Assert.Equal(20d, context.ResolveCornerRadius(PluginCornerRadiusPreset.Md, maximum: 15d), 3);
|
||||
Assert.Equal(20d, context.ResolveScaledCornerRadius(18d), 3);
|
||||
Assert.Equal(15d, context.ResolveCornerRadius(PluginCornerRadiusPreset.Md, maximum: 15d), 3);
|
||||
// ResolveScaledCornerRadius returns baseRadius as-is when no min/max specified
|
||||
Assert.Equal(18d, context.ResolveScaledCornerRadius(18d), 3);
|
||||
Assert.Equal(24d, context.ResolveCornerRadius(PluginCornerRadiusPreset.Component), 3);
|
||||
}
|
||||
|
||||
@@ -60,8 +61,12 @@ public sealed class CornerRadiusStyleTests
|
||||
96d,
|
||||
appearanceContext);
|
||||
|
||||
Assert.Equal(24d, context.ResolveScaledCornerRadius(12d), 3);
|
||||
Assert.Equal(24d, context.ResolveScaledCornerRadius(12d, 8d, 18d), 3);
|
||||
// ResolveScaledCornerRadius returns baseRadius as-is when no min/max specified
|
||||
Assert.Equal(12d, context.ResolveScaledCornerRadius(12d), 3);
|
||||
// When min/max specified, value is clamped
|
||||
Assert.Equal(12d, context.ResolveScaledCornerRadius(12d, 8d, 18d), 3);
|
||||
// Component token access
|
||||
Assert.Equal(24d, context.CornerRadiusTokens.Component, 3);
|
||||
}
|
||||
|
||||
private sealed class NullServiceProvider : IServiceProvider
|
||||
|
||||
@@ -848,6 +848,8 @@ public sealed class PluginLoader
|
||||
|
||||
private sealed class PluginRuntimeContext : IPluginRuntimeContext
|
||||
{
|
||||
private readonly PluginAppearanceContext _appearanceContext;
|
||||
|
||||
public PluginRuntimeContext(
|
||||
PluginManifest manifest,
|
||||
string pluginDirectory,
|
||||
@@ -859,7 +861,8 @@ public sealed class PluginLoader
|
||||
PluginDirectory = pluginDirectory;
|
||||
DataDirectory = dataDirectory;
|
||||
Properties = properties;
|
||||
Appearance = new PluginAppearanceContext(appearanceSnapshot);
|
||||
_appearanceContext = new PluginAppearanceContext(appearanceSnapshot);
|
||||
Appearance = _appearanceContext;
|
||||
Services = NullServiceProvider.Instance;
|
||||
}
|
||||
|
||||
@@ -898,6 +901,14 @@ public sealed class PluginLoader
|
||||
{
|
||||
Services = services ?? throw new ArgumentNullException(nameof(services));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新外观快照并通知插件。
|
||||
/// </summary>
|
||||
internal void UpdateAppearanceSnapshot(PluginAppearanceSnapshot newSnapshot, IReadOnlyCollection<AppearanceProperty> changedProperties)
|
||||
{
|
||||
_appearanceContext.UpdateSnapshot(newSnapshot, changedProperties);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class PluginMessageBus : IPluginMessageBus, IDisposable
|
||||
|
||||
Reference in New Issue
Block a user