mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-25 19:24:28 +08:00
0.7.1
This commit is contained in:
@@ -9,6 +9,7 @@ using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using LanMountainDesktop.ComponentSystem;
|
||||
using LanMountainDesktop.ComponentSystem.Extensions;
|
||||
using LanMountainDesktop.Host.Abstractions;
|
||||
using LanMountainDesktop.PluginSdk;
|
||||
using LanMountainDesktop.Services.Settings;
|
||||
using LanMountainDesktop.Views.Components;
|
||||
@@ -62,7 +63,11 @@ public static class DesktopComponentRegistryFactory
|
||||
registration.ComponentId,
|
||||
registration.DisplayNameLocalizationKey,
|
||||
factoryContext => CreatePluginControl(contribution, factoryContext),
|
||||
registration.CornerRadiusResolver));
|
||||
chromeContext =>
|
||||
{
|
||||
var appearanceContext = CreatePluginAppearanceContext(chromeContext);
|
||||
return registration.ResolveCornerRadius(appearanceContext, chromeContext.CellSize);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +128,10 @@ public static class DesktopComponentRegistryFactory
|
||||
contribution.Plugin.Manifest.Id,
|
||||
settingsService);
|
||||
var appearanceSnapshot = HostAppearanceThemeProvider.GetOrCreate().GetCurrent();
|
||||
var pluginAppearance = new PluginAppearanceContext(new PluginAppearanceSnapshot(
|
||||
GlobalCornerRadiusScale: appearanceSnapshot.GlobalCornerRadiusScale,
|
||||
CornerRadiusTokens: PluginCornerRadiusTokens.FromShared(appearanceSnapshot.CornerRadiusTokens),
|
||||
ThemeVariant: appearanceSnapshot.IsNightMode ? "Dark" : "Light"));
|
||||
var pluginContext = new PluginDesktopComponentContext(
|
||||
contribution.Plugin.Manifest,
|
||||
contribution.Plugin.Context.PluginDirectory,
|
||||
@@ -132,8 +141,7 @@ public static class DesktopComponentRegistryFactory
|
||||
contribution.Registration.ComponentId,
|
||||
context.PlacementId,
|
||||
context.CellSize,
|
||||
appearanceSnapshot.GlobalCornerRadiusScale,
|
||||
appearanceSnapshot.CornerRadiusTokens,
|
||||
pluginAppearance,
|
||||
pluginSettings);
|
||||
|
||||
return contribution.Registration.ControlFactory(contribution.Plugin.Services, pluginContext);
|
||||
@@ -146,6 +154,14 @@ public static class DesktopComponentRegistryFactory
|
||||
}
|
||||
}
|
||||
|
||||
private static IPluginAppearanceContext CreatePluginAppearanceContext(ComponentChromeContext chromeContext)
|
||||
{
|
||||
return new PluginAppearanceContext(new PluginAppearanceSnapshot(
|
||||
GlobalCornerRadiusScale: chromeContext.GlobalCornerRadiusScale,
|
||||
CornerRadiusTokens: PluginCornerRadiusTokens.FromShared(chromeContext.CornerRadiusTokens),
|
||||
ThemeVariant: "Unknown"));
|
||||
}
|
||||
|
||||
private static Control CreatePluginErrorControl(
|
||||
PluginDesktopComponentContribution contribution,
|
||||
Exception exception)
|
||||
|
||||
@@ -325,8 +325,9 @@ public partial class AnalogClockWidget : UserControl, IDesktopComponentWidget, I
|
||||
{
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = ResolveScale();
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(42 * scale, 16, 56);
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
RootBorder.Padding = new Thickness(Math.Clamp(14 * scale, 8, 26));
|
||||
ApplyModeVisualIfNeeded();
|
||||
}
|
||||
|
||||
@@ -381,12 +381,13 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(34 * softScale, 16, 52);
|
||||
var unifiedMainRectangle = ResolveUnifiedMainRectangle();
|
||||
RootBorder.CornerRadius = unifiedMainRectangle;
|
||||
RootBorder.Padding = new Thickness(0);
|
||||
|
||||
var horizontalPadding = Math.Clamp(16 * softScale, 8, 24);
|
||||
var verticalPadding = Math.Clamp(14 * softScale, 7, 20);
|
||||
CardBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * softScale, 16, 52);
|
||||
CardBorder.CornerRadius = unifiedMainRectangle;
|
||||
CardBorder.Padding = new Thickness(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
|
||||
|
||||
var innerWidth = Math.Max(120, totalWidth - (horizontalPadding * 2d));
|
||||
@@ -615,6 +616,11 @@ public partial class BaiduHotSearchWidget : UserControl, IDesktopComponentWidget
|
||||
return Math.Clamp(Math.Min(scaleX, scaleY), 0.72, 2.8);
|
||||
}
|
||||
|
||||
private CornerRadius ResolveUnifiedMainRectangle() => new(ResolveUnifiedMainRadiusValue());
|
||||
|
||||
private static double ResolveUnifiedMainRadiusValue() =>
|
||||
HostAppearanceThemeProvider.GetOrCreate().GetCurrent().CornerRadiusTokens.Lg.TopLeft;
|
||||
|
||||
private string L(string key, string fallback)
|
||||
{
|
||||
return _localizationService.GetString(_languageCode, key, fallback);
|
||||
|
||||
@@ -386,12 +386,13 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(34 * softScale, 16, 52);
|
||||
var unifiedMainRectangle = ResolveUnifiedMainRectangle();
|
||||
RootBorder.CornerRadius = unifiedMainRectangle;
|
||||
RootBorder.Padding = new Thickness(0);
|
||||
|
||||
var horizontalPadding = Math.Clamp(16 * softScale, 8, 24);
|
||||
var verticalPadding = Math.Clamp(14 * softScale, 7, 20);
|
||||
CardBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * softScale, 16, 52);
|
||||
CardBorder.CornerRadius = unifiedMainRectangle;
|
||||
CardBorder.Padding = new Thickness(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
|
||||
|
||||
var innerWidth = Math.Max(120, totalWidth - (horizontalPadding * 2d));
|
||||
@@ -629,6 +630,11 @@ public partial class BilibiliHotSearchWidget : UserControl, IDesktopComponentWid
|
||||
return Math.Clamp(Math.Min(scaleX, scaleY), 0.72, 2.8);
|
||||
}
|
||||
|
||||
private CornerRadius ResolveUnifiedMainRectangle() => new(ResolveUnifiedMainRadiusValue());
|
||||
|
||||
private static double ResolveUnifiedMainRadiusValue() =>
|
||||
HostAppearanceThemeProvider.GetOrCreate().GetCurrent().CornerRadiusTokens.Lg.TopLeft;
|
||||
|
||||
private string L(string key, string fallback)
|
||||
{
|
||||
return _localizationService.GetString(_languageCode, key, fallback);
|
||||
|
||||
@@ -79,11 +79,12 @@ public partial class BrowserWidget : UserControl, IDesktopComponentWidget,
|
||||
{
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.34, 12, 28);
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
RootBorder.Padding = new Thickness(Math.Clamp(_currentCellSize * 0.20, 8, 18));
|
||||
|
||||
WebViewHostBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.24, 10, 22);
|
||||
AddressBarBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.22, 10, 20);
|
||||
WebViewHostBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
AddressBarBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
AddressBarBorder.Padding = new Thickness(8, 6);
|
||||
|
||||
if (RootBorder.Child is Grid rootGrid)
|
||||
|
||||
@@ -613,7 +613,7 @@ public partial class ClassScheduleWidget : UserControl, IDesktopComponentWidget,
|
||||
? CreateBrush("#FF4FC3F7")
|
||||
: CreateBrush("#FF3250");
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.45, 24, 44);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
RootBorder.Background = _isNightVisual
|
||||
? CreateGradientBrush("#171A21", "#0C0E14")
|
||||
: CreateGradientBrush("#F7F8FC", "#ECEFF6");
|
||||
|
||||
@@ -132,8 +132,8 @@ public partial class ClockWidget : UserControl, IDesktopComponentWidget, ITimeZo
|
||||
var targetHeight = Math.Clamp(cellSize * 0.74, 34, 74);
|
||||
RootBorder.Height = targetHeight;
|
||||
|
||||
// 2. 动态圆角:确保始终是完美的胶囊半圆
|
||||
RootBorder.CornerRadius = new CornerRadius(targetHeight / 2);
|
||||
// 2. 主矩形统一到主题主档圆角
|
||||
RootBorder.CornerRadius = ResolveUnifiedMainRectangle();
|
||||
RootBorder.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
|
||||
|
||||
// 3. 核心:满盈字阶 (Filled Typography)
|
||||
@@ -189,4 +189,9 @@ public partial class ClockWidget : UserControl, IDesktopComponentWidget, ITimeZo
|
||||
RootBorder.ClearValue(Border.BorderThicknessProperty);
|
||||
RootBorder.ClearValue(Border.BoxShadowProperty);
|
||||
}
|
||||
|
||||
private CornerRadius ResolveUnifiedMainRectangle() => new(ResolveUnifiedMainRadiusValue());
|
||||
|
||||
private static double ResolveUnifiedMainRadiusValue() =>
|
||||
HostAppearanceThemeProvider.GetOrCreate().GetCurrent().CornerRadiusTokens.Lg.TopLeft;
|
||||
}
|
||||
|
||||
@@ -545,10 +545,11 @@ public partial class CnrDailyNewsWidget : UserControl, IDesktopComponentWidget,
|
||||
var scale = ResolveScale();
|
||||
var totalWidth = Bounds.Width > 1 ? Bounds.Width : _currentCellSize * BaseWidthCells;
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 16, 52);
|
||||
var unifiedMainRectangle = ResolveUnifiedMainRectangle();
|
||||
RootBorder.CornerRadius = unifiedMainRectangle;
|
||||
RootBorder.Padding = new Thickness(0);
|
||||
|
||||
CardBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 16, 52);
|
||||
CardBorder.CornerRadius = unifiedMainRectangle;
|
||||
CardBorder.Padding = new Thickness(
|
||||
Math.Clamp(16 * scale, 8, 24),
|
||||
Math.Clamp(14 * scale, 7, 22),
|
||||
@@ -865,6 +866,11 @@ public partial class CnrDailyNewsWidget : UserControl, IDesktopComponentWidget,
|
||||
return Math.Clamp(Math.Min(cellScale, Math.Min(widthScale, heightScale)), 0.56, 2.0);
|
||||
}
|
||||
|
||||
private CornerRadius ResolveUnifiedMainRectangle() => new(ResolveUnifiedMainRadiusValue());
|
||||
|
||||
private static double ResolveUnifiedMainRadiusValue() =>
|
||||
HostAppearanceThemeProvider.GetOrCreate().GetCurrent().CornerRadiusTokens.Lg.TopLeft;
|
||||
|
||||
private static string NormalizeCompactText(string? text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
|
||||
@@ -9,6 +9,25 @@ namespace LanMountainDesktop.Views.Components;
|
||||
|
||||
internal static class ComponentChromeCornerRadiusHelper
|
||||
{
|
||||
public static double ResolveMainRectangleRadiusValue(ComponentChromeContext? chromeContext = null, double fallback = 24d)
|
||||
{
|
||||
if (chromeContext is not null)
|
||||
{
|
||||
return Math.Max(0d, chromeContext.CornerRadiusTokens.Lg.TopLeft);
|
||||
}
|
||||
|
||||
var snapshot = HostAppearanceThemeProvider.GetOrCreate().GetCurrent();
|
||||
var resolved = snapshot.CornerRadiusTokens.Lg.TopLeft;
|
||||
return double.IsFinite(resolved)
|
||||
? Math.Max(0d, resolved)
|
||||
: Math.Max(0d, fallback * ResolveScale(chromeContext));
|
||||
}
|
||||
|
||||
public static CornerRadius ResolveMainRectangleRadius(ComponentChromeContext? chromeContext = null, double fallback = 24d)
|
||||
{
|
||||
return new CornerRadius(ResolveMainRectangleRadiusValue(chromeContext, fallback));
|
||||
}
|
||||
|
||||
public static double ResolveScale(ComponentChromeContext? chromeContext = null)
|
||||
{
|
||||
if (chromeContext is not null)
|
||||
|
||||
@@ -101,7 +101,7 @@ public partial class DailyArtworkWidget : UserControl, IDesktopComponentWidget,
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = ResolveScale();
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 16, 52);
|
||||
RootBorder.CornerRadius = ResolveUnifiedMainRectangle();
|
||||
|
||||
InfoPanel.Padding = new Thickness(
|
||||
Math.Clamp(18 * scale, 10, 28),
|
||||
@@ -754,6 +754,11 @@ public partial class DailyArtworkWidget : UserControl, IDesktopComponentWidget,
|
||||
return Math.Clamp(Math.Min(cellScale, Math.Min(widthScale, heightScale)), 0.56, 2.0);
|
||||
}
|
||||
|
||||
private CornerRadius ResolveUnifiedMainRectangle() => new(ResolveUnifiedMainRadiusValue());
|
||||
|
||||
private static double ResolveUnifiedMainRadiusValue() =>
|
||||
HostAppearanceThemeProvider.GetOrCreate().GetCurrent().CornerRadiusTokens.Lg.TopLeft;
|
||||
|
||||
private static string NormalizeCompactText(string? text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
|
||||
@@ -92,7 +92,7 @@ public partial class DailyPoetryWidget : UserControl, IDesktopComponentWidget, I
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = ResolveScale();
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 16, 52);
|
||||
RootBorder.CornerRadius = ResolveUnifiedMainRectangle();
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(20 * scale, 10, 34),
|
||||
Math.Clamp(16 * scale, 8, 28),
|
||||
@@ -452,6 +452,11 @@ public partial class DailyPoetryWidget : UserControl, IDesktopComponentWidget, I
|
||||
return Math.Clamp(Math.Min(cellScale, Math.Min(widthScale, heightScale)), 0.52, 2.2);
|
||||
}
|
||||
|
||||
private CornerRadius ResolveUnifiedMainRectangle() => new(ResolveUnifiedMainRadiusValue());
|
||||
|
||||
private static double ResolveUnifiedMainRadiusValue() =>
|
||||
HostAppearanceThemeProvider.GetOrCreate().GetCurrent().CornerRadiusTokens.Lg.TopLeft;
|
||||
|
||||
private void ApplyAdaptiveTextLayout(bool isNightMode, double scale, double totalWidth, double totalHeight)
|
||||
{
|
||||
var padding = RootBorder.Padding;
|
||||
|
||||
@@ -328,8 +328,9 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(30 * scale, 14, 40);
|
||||
CardBorder.CornerRadius = RootBorder.CornerRadius;
|
||||
var unifiedMainRectangle = ResolveUnifiedMainRectangle();
|
||||
RootBorder.CornerRadius = unifiedMainRectangle;
|
||||
CardBorder.CornerRadius = unifiedMainRectangle;
|
||||
CardBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale, 8, 18),
|
||||
Math.Clamp(11 * scale, 7, 16),
|
||||
@@ -482,6 +483,11 @@ public partial class DailyWord2x2Widget : UserControl, IDesktopComponentWidget,
|
||||
return Math.Clamp(Math.Min(cellScale, Math.Min(widthScale, heightScale)), 0.56, 2.0);
|
||||
}
|
||||
|
||||
private CornerRadius ResolveUnifiedMainRectangle() => new(ResolveUnifiedMainRadiusValue());
|
||||
|
||||
private static double ResolveUnifiedMainRadiusValue() =>
|
||||
HostAppearanceThemeProvider.GetOrCreate().GetCurrent().CornerRadiusTokens.Lg.TopLeft;
|
||||
|
||||
private string L(string key, string fallback)
|
||||
{
|
||||
return _localizationService.GetString(_languageCode, key, fallback);
|
||||
|
||||
@@ -298,7 +298,7 @@ public partial class DailyWordWidget : UserControl, IDesktopComponentWidget, IRe
|
||||
isFourByThree = widthRatio >= 0.9 && heightRatio >= 1.35;
|
||||
}
|
||||
|
||||
var containerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 16, 52);
|
||||
var containerRadius = ResolveUnifiedMainRectangle();
|
||||
RootBorder.CornerRadius = containerRadius;
|
||||
RootBorder.Padding = new Thickness(0);
|
||||
|
||||
@@ -527,6 +527,11 @@ public partial class DailyWordWidget : UserControl, IDesktopComponentWidget, IRe
|
||||
return Math.Clamp(Math.Min(cellScale, Math.Min(widthScale, heightScale)), 0.56, 2.0);
|
||||
}
|
||||
|
||||
private CornerRadius ResolveUnifiedMainRectangle() => new(ResolveUnifiedMainRadiusValue());
|
||||
|
||||
private static double ResolveUnifiedMainRadiusValue() =>
|
||||
HostAppearanceThemeProvider.GetOrCreate().GetCurrent().CornerRadiusTokens.Lg.TopLeft;
|
||||
|
||||
private string BuildPronunciationText(DailyWordSnapshot snapshot)
|
||||
{
|
||||
var uk = NormalizeCompactText(snapshot.UkPronunciation);
|
||||
|
||||
@@ -324,8 +324,9 @@ public partial class DateWidget : UserControl, IDesktopComponentWidget, ITimeZon
|
||||
private void ApplyAdaptiveTypography()
|
||||
{
|
||||
var scale = ResolveScale();
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(28 * scale, 16, 40);
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
RootBorder.Padding = new Thickness(Math.Clamp(11 * scale, 7, 17));
|
||||
|
||||
LayoutRoot.ColumnSpacing = Math.Clamp(10 * scale, 6, 16);
|
||||
@@ -337,7 +338,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 = ComponentChromeCornerRadiusHelper.Scale(24 * scale, 14, 34);
|
||||
LunarCardBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
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));
|
||||
|
||||
@@ -89,12 +89,7 @@ public sealed class DesktopComponentRuntimeRegistration
|
||||
public sealed class DesktopComponentRuntimeDescriptor
|
||||
{
|
||||
private static readonly Func<ComponentChromeContext, double> DefaultCornerRadiusResolver =
|
||||
chromeContext =>
|
||||
{
|
||||
var scale = Math.Max(GlobalAppearanceSettings.MinimumCornerRadiusScale, chromeContext.GlobalCornerRadiusScale);
|
||||
var baseRadius = Math.Clamp(chromeContext.CellSize * 0.22, 8, 18);
|
||||
return Math.Clamp(baseRadius * scale, 8 * scale, 18 * scale);
|
||||
};
|
||||
chromeContext => ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadiusValue(chromeContext);
|
||||
|
||||
private readonly Func<DesktopComponentControlFactoryContext, Control> _controlFactory;
|
||||
private readonly Func<ComponentChromeContext, double> _cornerRadiusResolver;
|
||||
@@ -324,194 +319,155 @@ public sealed class DesktopComponentRuntimeRegistry
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.Date,
|
||||
"component.date",
|
||||
() => new DateWidget(),
|
||||
_ => 16),
|
||||
() => new DateWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.MonthCalendar,
|
||||
"component.month_calendar",
|
||||
() => new MonthCalendarWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.26, 10, 22)),
|
||||
() => new MonthCalendarWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.LunarCalendar,
|
||||
"component.lunar_calendar",
|
||||
() => new LunarCalendarWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.30, 12, 26)),
|
||||
() => new LunarCalendarWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopClock,
|
||||
"component.desktop_clock",
|
||||
() => new AnalogClockWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.30, 12, 28)),
|
||||
() => new AnalogClockWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopWeatherClock,
|
||||
"component.weather_clock",
|
||||
() => new WeatherClockWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 14, 30)),
|
||||
() => new WeatherClockWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopWorldClock,
|
||||
"component.world_clock",
|
||||
() => new WorldClockWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.30, 10, 24)),
|
||||
() => new WorldClockWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopTimer,
|
||||
"component.desktop_timer",
|
||||
() => new TimerWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.30, 12, 28)),
|
||||
() => new TimerWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopWeather,
|
||||
"component.desktop_weather",
|
||||
() => new WeatherWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.45, 24, 44)),
|
||||
() => new WeatherWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopHourlyWeather,
|
||||
"component.hourly_weather",
|
||||
() => new HourlyWeatherWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.45, 24, 44)),
|
||||
() => new HourlyWeatherWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopMultiDayWeather,
|
||||
"component.multiday_weather",
|
||||
() => new MultiDayWeatherWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.45, 24, 44)),
|
||||
() => new MultiDayWeatherWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopExtendedWeather,
|
||||
"component.extended_weather",
|
||||
() => new ExtendedWeatherWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.45, 24, 44)),
|
||||
() => new ExtendedWeatherWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopClassSchedule,
|
||||
"component.class_schedule",
|
||||
() => new ClassScheduleWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.45, 24, 44)),
|
||||
() => new ClassScheduleWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopMusicControl,
|
||||
"component.music_control",
|
||||
() => new MusicControlWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 14, 30)),
|
||||
() => new MusicControlWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopAudioRecorder,
|
||||
"component.audio_recorder",
|
||||
() => new RecordingWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.36, 16, 34)),
|
||||
() => new RecordingWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopStudyEnvironment,
|
||||
"component.study_environment",
|
||||
() => new StudyEnvironmentWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.36, 12, 26)),
|
||||
() => new StudyEnvironmentWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopStudySessionControl,
|
||||
"component.study_session_control",
|
||||
() => new StudySessionControlWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.36, 10, 24)),
|
||||
() => new StudySessionControlWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopStudySessionHistory,
|
||||
"component.study_session_history",
|
||||
() => new StudySessionHistoryWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 10, 24)),
|
||||
() => new StudySessionHistoryWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopStudyNoiseCurve,
|
||||
"component.study_noise_curve",
|
||||
() => new StudyNoiseCurveWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 12, 26)),
|
||||
() => new StudyNoiseCurveWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopStudyNoiseDistribution,
|
||||
"component.study_noise_distribution",
|
||||
() => new StudyNoiseDistributionWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 12, 26)),
|
||||
() => new StudyNoiseDistributionWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopStudyScoreOverview,
|
||||
"component.study_score_overview",
|
||||
() => new StudyScoreOverviewWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 12, 28)),
|
||||
() => new StudyScoreOverviewWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopStudyDeductionReasons,
|
||||
"component.study_deduction_reasons",
|
||||
() => new StudyDeductionReasonsWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 10, 24)),
|
||||
() => new StudyDeductionReasonsWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopStudyInterruptDensity,
|
||||
"component.study_interrupt_density",
|
||||
() => new StudyInterruptDensityWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 10, 24)),
|
||||
() => new StudyInterruptDensityWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopDailyPoetry,
|
||||
"component.daily_poetry",
|
||||
() => new DailyPoetryWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 14, 30)),
|
||||
() => new DailyPoetryWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopDailyArtwork,
|
||||
"component.daily_artwork",
|
||||
() => new DailyArtworkWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 14, 30)),
|
||||
() => new DailyArtworkWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopDailyWord,
|
||||
"component.daily_word",
|
||||
() => new DailyWordWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 14, 30)),
|
||||
() => new DailyWordWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopDailyWord2x2,
|
||||
"component.daily_word_2x2",
|
||||
() => new DailyWord2x2Widget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 12, 26)),
|
||||
() => new DailyWord2x2Widget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopCnrDailyNews,
|
||||
"component.cnr_daily_news",
|
||||
() => new CnrDailyNewsWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 14, 30)),
|
||||
() => new CnrDailyNewsWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopIfengNews,
|
||||
"component.ifeng_news",
|
||||
() => new IfengNewsWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.30, 12, 24)),
|
||||
() => new IfengNewsWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopBilibiliHotSearch,
|
||||
"component.bilibili_hot_search",
|
||||
() => new BilibiliHotSearchWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 14, 30)),
|
||||
() => new BilibiliHotSearchWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopBaiduHotSearch,
|
||||
"component.baidu_hot_search",
|
||||
() => new BaiduHotSearchWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.34, 14, 30)),
|
||||
() => new BaiduHotSearchWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopStcn24Forum,
|
||||
"component.stcn24_forum",
|
||||
() => new Stcn24ForumWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.28, 12, 24)),
|
||||
() => new Stcn24ForumWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopExchangeRateCalculator,
|
||||
"component.exchange_rate_converter",
|
||||
() => new ExchangeRateCalculatorWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.28, 12, 26)),
|
||||
() => new ExchangeRateCalculatorWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopWhiteboard,
|
||||
"component.whiteboard",
|
||||
() => new WhiteboardWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.24, 10, 24)),
|
||||
() => new WhiteboardWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopBlackboardLandscape,
|
||||
"component.blackboard_landscape",
|
||||
() => new WhiteboardWidget(baseWidthCells: 4),
|
||||
cellSize => Math.Clamp(cellSize * 0.24, 10, 24)),
|
||||
() => new WhiteboardWidget(baseWidthCells: 4)),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopBrowser,
|
||||
"component.browser",
|
||||
() => new BrowserWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.24, 10, 24)),
|
||||
() => new BrowserWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopOfficeRecentDocuments,
|
||||
"component.office_recent_documents",
|
||||
_ => new OfficeRecentDocumentsWidget(),
|
||||
chromeContext => Math.Clamp(chromeContext.CellSize * 0.50, 10, 24) *
|
||||
Math.Max(GlobalAppearanceSettings.MinimumCornerRadiusScale, chromeContext.GlobalCornerRadiusScale)),
|
||||
() => new OfficeRecentDocumentsWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.DesktopRemovableStorage,
|
||||
"component.removable_storage",
|
||||
() => new RemovableStorageWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.46, 12, 26)),
|
||||
() => new RemovableStorageWidget()),
|
||||
new DesktopComponentRuntimeRegistration(
|
||||
BuiltInComponentIds.HolidayCalendar,
|
||||
"component.holiday_calendar",
|
||||
() => new HolidayCalendarWidget(),
|
||||
cellSize => Math.Clamp(cellSize * 0.32, 12, 28))
|
||||
() => new HolidayCalendarWidget())
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ public partial class ExchangeRateCalculatorWidget : UserControl, IDesktopCompone
|
||||
{
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = ResolveScale();
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 14, 48);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
RootBorder.Padding = new Thickness(ComponentChromeCornerRadiusHelper.SafeValue(12 * scale, 6, 18));
|
||||
}
|
||||
|
||||
|
||||
@@ -124,13 +124,9 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(
|
||||
_currentCellSize * metrics.CornerRadiusScale,
|
||||
28,
|
||||
54,
|
||||
_chromeContext);
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius(_chromeContext);
|
||||
ComponentChromeCornerRadiusHelper.Apply(
|
||||
radius,
|
||||
mainRectangleCornerRadius,
|
||||
RootBorder,
|
||||
BackgroundImageLayer,
|
||||
BackgroundMotionLayer,
|
||||
|
||||
@@ -216,7 +216,7 @@ public partial class HolidayCalendarWidget : UserControl, IDesktopComponentWidge
|
||||
var titleNeedsTwoLines = isUltraCompact || titleUnits >= (isCompact ? 13 : 17);
|
||||
var dateNeedsTwoLines = isUltraCompact || dateUnits >= (isCompact ? 15 : 20);
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(shortSide * 0.13, 10, 46);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
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);
|
||||
|
||||
@@ -270,14 +270,10 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(
|
||||
_currentCellSize * metrics.CornerRadiusScale,
|
||||
24,
|
||||
46,
|
||||
_chromeContext);
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius(_chromeContext);
|
||||
|
||||
ComponentChromeCornerRadiusHelper.Apply(
|
||||
cornerRadius,
|
||||
mainRectangleCornerRadius,
|
||||
RootBorder,
|
||||
BackgroundImageLayer,
|
||||
BackgroundMotionLayer,
|
||||
|
||||
@@ -400,8 +400,9 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(32 * softScale, 16, 46);
|
||||
CardBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(32 * softScale, 16, 46);
|
||||
var unifiedMainRectangle = ResolveUnifiedMainRectangle();
|
||||
RootBorder.CornerRadius = unifiedMainRectangle;
|
||||
CardBorder.CornerRadius = unifiedMainRectangle;
|
||||
|
||||
var horizontalPadding = Math.Clamp(14 * softScale, 8, 20);
|
||||
var verticalPadding = Math.Clamp(14 * softScale, 8, 20);
|
||||
@@ -683,6 +684,11 @@ public partial class IfengNewsWidget : UserControl, IDesktopComponentWidget, IRe
|
||||
return Math.Clamp(Math.Min(scaleX, scaleY), 0.72, 2.4);
|
||||
}
|
||||
|
||||
private CornerRadius ResolveUnifiedMainRectangle() => new(ResolveUnifiedMainRadiusValue());
|
||||
|
||||
private static double ResolveUnifiedMainRadiusValue() =>
|
||||
HostAppearanceThemeProvider.GetOrCreate().GetCurrent().CornerRadiusTokens.Lg.TopLeft;
|
||||
|
||||
private static string NormalizeCompactText(string? text)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
|
||||
@@ -181,8 +181,9 @@ public partial class LunarCalendarWidget : UserControl, IDesktopComponentWidget,
|
||||
private void ApplyAdaptiveTypography()
|
||||
{
|
||||
var scale = ResolveScale();
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(30 * scale, 16, 44);
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
RootBorder.Padding = new Thickness(ComponentChromeCornerRadiusHelper.SafeValue(16 * scale, 8, 24));
|
||||
LayoutRoot.RowSpacing = Math.Clamp(10 * scale, 5, 18);
|
||||
DividerBorder.Margin = new Thickness(
|
||||
|
||||
@@ -216,8 +216,9 @@ public partial class MonthCalendarWidget : UserControl, IDesktopComponentWidget,
|
||||
private void ApplyAdaptiveTypography()
|
||||
{
|
||||
var scale = ResolveScale();
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(28 * scale, 14, 40);
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
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);
|
||||
|
||||
@@ -268,14 +268,10 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(
|
||||
_currentCellSize * metrics.CornerRadiusScale,
|
||||
24,
|
||||
46,
|
||||
_chromeContext);
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius(_chromeContext);
|
||||
|
||||
ComponentChromeCornerRadiusHelper.Apply(
|
||||
cornerRadius,
|
||||
mainRectangleCornerRadius,
|
||||
RootBorder,
|
||||
BackgroundImageLayer,
|
||||
BackgroundMotionLayer,
|
||||
|
||||
@@ -63,7 +63,7 @@ public partial class MusicControlWidget : UserControl, IDesktopComponentWidget,
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = ResolveScale();
|
||||
|
||||
var rootCornerRadius = ComponentChromeCornerRadiusHelper.Scale(30 * scale, 16, 44);
|
||||
var rootCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
|
||||
RootBorder.CornerRadius = rootCornerRadius;
|
||||
ContentPaddingBorder.Padding = new Thickness(
|
||||
@@ -84,7 +84,7 @@ public partial class MusicControlWidget : UserControl, IDesktopComponentWidget,
|
||||
|
||||
CoverBorder.Width = Math.Clamp(56 * scale, 38, 86);
|
||||
CoverBorder.Height = Math.Clamp(56 * scale, 38, 86);
|
||||
CoverBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(12 * scale, 8, 16);
|
||||
CoverBorder.CornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
|
||||
TitleTextBlock.FontSize = Math.Clamp(20 * scale, 12, 28);
|
||||
ArtistTextBlock.FontSize = Math.Clamp(14 * scale, 9, 18);
|
||||
|
||||
@@ -36,7 +36,7 @@ public partial class OfficeRecentDocumentsWidget : UserControl, IDesktopComponen
|
||||
return;
|
||||
}
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(cellSize * 0.50, 10, 24);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
}
|
||||
|
||||
public void SetDesktopPageContext(bool isOnActivePage, bool isEditMode)
|
||||
|
||||
@@ -63,7 +63,7 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(34 * chromeScale, 16, 56);
|
||||
var rootRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
RootBorder.CornerRadius = rootRadius;
|
||||
RootBorder.Padding = new Thickness(0);
|
||||
RecorderCardBorder.CornerRadius = rootRadius;
|
||||
|
||||
@@ -347,7 +347,7 @@ public partial class RemovableStorageWidget : UserControl, IDesktopComponentWidg
|
||||
var scale = ResolveScale();
|
||||
var width = Bounds.Width > 1 ? Bounds.Width : _currentCellSize * 2;
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.44, 18, 34);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
RootBorder.Padding = new Thickness(
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(16 * scale, 10, 24),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(15 * scale, 10, 22),
|
||||
|
||||
@@ -602,8 +602,9 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(30 * softScale, 14, 44);
|
||||
CardBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(30 * softScale, 14, 44);
|
||||
var unifiedMainRectangle = ResolveUnifiedMainRectangle();
|
||||
RootBorder.CornerRadius = unifiedMainRectangle;
|
||||
CardBorder.CornerRadius = unifiedMainRectangle;
|
||||
CardBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * softScale, 8, 18),
|
||||
Math.Clamp(12 * softScale, 8, 18),
|
||||
@@ -833,6 +834,11 @@ public partial class Stcn24ForumWidget : UserControl, IDesktopComponentWidget, I
|
||||
return Math.Clamp(Math.Min(scaleX, scaleY), 0.62, 2.6);
|
||||
}
|
||||
|
||||
private CornerRadius ResolveUnifiedMainRectangle() => new(ResolveUnifiedMainRadiusValue());
|
||||
|
||||
private static double ResolveUnifiedMainRadiusValue() =>
|
||||
HostAppearanceThemeProvider.GetOrCreate().GetCurrent().CornerRadiusTokens.Lg.TopLeft;
|
||||
|
||||
private string L(string key, string fallback)
|
||||
{
|
||||
return _localizationService.GetString(_languageCode, key, fallback);
|
||||
|
||||
@@ -229,7 +229,8 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.46, 12, 34);
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale * compactMultiplier, 6, 18),
|
||||
Math.Clamp(10 * scale * compactMultiplier, 5, 16));
|
||||
@@ -276,6 +277,9 @@ public partial class StudyDeductionReasonsWidget : UserControl, IDesktopComponen
|
||||
SustainedRowBorder.Padding = rowPadding;
|
||||
TimeRowBorder.Padding = rowPadding;
|
||||
SegmentRowBorder.Padding = rowPadding;
|
||||
SustainedRowBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
TimeRowBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
SegmentRowBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
|
||||
SustainedMetricTextBlock.IsVisible = !_isUltraCompactMode;
|
||||
TimeMetricTextBlock.IsVisible = !_isUltraCompactMode;
|
||||
|
||||
@@ -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 = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.34, 10, 28);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(14 * scale, 8, 20),
|
||||
Math.Clamp(10 * scale, 6, 16));
|
||||
|
||||
@@ -255,7 +255,8 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.46, 12, 34);
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale * compactMultiplier, 6, 18),
|
||||
Math.Clamp(9 * scale * compactMultiplier, 5, 16));
|
||||
@@ -301,6 +302,8 @@ public partial class StudyInterruptDensityWidget : UserControl, IDesktopComponen
|
||||
Math.Clamp(6 * scale * compactMultiplier, 3, 9));
|
||||
CountCardBorder.Padding = cardPadding;
|
||||
DurationCardBorder.Padding = cardPadding;
|
||||
CountCardBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
DurationCardBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
|
||||
TitleTextBlock.IsVisible = !_isUltraCompactMode;
|
||||
ThresholdTextBlock.IsVisible = !_isUltraCompactMode;
|
||||
|
||||
@@ -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 = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.44, 14, 42);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
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 = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.44, 12, 34);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale * compactMultiplier, 6, 18),
|
||||
Math.Clamp(9 * scale * compactMultiplier, 5, 16));
|
||||
|
||||
@@ -258,7 +258,8 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.50, 14, 42);
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(16 * scale * compactMultiplier * expandedMultiplier, 8, 30),
|
||||
Math.Clamp(14 * scale * compactMultiplier * expandedMultiplier, 6, 26));
|
||||
@@ -305,7 +306,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 = ComponentChromeCornerRadiusHelper.Scale(10 * scale, 6, 18);
|
||||
var cardCornerRadius = mainRectangleCornerRadius;
|
||||
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 = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.34, 10, 28);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
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 = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.20, 8, 14),
|
||||
CornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius(),
|
||||
Background = new SolidColorBrush(rowBackground),
|
||||
BorderBrush = new SolidColorBrush(rowBorderColor),
|
||||
BorderThickness = new Thickness(1),
|
||||
@@ -588,7 +588,8 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(_currentCellSize * 0.44, 12, 36);
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
RootBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale, 7, 22),
|
||||
Math.Clamp(9 * scale, 5, 16));
|
||||
@@ -606,7 +607,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 = ComponentChromeCornerRadiusHelper.Scale(12 * scale, 10, 18);
|
||||
DialogCardBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
DialogCardBorder.Padding = new Thickness(
|
||||
Math.Clamp(12 * scale, 9, 20),
|
||||
Math.Clamp(11 * scale, 8, 18));
|
||||
|
||||
@@ -196,10 +196,11 @@ public partial class TimerWidget : UserControl, IDesktopComponentWidget
|
||||
{
|
||||
_currentCellSize = Math.Max(1, cellSize);
|
||||
var scale = ResolveScale();
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(34 * scale, 12, 48);
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
RootBorder.Padding = new Thickness(Math.Clamp(14 * scale, 7, 22));
|
||||
TimerPanelBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(32 * scale, 12, 42);
|
||||
TimerPanelBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
|
||||
PlayButtonBorder.Width = Math.Clamp(42 * scale, 28, 58);
|
||||
PlayButtonBorder.Height = Math.Clamp(42 * scale, 28, 58);
|
||||
|
||||
@@ -151,11 +151,7 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(
|
||||
targetHeight * metrics.CornerRadiusScale,
|
||||
15,
|
||||
36,
|
||||
_chromeContext);
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius(_chromeContext);
|
||||
|
||||
var horizontalPadding = ComponentChromeCornerRadiusHelper.SafeValue(
|
||||
targetHeight * Lerp(0.18, 0.12, compactness),
|
||||
@@ -168,7 +164,7 @@ public partial class WeatherClockWidget : UserControl, IDesktopComponentWidget,
|
||||
20,
|
||||
_chromeContext);
|
||||
|
||||
RootBorder.CornerRadius = cornerRadius;
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
RootBorder.Padding = new Thickness(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
|
||||
|
||||
var columnSpacing = Math.Clamp(targetHeight * Lerp(0.16, 0.08, compactness), 2, 22);
|
||||
|
||||
@@ -213,16 +213,12 @@ 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 = ComponentChromeCornerRadiusHelper.Scale(
|
||||
_currentCellSize * metrics.CornerRadiusScale,
|
||||
26,
|
||||
46,
|
||||
_chromeContext);
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius(_chromeContext);
|
||||
var horizontalPadding = Math.Clamp(_currentCellSize * metrics.HorizontalPaddingScale, 10, 24);
|
||||
var verticalPadding = Math.Clamp(_currentCellSize * metrics.VerticalPaddingScale, 10, 24);
|
||||
|
||||
ComponentChromeCornerRadiusHelper.Apply(
|
||||
cornerRadius,
|
||||
mainRectangleCornerRadius,
|
||||
RootBorder,
|
||||
BackgroundImageLayer,
|
||||
BackgroundMotionLayer,
|
||||
|
||||
@@ -118,9 +118,10 @@ public partial class WhiteboardWidget : UserControl, IDesktopComponentWidget, IC
|
||||
var toolbarPaddingVertical = Math.Clamp(buttonSize * 0.24, 4, 8);
|
||||
|
||||
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);
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
CanvasBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
ToolbarBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
ToolbarBorder.Padding = new Thickness(
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(toolbarPaddingHorizontal, 6, 12),
|
||||
ComponentChromeCornerRadiusHelper.SafeValue(toolbarPaddingVertical, 4, 8));
|
||||
|
||||
@@ -166,11 +166,12 @@ public partial class WorldClockWidget : UserControl, IDesktopComponentWidget, IT
|
||||
|
||||
var totalWidth = Bounds.Width > 1 ? Bounds.Width : _currentCellSize * BaseWidthCells;
|
||||
var totalHeight = Bounds.Height > 1 ? Bounds.Height : _currentCellSize * BaseHeightCells;
|
||||
var mainRectangleCornerRadius = ComponentChromeCornerRadiusHelper.ResolveMainRectangleRadius();
|
||||
|
||||
var horizontalPadding = Math.Clamp(10 * scale, 4, 26);
|
||||
var verticalPadding = Math.Clamp(8 * scale, 3, 22);
|
||||
RootBorder.Padding = new Thickness(horizontalPadding, verticalPadding);
|
||||
RootBorder.CornerRadius = ComponentChromeCornerRadiusHelper.Scale(24 * scale, 10, 46);
|
||||
RootBorder.CornerRadius = mainRectangleCornerRadius;
|
||||
|
||||
var usableWidth = Math.Max(48, totalWidth - horizontalPadding * 2);
|
||||
var usableHeight = Math.Max(28, totalHeight - verticalPadding * 2);
|
||||
|
||||
@@ -269,7 +269,7 @@
|
||||
Grid.ColumnSpan="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
Margin="0"
|
||||
CornerRadius="36"
|
||||
CornerRadius="{DynamicResource DesignCornerRadiusLg}"
|
||||
Padding="6">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto"
|
||||
ColumnSpacing="8">
|
||||
|
||||
@@ -346,6 +346,7 @@ public partial class MainWindow : Window, ISettingsWindowAnchorProvider
|
||||
ApplyAdaptiveThemeResources();
|
||||
_recommendedColors = snapshot.MonetPalette.RecommendedColors;
|
||||
_monetColors = snapshot.MonetPalette.MonetColors;
|
||||
ApplyUnifiedMainRectangleChrome(snapshot);
|
||||
}, DispatcherPriority.Background);
|
||||
}
|
||||
|
||||
@@ -491,7 +492,7 @@ public partial class MainWindow : Window, ISettingsWindowAnchorProvider
|
||||
TopStatusBarHost.Padding = new Thickness(0);
|
||||
|
||||
BottomTaskbarContainer.Margin = new Thickness(0);
|
||||
BottomTaskbarContainer.CornerRadius = new CornerRadius(Math.Clamp(taskbarCellHeight * 0.58, 20, 44));
|
||||
ApplyUnifiedMainRectangleChrome();
|
||||
BottomTaskbarContainer.Padding = new Thickness(Math.Clamp(taskbarCellHeight * 0.16, 6, 14));
|
||||
|
||||
ClockWidget.Margin = new Thickness(0);
|
||||
@@ -527,6 +528,27 @@ public partial class MainWindow : Window, ISettingsWindowAnchorProvider
|
||||
UpdateComponentLibraryLayout(cellSize);
|
||||
}
|
||||
|
||||
private void ApplyUnifiedMainRectangleChrome(AppearanceThemeSnapshot? snapshot = null)
|
||||
{
|
||||
var unifiedMainRectangle = new CornerRadius(ResolveUnifiedMainRadiusValue(snapshot));
|
||||
BottomTaskbarContainer.CornerRadius = unifiedMainRectangle;
|
||||
|
||||
if (_currentDesktopCellSize > 0)
|
||||
{
|
||||
ClockWidget.ApplyCellSize(_currentDesktopCellSize);
|
||||
}
|
||||
}
|
||||
|
||||
private double ResolveUnifiedMainRadiusValue(AppearanceThemeSnapshot? snapshot = null)
|
||||
{
|
||||
if (snapshot is not null)
|
||||
{
|
||||
return snapshot.CornerRadiusTokens.Lg.TopLeft;
|
||||
}
|
||||
|
||||
return _appearanceThemeService.GetCurrent().CornerRadiusTokens.Lg.TopLeft;
|
||||
}
|
||||
|
||||
private static void SetButtonContentSpacing(Button? button, double spacing)
|
||||
{
|
||||
if (button?.Content is StackPanel contentPanel)
|
||||
|
||||
@@ -156,7 +156,7 @@ public sealed class PluginLoader
|
||||
var pluginType = ResolvePluginType(assembly);
|
||||
plugin = CreatePluginInstance(pluginType);
|
||||
AppLogger.Info("PluginLoader", $"Plugin instance created. PluginId='{manifest.Id}'; PluginType='{pluginType.FullName}'.");
|
||||
runtimeContext = CreateRuntimeContext(manifest, pluginDirectory, dataDirectory, properties);
|
||||
runtimeContext = CreateRuntimeContext(manifest, pluginDirectory, dataDirectory, properties, services);
|
||||
var serviceCollection = CreateServiceCollection(runtimeContext, services);
|
||||
var hostBuilderContext = CreateHostBuilderContext(runtimeContext);
|
||||
|
||||
@@ -297,13 +297,15 @@ public sealed class PluginLoader
|
||||
PluginManifest manifest,
|
||||
string pluginDirectory,
|
||||
string dataDirectory,
|
||||
IReadOnlyDictionary<string, object?>? properties)
|
||||
IReadOnlyDictionary<string, object?>? properties,
|
||||
IServiceProvider? hostServices)
|
||||
{
|
||||
return new PluginRuntimeContext(
|
||||
manifest,
|
||||
pluginDirectory,
|
||||
dataDirectory,
|
||||
CreateReadOnlyProperties(properties));
|
||||
CreateReadOnlyProperties(properties),
|
||||
BuildAppearanceSnapshot(hostServices));
|
||||
}
|
||||
|
||||
private ServiceCollection CreateServiceCollection(
|
||||
@@ -313,6 +315,7 @@ public sealed class PluginLoader
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton(runtimeContext);
|
||||
services.AddSingleton<IPluginRuntimeContext>(runtimeContext);
|
||||
services.AddSingleton<IPluginAppearanceContext>(runtimeContext.Appearance);
|
||||
services.AddSingleton(runtimeContext.Manifest);
|
||||
services.AddSingleton<IReadOnlyDictionary<string, object?>>(runtimeContext.Properties);
|
||||
services.AddSingleton<IPluginMessageBus, PluginMessageBus>();
|
||||
@@ -332,6 +335,33 @@ public sealed class PluginLoader
|
||||
return services;
|
||||
}
|
||||
|
||||
private static PluginAppearanceSnapshot BuildAppearanceSnapshot(IServiceProvider? hostServices)
|
||||
{
|
||||
var defaultSnapshot = new PluginAppearanceSnapshot(
|
||||
GlobalCornerRadiusScale: 1d,
|
||||
CornerRadiusTokens: new PluginCornerRadiusTokens(6, 10, 14, 18, 24, 30, 36),
|
||||
ThemeVariant: "Unknown");
|
||||
|
||||
if (hostServices?.GetService(typeof(IAppearanceThemeService)) is not IAppearanceThemeService appearanceThemeService)
|
||||
{
|
||||
return defaultSnapshot;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var hostSnapshot = appearanceThemeService.GetCurrent();
|
||||
return new PluginAppearanceSnapshot(
|
||||
GlobalCornerRadiusScale: Math.Max(0d, hostSnapshot.GlobalCornerRadiusScale),
|
||||
CornerRadiusTokens: PluginCornerRadiusTokens.FromShared(hostSnapshot.CornerRadiusTokens),
|
||||
ThemeVariant: hostSnapshot.IsNightMode ? "Dark" : "Light");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AppLogger.Warn("PluginLoader", "Failed to resolve host appearance snapshot for plugin runtime context.", ex);
|
||||
return defaultSnapshot;
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterHostService<TService>(IServiceCollection services, IServiceProvider? hostServices)
|
||||
where TService : class
|
||||
{
|
||||
@@ -730,12 +760,14 @@ public sealed class PluginLoader
|
||||
PluginManifest manifest,
|
||||
string pluginDirectory,
|
||||
string dataDirectory,
|
||||
IReadOnlyDictionary<string, object?> properties)
|
||||
IReadOnlyDictionary<string, object?> properties,
|
||||
PluginAppearanceSnapshot appearanceSnapshot)
|
||||
{
|
||||
Manifest = manifest;
|
||||
PluginDirectory = pluginDirectory;
|
||||
DataDirectory = dataDirectory;
|
||||
Properties = properties;
|
||||
Appearance = new PluginAppearanceContext(appearanceSnapshot);
|
||||
Services = NullServiceProvider.Instance;
|
||||
}
|
||||
|
||||
@@ -749,6 +781,8 @@ public sealed class PluginLoader
|
||||
|
||||
public IReadOnlyDictionary<string, object?> Properties { get; }
|
||||
|
||||
public IPluginAppearanceContext Appearance { get; }
|
||||
|
||||
public T? GetService<T>()
|
||||
{
|
||||
return (T?)Services.GetService(typeof(T));
|
||||
|
||||
@@ -90,16 +90,30 @@ internal static class AirAppMarketDefaults
|
||||
private static string? TryResolveWorkspacePath(string repositoryName, string relativePath)
|
||||
{
|
||||
var current = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
while (current is not null)
|
||||
while (current is not null && current.Exists)
|
||||
{
|
||||
var candidate = Path.Combine(current.FullName, repositoryName);
|
||||
if (Directory.Exists(candidate))
|
||||
var solutionPath = Path.Combine(current.FullName, "LanMountainDesktop.slnx");
|
||||
if (File.Exists(solutionPath))
|
||||
{
|
||||
var candidatePath = Path.GetFullPath(Path.Combine(candidate, relativePath));
|
||||
var workspaceRoot = current.Parent;
|
||||
if (workspaceRoot is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var candidateRepositoryPath = Path.Combine(workspaceRoot.FullName, repositoryName);
|
||||
if (!Directory.Exists(candidateRepositoryPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var candidatePath = Path.GetFullPath(Path.Combine(candidateRepositoryPath, relativePath));
|
||||
if (File.Exists(candidatePath))
|
||||
{
|
||||
return candidatePath;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
current = current.Parent;
|
||||
|
||||
@@ -1,53 +1,26 @@
|
||||
# 宿主侧插件运行时 / Host Plugin Runtime
|
||||
|
||||
## 中文
|
||||
|
||||
本目录保存阑山桌面宿主侧插件运行时实现。
|
||||
|
||||
### 主要职责
|
||||
|
||||
- 发现、安装和替换 `.laapp` 插件包
|
||||
- 加载插件程序集和共享契约
|
||||
- 接入插件设置页、桌面组件与市场界面
|
||||
- 为 `3.0.0` API 基线插件构建插件作用域的 `IServiceCollection` / `ServiceProvider`
|
||||
- 在激活前解析共享契约缓存,并暴露显式插件导出
|
||||
|
||||
### 与 LanAirApp 的分工
|
||||
|
||||
- `LanAirApp` 负责官方市场索引、开发文档、校验工具和镜像样例
|
||||
- 本目录负责宿主运行时发现、安装、加载和界面接入
|
||||
- 权威示例插件是独立仓库 `LanMountainDesktop.SamplePlugin`,`LanAirApp` 中的样例目录只是镜像模板
|
||||
|
||||
### 市场安装顺序
|
||||
|
||||
1. 宿主读取官方 `LanAirApp/airappmarket/index.json`
|
||||
2. 若条目同时包含 `releaseTag` 与 `releaseAssetName`,优先解析 GitHub Release 资产
|
||||
3. 若 Release 解析失败,则回退到仓库根目录 `.laapp`
|
||||
4. 插件详情始终读取插件仓库根目录 `README.md`
|
||||
5. 市场安装为暂存安装,重启后生效
|
||||
|
||||
## English
|
||||
# Host Plugin Runtime
|
||||
|
||||
This directory contains the host-side plugin runtime for LanMountainDesktop.
|
||||
|
||||
### Responsibilities
|
||||
## Responsibilities
|
||||
|
||||
- discover, install, and replace `.laapp` packages
|
||||
- load plugin assemblies and shared contracts
|
||||
- integrate plugin settings pages, desktop components, and market UI
|
||||
- build a plugin-scoped `IServiceCollection` / `ServiceProvider` for API `3.0.0` plugins
|
||||
- resolve shared contract caches before activation and expose explicit plugin exports
|
||||
- Discover, install, replace, and stage `.laapp` plugin packages
|
||||
- Load plugin assemblies and shared contracts
|
||||
- Integrate plugin settings sections, desktop components, and market UI
|
||||
- Build plugin-scoped `IServiceCollection` / `ServiceProvider` for API `4.x` plugins
|
||||
- Resolve shared contracts before activation and expose explicit plugin exports
|
||||
|
||||
### Relationship with LanAirApp
|
||||
## Relationship with LanAirApp
|
||||
|
||||
- `LanAirApp` owns the official market index, developer docs, validation tools, and mirrored sample templates
|
||||
- this directory owns host-side discovery, installation, loading, and UI integration
|
||||
- the authoritative sample plugin lives in the standalone `LanMountainDesktop.SamplePlugin` repository; the `LanAirApp` sample directory is only a mirror/template copy
|
||||
- `LanAirApp` is a standalone repository and owns market metadata plus developer ecosystem materials
|
||||
- This host runtime only consumes market metadata and plugin packages
|
||||
- The host no longer maintains an embedded `LanAirApp/` mirror inside this repository
|
||||
- Workspace debugging resolves market files from sibling path `..\\LanAirApp\\...`
|
||||
|
||||
### Market install order
|
||||
## Market Install Flow
|
||||
|
||||
1. The host reads the official `LanAirApp/airappmarket/index.json`
|
||||
2. If an entry contains both `releaseTag` and `releaseAssetName`, the host first resolves the exact GitHub Release asset
|
||||
3. If Release resolution fails, the host falls back to the repository-root `.laapp`
|
||||
4. Plugin details always come from the plugin repository root `README.md`
|
||||
5. Market installs are staged and take effect after restart
|
||||
1. Host reads the official market index
|
||||
2. If both `releaseTag` and `releaseAssetName` are present, host resolves the exact GitHub Release asset first
|
||||
3. If release resolution fails, host falls back to repository-root `.laapp`
|
||||
4. Plugin detail text is read from plugin repository root `README.md`
|
||||
5. Installation is staged and becomes effective after restart
|
||||
|
||||
Reference in New Issue
Block a user