using System; using System.Collections.Generic; using System.Linq; using Avalonia.Controls; using LanMontainDesktop.ComponentSystem; using LanMontainDesktop.Services; namespace LanMontainDesktop.Views.Components; public sealed record DesktopComponentRuntimeRegistration( string ComponentId, string DisplayNameLocalizationKey, Func ControlFactory, Func? CornerRadiusResolver = null); public sealed class DesktopComponentRuntimeDescriptor { private static readonly Func DefaultCornerRadiusResolver = cellSize => Math.Clamp(cellSize * 0.22, 8, 18); private readonly Func _controlFactory; private readonly Func _cornerRadiusResolver; internal DesktopComponentRuntimeDescriptor( DesktopComponentDefinition definition, string displayNameLocalizationKey, Func controlFactory, Func? cornerRadiusResolver) { Definition = definition; DisplayNameLocalizationKey = displayNameLocalizationKey; _controlFactory = controlFactory; _cornerRadiusResolver = cornerRadiusResolver ?? DefaultCornerRadiusResolver; } public DesktopComponentDefinition Definition { get; } public string DisplayNameLocalizationKey { get; } public Control CreateControl(double cellSize, TimeZoneService timeZoneService, IWeatherInfoService weatherInfoService) { var control = _controlFactory(); if (control is IDesktopComponentWidget sizedComponent) { sizedComponent.ApplyCellSize(cellSize); } if (control is ITimeZoneAwareComponentWidget timeZoneAwareComponent) { timeZoneAwareComponent.SetTimeZoneService(timeZoneService); } if (control is IWeatherInfoAwareComponentWidget weatherInfoAwareComponent) { weatherInfoAwareComponent.SetWeatherInfoService(weatherInfoService); } return control; } public double ResolveCornerRadius(double cellSize) { return _cornerRadiusResolver(Math.Max(1, cellSize)); } } public sealed class DesktopComponentRuntimeRegistry { private readonly Dictionary _descriptors; public DesktopComponentRuntimeRegistry( ComponentRegistry componentRegistry, IEnumerable registrations) { var registrationMap = registrations .Where(r => !string.IsNullOrWhiteSpace(r.ComponentId) && r.ControlFactory is not null) .GroupBy(r => r.ComponentId.Trim(), StringComparer.OrdinalIgnoreCase) .ToDictionary(g => g.Key, g => g.Last(), StringComparer.OrdinalIgnoreCase); _descriptors = componentRegistry .GetAll() .Where(definition => registrationMap.ContainsKey(definition.Id)) .ToDictionary( definition => definition.Id, definition => { var registration = registrationMap[definition.Id]; return new DesktopComponentRuntimeDescriptor( definition, registration.DisplayNameLocalizationKey, registration.ControlFactory, registration.CornerRadiusResolver); }, StringComparer.OrdinalIgnoreCase); } public static DesktopComponentRuntimeRegistry CreateDefault(ComponentRegistry componentRegistry) { return new DesktopComponentRuntimeRegistry( componentRegistry, new[] { new DesktopComponentRuntimeRegistration( BuiltInComponentIds.Date, "component.date", () => new DateWidget(), _ => 16), new DesktopComponentRuntimeRegistration( BuiltInComponentIds.MonthCalendar, "component.month_calendar", () => new MonthCalendarWidget(), cellSize => Math.Clamp(cellSize * 0.26, 10, 22)), new DesktopComponentRuntimeRegistration( BuiltInComponentIds.LunarCalendar, "component.lunar_calendar", () => new LunarCalendarWidget(), cellSize => Math.Clamp(cellSize * 0.30, 12, 26)), new DesktopComponentRuntimeRegistration( BuiltInComponentIds.DesktopClock, "component.desktop_clock", () => new AnalogClockWidget(), cellSize => Math.Clamp(cellSize * 0.30, 12, 28)), new DesktopComponentRuntimeRegistration( BuiltInComponentIds.DesktopWeatherClock, "component.weather_clock", () => new WeatherClockWidget(), cellSize => Math.Clamp(cellSize * 0.34, 14, 30)), new DesktopComponentRuntimeRegistration( BuiltInComponentIds.DesktopTimer, "component.desktop_timer", () => new TimerWidget(), cellSize => Math.Clamp(cellSize * 0.30, 12, 28)), new DesktopComponentRuntimeRegistration( BuiltInComponentIds.DesktopWeather, "component.desktop_weather", () => new WeatherWidget(), cellSize => Math.Clamp(cellSize * 0.45, 24, 44)), new DesktopComponentRuntimeRegistration( BuiltInComponentIds.DesktopHourlyWeather, "component.hourly_weather", () => new HourlyWeatherWidget(), cellSize => Math.Clamp(cellSize * 0.45, 24, 44)), new DesktopComponentRuntimeRegistration( BuiltInComponentIds.DesktopMultiDayWeather, "component.multiday_weather", () => new MultiDayWeatherWidget(), cellSize => Math.Clamp(cellSize * 0.45, 24, 44)), new DesktopComponentRuntimeRegistration( BuiltInComponentIds.DesktopWhiteboard, "component.whiteboard", () => new WhiteboardWidget(), cellSize => Math.Clamp(cellSize * 0.24, 10, 24)), new DesktopComponentRuntimeRegistration( BuiltInComponentIds.DesktopBlackboardLandscape, "component.blackboard_landscape", () => new WhiteboardWidget(baseWidthCells: 4), cellSize => Math.Clamp(cellSize * 0.24, 10, 24)), new DesktopComponentRuntimeRegistration( BuiltInComponentIds.HolidayCalendar, "component.holiday_calendar", () => new HolidayCalendarWidget(), cellSize => Math.Clamp(cellSize * 0.32, 12, 28)) }); } public bool TryGetDescriptor(string componentId, out DesktopComponentRuntimeDescriptor descriptor) { return _descriptors.TryGetValue(componentId, out descriptor!); } public IReadOnlyList GetDesktopComponents() { return _descriptors.Values .Where(descriptor => descriptor.Definition.AllowDesktopPlacement) .OrderBy(descriptor => descriptor.Definition.Category, StringComparer.OrdinalIgnoreCase) .ThenBy(descriptor => descriptor.Definition.DisplayName, StringComparer.OrdinalIgnoreCase) .ToList(); } }