using Avalonia.Controls; using Microsoft.Extensions.DependencyInjection; namespace LanMountainDesktop.PluginSdk; public static class PluginServiceCollectionExtensions { public static IServiceCollection AddPluginSettingsSection( this IServiceCollection services, string id, string titleLocalizationKey, Action configure, string? descriptionLocalizationKey = null, string iconKey = "PuzzlePiece", int sortOrder = 0) { ArgumentNullException.ThrowIfNull(services); ArgumentNullException.ThrowIfNull(configure); var builder = new PluginSettingsSectionBuilder( id, titleLocalizationKey, descriptionLocalizationKey, iconKey, sortOrder); configure(builder); services.AddSingleton(builder.Build()); return services; } public static IServiceCollection AddPluginDesktopComponent( this IServiceCollection services, string componentId, string displayName, string iconKey = "PuzzlePiece", string category = "Plugins", int minWidthCells = 2, int minHeightCells = 2, bool allowDesktopPlacement = true, bool allowStatusBarPlacement = false, PluginDesktopComponentResizeMode resizeMode = PluginDesktopComponentResizeMode.Proportional, string? displayNameLocalizationKey = null, Func? cornerRadiusResolver = null) where TControl : Control { ArgumentNullException.ThrowIfNull(services); services.AddSingleton(new PluginDesktopComponentRegistration( componentId, displayName, (provider, context) => ActivatorUtilities.CreateInstance(provider, context), iconKey, category, minWidthCells, minHeightCells, allowDesktopPlacement, allowStatusBarPlacement, resizeMode, displayNameLocalizationKey, cornerRadiusResolver)); return services; } public static IServiceCollection AddPluginExport(this IServiceCollection services) where TContract : class where TImplementation : class, TContract { ArgumentNullException.ThrowIfNull(services); EnsureSingletonRegistration(services); if (!services.Any(descriptor => descriptor.ServiceType == typeof(PluginServiceExportRegistration) && descriptor.ImplementationInstance is PluginServiceExportRegistration existing && existing.ContractType == typeof(TContract) && existing.ImplementationType == typeof(TImplementation))) { services.AddSingleton(new PluginServiceExportRegistration(typeof(TContract), typeof(TImplementation))); } return services; } private static void EnsureSingletonRegistration(IServiceCollection services) where TContract : class where TImplementation : class, TContract { var contractDescriptor = services.LastOrDefault(descriptor => descriptor.ServiceType == typeof(TContract)); if (contractDescriptor is null) { services.AddSingleton(); return; } if (contractDescriptor.Lifetime != ServiceLifetime.Singleton) { throw new InvalidOperationException( $"Exported contract '{typeof(TContract).FullName}' must be registered as Singleton."); } } }