diff --git a/Hyperbar.Windows.Contextual/ContextualWidgetProvider.cs b/Hyperbar.Windows.Contextual/ContextualWidgetProvider.cs index dc33a26..bc8aa81 100644 --- a/Hyperbar.Windows.Contextual/ContextualWidgetProvider.cs +++ b/Hyperbar.Windows.Contextual/ContextualWidgetProvider.cs @@ -1,12 +1,13 @@ using Hyperbar.Extensions; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; namespace Hyperbar.Widget.Contextual; public class ContextualWidgetProvider : IWidgetProvider { - public void Create(IServiceCollection services) => services - .AddConfiguration() + public void Create(HostBuilderContext comtext, IServiceCollection services) => services + .AddConfiguration(comtext.Configuration.GetSection(nameof(ContextualWidgetConfiguration))) .AddWidgetTemplate(); } \ No newline at end of file diff --git a/Hyperbar.Windows.Primary/Hyperbar.Widget.Primary.csproj b/Hyperbar.Windows.Primary/Hyperbar.Widget.Primary.csproj index 4a8f052..f3e9e72 100644 --- a/Hyperbar.Windows.Primary/Hyperbar.Widget.Primary.csproj +++ b/Hyperbar.Windows.Primary/Hyperbar.Widget.Primary.csproj @@ -7,6 +7,7 @@ + diff --git a/Hyperbar.Windows.Primary/PrimaryWidgetConfiguration.cs b/Hyperbar.Windows.Primary/PrimaryWidgetConfiguration.cs index 44a1b03..59057c6 100644 --- a/Hyperbar.Windows.Primary/PrimaryWidgetConfiguration.cs +++ b/Hyperbar.Windows.Primary/PrimaryWidgetConfiguration.cs @@ -1,6 +1,10 @@ namespace Hyperbar.Windows.Primary; public class PrimaryWidgetConfiguration : - List + List { + public static PrimaryWidgetConfiguration Defaults => new() + { + new KeyAcceleratorCommandConfiguration { Icon = "Test", Key = "Test", Modifiers = ["Test", "Test"] } + }; } \ No newline at end of file diff --git a/Hyperbar.Windows.Primary/PrimaryWidgetProvider.cs b/Hyperbar.Windows.Primary/PrimaryWidgetProvider.cs index 3fae557..e786666 100644 --- a/Hyperbar.Windows.Primary/PrimaryWidgetProvider.cs +++ b/Hyperbar.Windows.Primary/PrimaryWidgetProvider.cs @@ -1,13 +1,16 @@ using Hyperbar.Extensions; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; namespace Hyperbar.Windows.Primary; public class PrimaryWidgetProvider : IWidgetProvider { - public void Create(IServiceCollection services) => services.AddConfiguration() - .AddTransient() - .AddTransient(provider => provider.GetRequiredService().Create()) + public void Create(HostBuilderContext comtext, IServiceCollection services) => + services.AddConfiguration(comtext.Configuration.GetSection(nameof(PrimaryWidgetConfiguration)), + PrimaryWidgetConfiguration.Defaults) + .AddTransient() + .AddTransient(provider => provider.GetRequiredService().Create()) .AddWidgetTemplate(); } \ No newline at end of file diff --git a/Hyperbar.Windows.Primary/WidgetComponentMappinglFactory.cs b/Hyperbar.Windows.Primary/WidgetComponentMappinglFactory.cs index 669d5e1..fc91b99 100644 --- a/Hyperbar.Windows.Primary/WidgetComponentMappinglFactory.cs +++ b/Hyperbar.Windows.Primary/WidgetComponentMappinglFactory.cs @@ -1,12 +1,12 @@ namespace Hyperbar.Windows.Primary; -public class WidgetComponentMappinglFactory : - MappingFactory> +public class WidgetComponentMappingFactory : + IMappingFactory> { private readonly PrimaryWidgetConfiguration configuration; private readonly IServiceFactory service; - public WidgetComponentMappinglFactory(PrimaryWidgetConfiguration configuration, + public WidgetComponentMappingFactory(PrimaryWidgetConfiguration configuration, IServiceFactory service) { this.configuration = configuration; diff --git a/Hyperbar.Windows/App.xaml.cs b/Hyperbar.Windows/App.xaml.cs index 2a4bb3e..3134667 100644 --- a/Hyperbar.Windows/App.xaml.cs +++ b/Hyperbar.Windows/App.xaml.cs @@ -5,6 +5,7 @@ using Hyperbar.Windows.Primary; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; using Microsoft.UI.Xaml; namespace Hyperbar.Windows; @@ -23,7 +24,7 @@ public partial class App : .ConfigureAppConfiguration(config => { config.SetBasePath(AppContext.BaseDirectory); - config.AddJsonFile("Settings.json", true); + config.AddJsonFile("Settings.json", true, true); config.Build(); }) diff --git a/Hyperbar.Windows/Lifecycles/IServiceCollectionExtensions.cs b/Hyperbar.Windows/Lifecycles/IServiceCollectionExtensions.cs index ccc706a..859cb6c 100644 --- a/Hyperbar.Windows/Lifecycles/IServiceCollectionExtensions.cs +++ b/Hyperbar.Windows/Lifecycles/IServiceCollectionExtensions.cs @@ -1,7 +1,10 @@ using Hyperbar.Extensions; using Hyperbar.Windows.Interop; +using Hyperbar.Windows.Primary; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; namespace Hyperbar.Windows { @@ -13,8 +16,18 @@ namespace Hyperbar.Windows { TWidgetProvider builder = new(); IHost? host = new HostBuilder() - .ConfigureServices(isolatedServices => + .UseContentRoot(AppContext.BaseDirectory) + .ConfigureAppConfiguration(config => { + config.SetBasePath(AppContext.BaseDirectory); + config.AddJsonFile("Settings.json", true, true); + + config.Build(); + }) + .ConfigureServices((context, isolatedServices) => + { + isolatedServices.AddHostedService(); + isolatedServices.AddSingleton(provider => new ServiceFactory((type, parameters) => ActivatorUtilities.CreateInstance(provider, type, parameters!))); @@ -29,10 +42,15 @@ namespace Hyperbar.Windows isolatedServices.AddTransient(); isolatedServices.AddTransient(); - builder.Create(isolatedServices); + builder.Create(context, isolatedServices); }).Build(); + services.AddTransient(provider => new WidgetContext(host.Services)); + host.Start(); + + var d = host.Services.GetService>(); + return services; } } diff --git a/Hyperbar/Configuration/ConfigurationInitializer.cs b/Hyperbar/Configuration/ConfigurationInitializer.cs new file mode 100644 index 0000000..d4f166d --- /dev/null +++ b/Hyperbar/Configuration/ConfigurationInitializer.cs @@ -0,0 +1,13 @@ +namespace Hyperbar; + +public class ConfigurationInitializer(DefaultConfiguration defaults, + IConfigurationWriter writer) : IInitializer + where TConfiguration : + class, new() +{ + public Task InitializeAsync() + { + writer.Write(defaults.Configuration); + return Task.CompletedTask; + } +} diff --git a/Hyperbar/Configuration/ConfigurationWriter.cs b/Hyperbar/Configuration/ConfigurationWriter.cs index 0495761..39d8ffe 100644 --- a/Hyperbar/Configuration/ConfigurationWriter.cs +++ b/Hyperbar/Configuration/ConfigurationWriter.cs @@ -11,7 +11,7 @@ public class ConfigurationWriter(string path, where TConfiguration : class, new() { - internal static Func DefaultSerializerOptions = new(() => + private static readonly Func defaultSerializerOptions = new(() => { return new JsonSerializerOptions { @@ -21,8 +21,6 @@ public class ConfigurationWriter(string path, }; }); - private readonly JsonSerializerOptions? serializerOptions = serializerOptions ??= DefaultSerializerOptions(); - public void Write(Action updateDelegate) { if ((TryGet(out TConfiguration? value) ? value : new TConfiguration()) is TConfiguration updatedValue) @@ -57,7 +55,7 @@ public class ConfigurationWriter(string path, writer.WriteStartObject(); bool isWritten = false; - JsonDocument optionsElement = JsonDocument.Parse(JsonSerializer.SerializeToUtf8Bytes(value, serializerOptions)); + JsonDocument optionsElement = JsonDocument.Parse(JsonSerializer.SerializeToUtf8Bytes(value, serializerOptions ?? defaultSerializerOptions())); foreach (JsonProperty element in jsonDocument.RootElement.EnumerateObject()) { @@ -91,7 +89,7 @@ public class ConfigurationWriter(string path, using JsonDocument jsonDocument = JsonDocument.Parse(jsonContent); if (jsonDocument.RootElement.TryGetProperty(section, out JsonElement sectionValue)) { - value = JsonSerializer.Deserialize(sectionValue.ToString(), serializerOptions); + value = JsonSerializer.Deserialize(sectionValue.ToString(), serializerOptions ?? defaultSerializerOptions()); return true; } } diff --git a/Hyperbar/Configuration/DefaultConfiguration.cs b/Hyperbar/Configuration/DefaultConfiguration.cs new file mode 100644 index 0000000..f35f8b1 --- /dev/null +++ b/Hyperbar/Configuration/DefaultConfiguration.cs @@ -0,0 +1,6 @@ +namespace Hyperbar; + +public class DefaultConfiguration(TConfiguration configuration) +{ + public TConfiguration Configuration => configuration; +} diff --git a/Hyperbar/Extensions/IServiceCollectionExtensions.cs b/Hyperbar/Extensions/IServiceCollectionExtensions.cs index ec7e909..4e308b5 100644 --- a/Hyperbar/Extensions/IServiceCollectionExtensions.cs +++ b/Hyperbar/Extensions/IServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Hosting; @@ -85,27 +86,30 @@ public static class IServiceCollectionExtensions return serviceCollection; } - public static IServiceCollection AddConfiguration(this IServiceCollection services, - string path = "Settings.json") + IConfiguration configuration, + TConfiguration? defaults = null) where TConfiguration : class, new() { - return services.AddConfiguration(typeof(TConfiguration).Name, path); + return services.AddConfiguration(configuration, typeof(TConfiguration).Name, "Settings.json", defaults); } public static IServiceCollection AddConfiguration(this IServiceCollection services, + IConfiguration configuration, string section, string path = "Settings.json", + TConfiguration? defaults = null, Action? serializerDelegate = null) where TConfiguration : class, new() { - services.AddOptions(); + services.Configure(configuration); services.AddSingleton>(new ConfigureNamedOptions("", args => { })); services.AddTransient(provider => provider.GetService>()!.CurrentValue); - services.AddTransient>(provider => + + services.AddSingleton>(provider => { string? jsonFilePath = null; if (provider.GetService() is IHostEnvironment hostEnvironment) @@ -118,16 +122,22 @@ public static class IServiceCollectionExtensions jsonFilePath ??= Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path); - JsonSerializerOptions? defaultSerializerOptions = null; + JsonSerializerOptions? defaultSerializer = null; if (serializerDelegate is not null) { - defaultSerializerOptions = new JsonSerializerOptions(); - serializerDelegate.Invoke(defaultSerializerOptions); + defaultSerializer = new JsonSerializerOptions(); + serializerDelegate.Invoke(defaultSerializer); } - return new ConfigurationWriter(jsonFilePath, section, defaultSerializerOptions); + return new ConfigurationWriter(jsonFilePath, section, defaultSerializer); }); + if (defaults is not null) + { + services.AddTransient(provider => new DefaultConfiguration(defaults)); + services.AddTransient>(); + } + services.AddTransient, WritableConfiguration>(); return services; } diff --git a/Hyperbar/Views/MappingFactory.cs b/Hyperbar/Factories/IMappingFactory.cs similarity index 50% rename from Hyperbar/Views/MappingFactory.cs rename to Hyperbar/Factories/IMappingFactory.cs index 287a42c..93567e7 100644 --- a/Hyperbar/Views/MappingFactory.cs +++ b/Hyperbar/Factories/IMappingFactory.cs @@ -1,6 +1,6 @@ namespace Hyperbar; -public interface MappingFactory +public interface IMappingFactory { TTo Create(); } diff --git a/Hyperbar/Widgets/IWidgetProvider.cs b/Hyperbar/Widgets/IWidgetProvider.cs index a8338aa..3608add 100644 --- a/Hyperbar/Widgets/IWidgetProvider.cs +++ b/Hyperbar/Widgets/IWidgetProvider.cs @@ -1,8 +1,9 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; namespace Hyperbar; public interface IWidgetProvider { - void Create(IServiceCollection services); + void Create(HostBuilderContext context, IServiceCollection services); } \ No newline at end of file diff --git a/Hyperbar/Widgets/WidgetService.cs b/Hyperbar/Widgets/WidgetService.cs new file mode 100644 index 0000000..c4a662b --- /dev/null +++ b/Hyperbar/Widgets/WidgetService.cs @@ -0,0 +1,17 @@ +using Microsoft.Extensions.Hosting; + +namespace Hyperbar; + +public class WidgetService(IEnumerable initializers) : + IHostedService +{ + public async Task StartAsync(CancellationToken cancellationToken) + { + foreach (IInitializer initializer in initializers) + { + await initializer.InitializeAsync(); + } + } + + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; +} \ No newline at end of file