From 45070dc5608b0a82548842df3e95df31a8bc5e5f Mon Sep 17 00:00:00 2001 From: TheXamlGuy Date: Sat, 20 Jan 2024 21:58:57 +0000 Subject: [PATCH] more refoctoring work --- .../ContextualWidget.cs | 16 +++ .../ContextualWidgetBuilder.cs | 16 --- .../ContextualWidgetConfiguration.cs | 3 +- .../Hyperbar.Windows.Controls.csproj | 2 - .../Lifecycles/MediaControllerWidget.cs | 29 ++++ .../MediaControllerWidgetBuilder.cs | 28 ---- .../MediaControllerWidgetConfiguration.cs | 7 + .../Views/MediaButtonViewModel.cs | 2 +- .../Views/MediaInformationViewModel.cs | 4 +- Hyperbar.Windows.Primary/PrimaryWidget.cs | 24 ++++ .../PrimaryWidgetConfiguration.cs | 2 +- .../PrimaryWidgetConfigurationBuilder.cs | 23 ---- .../PrimaryWidgetViewModel.cs | 2 +- ...erator.cs => WidgetComponentEnumerator.cs} | 4 +- ...elFactory.cs => WidgetComponentFactory.cs} | 2 +- ...Provider.cs => WidgetComponentProvider.cs} | 2 +- Hyperbar.Windows/App.xaml.cs | 65 +++++---- Hyperbar.Windows/Hyperbar.Windows.csproj | 34 ++--- .../Lifecycles/ConfigurationChangedHandler.cs | 2 +- .../IServiceCollectionExtensions.cs | 15 +-- .../Configuration/ConfigurationInitializer.cs | 8 +- .../Configuration/ConfigurationMonitor.cs | 25 ++-- Hyperbar/Configuration/ConfigurationReader.cs | 40 ++---- Hyperbar/Configuration/ConfigurationSource.cs | 127 +++++++++++++++++- Hyperbar/Configuration/ConfigurationWriter.cs | 86 +----------- .../Configuration/IConfigurationReader.cs | 2 + .../Configuration/IConfigurationSource.cs | 8 +- Hyperbar/Extensions/IHostBuilderExtensions.cs | 19 +++ .../IServiceCollectionExtensions.cs | 92 ++++++------- Hyperbar/Lifecycles/Cache.cs | 4 +- ...IViewModelEnumerator.cs => IEnumerator.cs} | 2 +- ...elInitialization.cs => IInitialization.cs} | 2 +- .../Views/ObservableCollectionViewModel.cs | 6 +- Hyperbar/Widgets/IWidget.cs | 6 +- Hyperbar/Widgets/IWidgetAssemblyLoader.cs | 6 + Hyperbar/Widgets/IWidgetBuilder.cs | 4 +- Hyperbar/Widgets/IWidgetBuilderExtensions.cs | 35 +++++ Hyperbar/Widgets/Widget.cs | 11 -- Hyperbar/Widgets/WidgetBuilder.cs | 22 +++ Hyperbar/Widgets/WidgetConfiguration.cs | 19 +-- Hyperbar/Widgets/WidgetContext.cs | 21 ++- Hyperbar/Widgets/WidgetEnumerator.cs | 11 ++ 42 files changed, 477 insertions(+), 361 deletions(-) create mode 100644 Hyperbar.Windows.Contextual/ContextualWidget.cs delete mode 100644 Hyperbar.Windows.Contextual/ContextualWidgetBuilder.cs create mode 100644 Hyperbar.Windows.MediaController/Lifecycles/MediaControllerWidget.cs delete mode 100644 Hyperbar.Windows.MediaController/Lifecycles/MediaControllerWidgetBuilder.cs create mode 100644 Hyperbar.Windows.MediaController/Lifecycles/MediaControllerWidgetConfiguration.cs create mode 100644 Hyperbar.Windows.Primary/PrimaryWidget.cs delete mode 100644 Hyperbar.Windows.Primary/PrimaryWidgetConfigurationBuilder.cs rename Hyperbar.Windows.Primary/{WidgetComponentViewModelEnumerator.cs => WidgetComponentEnumerator.cs} (88%) rename Hyperbar.Windows.Primary/{WidgetComponentViewModelFactory.cs => WidgetComponentFactory.cs} (98%) rename Hyperbar.Windows.Primary/{WidgetComponentViewModelProvider.cs => WidgetComponentProvider.cs} (79%) create mode 100644 Hyperbar/Extensions/IHostBuilderExtensions.cs rename Hyperbar/Views/{IViewModelEnumerator.cs => IEnumerator.cs} (57%) rename Hyperbar/Views/{IViewModelInitialization.cs => IInitialization.cs} (73%) create mode 100644 Hyperbar/Widgets/IWidgetAssemblyLoader.cs create mode 100644 Hyperbar/Widgets/IWidgetBuilderExtensions.cs delete mode 100644 Hyperbar/Widgets/Widget.cs create mode 100644 Hyperbar/Widgets/WidgetBuilder.cs create mode 100644 Hyperbar/Widgets/WidgetEnumerator.cs diff --git a/Hyperbar.Windows.Contextual/ContextualWidget.cs b/Hyperbar.Windows.Contextual/ContextualWidget.cs new file mode 100644 index 0000000..b281650 --- /dev/null +++ b/Hyperbar.Windows.Contextual/ContextualWidget.cs @@ -0,0 +1,16 @@ +namespace Hyperbar.Widget.Contextual; + +public class ContextualWidget : + IWidget +{ + public IWidgetBuilder Create() => + WidgetBuilder.Configure(args => + { + args.Id = Guid.Parse("d3030852-8d4a-4fbb-9aa5-96dff3dfa06c"); + args.Name = "Contextual commands"; + + }).ConfigureServices(args => + { + args.AddWidgetTemplate(); + }); +} \ No newline at end of file diff --git a/Hyperbar.Windows.Contextual/ContextualWidgetBuilder.cs b/Hyperbar.Windows.Contextual/ContextualWidgetBuilder.cs deleted file mode 100644 index 4589a32..0000000 --- a/Hyperbar.Windows.Contextual/ContextualWidgetBuilder.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace Hyperbar.Widget.Contextual; - -public class ContextualWidgetBuilder : - IWidgetBuilder -{ - public void Create(IServiceCollection services) => - WidgetBuilder.Config(services, config => - { - config.Id = Guid.Parse("d3030852-8d4a-4fbb-9aa5-96dff3dfa06c"); - config.Name = "Contextual commands"; - - services.AddWidgetTemplate(); - }); -} \ No newline at end of file diff --git a/Hyperbar.Windows.Contextual/ContextualWidgetConfiguration.cs b/Hyperbar.Windows.Contextual/ContextualWidgetConfiguration.cs index af29871..793e460 100644 --- a/Hyperbar.Windows.Contextual/ContextualWidgetConfiguration.cs +++ b/Hyperbar.Windows.Contextual/ContextualWidgetConfiguration.cs @@ -1,5 +1,6 @@ namespace Hyperbar.Widget.Contextual; -public class ContextualWidgetConfiguration +public class ContextualWidgetConfiguration : + WidgetConfiguration { } \ No newline at end of file diff --git a/Hyperbar.Windows.Controls/Hyperbar.Windows.Controls.csproj b/Hyperbar.Windows.Controls/Hyperbar.Windows.Controls.csproj index ef10394..adab486 100644 --- a/Hyperbar.Windows.Controls/Hyperbar.Windows.Controls.csproj +++ b/Hyperbar.Windows.Controls/Hyperbar.Windows.Controls.csproj @@ -11,8 +11,6 @@ - - diff --git a/Hyperbar.Windows.MediaController/Lifecycles/MediaControllerWidget.cs b/Hyperbar.Windows.MediaController/Lifecycles/MediaControllerWidget.cs new file mode 100644 index 0000000..2193dd8 --- /dev/null +++ b/Hyperbar.Windows.MediaController/Lifecycles/MediaControllerWidget.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.DependencyInjection; +using Windows.Media.Control; + +namespace Hyperbar.Windows.MediaController; + +public class MediaControllerWidget : + IWidget +{ + public IWidgetBuilder Create() => + WidgetBuilder.Configure(args => + { + args.Id = Guid.Parse("1667a800-ec5a-4d39-aa75-4f5ee95bb9f1"); + args.Name = "Media controller"; + }).ConfigureServices(args => + { + args.AddWidgetTemplate() + .AddSingleton() + .AddTransient, ServiceScopeFactory>() + .AddTransient, ServiceScopeProvider>() + .AddCache() + .AddTransient, MediaControllerFactory>() + .AddHandler() + .AddTransient, MediaControllerViewModelFactory>() + .AddCache() + .AddContentTemplate() + .AddContentTemplate() + .AddContentTemplate(); + }); +} \ No newline at end of file diff --git a/Hyperbar.Windows.MediaController/Lifecycles/MediaControllerWidgetBuilder.cs b/Hyperbar.Windows.MediaController/Lifecycles/MediaControllerWidgetBuilder.cs deleted file mode 100644 index b496279..0000000 --- a/Hyperbar.Windows.MediaController/Lifecycles/MediaControllerWidgetBuilder.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Windows.Media.Control; - -namespace Hyperbar.Windows.MediaController; - -public class MediaControllerWidgetBuilder : - IWidgetBuilder -{ - public void Create(IServiceCollection services) => - WidgetBuilder.Config(services, config => - { - config.Id = Guid.Parse("1667a800-ec5a-4d39-aa75-4f5ee95bb9f1"); - config.Name = "Media controller"; - - services.AddWidgetTemplate() - .AddSingleton() - .AddTransient, ServiceScopeFactory>() - .AddTransient, ServiceScopeProvider>() - .AddCache() - .AddTransient, MediaControllerFactory>() - .AddHandler() - .AddTransient, MediaControllerViewModelFactory>() - .AddCache() - .AddContentTemplate() - .AddContentTemplate() - .AddContentTemplate(); - }); -} \ No newline at end of file diff --git a/Hyperbar.Windows.MediaController/Lifecycles/MediaControllerWidgetConfiguration.cs b/Hyperbar.Windows.MediaController/Lifecycles/MediaControllerWidgetConfiguration.cs new file mode 100644 index 0000000..d25b286 --- /dev/null +++ b/Hyperbar.Windows.MediaController/Lifecycles/MediaControllerWidgetConfiguration.cs @@ -0,0 +1,7 @@ +namespace Hyperbar.Windows.MediaController; + +public class MediaControllerWidgetConfiguration : + WidgetConfiguration +{ + +} diff --git a/Hyperbar.Windows.MediaController/Views/MediaButtonViewModel.cs b/Hyperbar.Windows.MediaController/Views/MediaButtonViewModel.cs index 96c1f1f..aafbcbd 100644 --- a/Hyperbar.Windows.MediaController/Views/MediaButtonViewModel.cs +++ b/Hyperbar.Windows.MediaController/Views/MediaButtonViewModel.cs @@ -12,7 +12,7 @@ public class MediaButtonViewModel(IServiceFactory serviceFactory, string? icon = null, RelayCommand? command = null) : WidgetButtonViewModel(serviceFactory, mediator, disposer, templateFactory, guid, text, icon, command), - IViewModelInitialization + IInitialization { public ICommand Initialize => new AsyncRelayCommand(InitializeAsync); diff --git a/Hyperbar.Windows.MediaController/Views/MediaInformationViewModel.cs b/Hyperbar.Windows.MediaController/Views/MediaInformationViewModel.cs index cbab067..da0dec7 100644 --- a/Hyperbar.Windows.MediaController/Views/MediaInformationViewModel.cs +++ b/Hyperbar.Windows.MediaController/Views/MediaInformationViewModel.cs @@ -8,8 +8,8 @@ public partial class MediaInformationViewModel(IServiceFactory serviceFactory, IMediator mediator, IDisposer disposer, ITemplateFactory templateFactory) : - WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory), - IViewModelInitialization, + WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory), + IInitialization, INotificationHandler> { [ObservableProperty] diff --git a/Hyperbar.Windows.Primary/PrimaryWidget.cs b/Hyperbar.Windows.Primary/PrimaryWidget.cs new file mode 100644 index 0000000..7b564a4 --- /dev/null +++ b/Hyperbar.Windows.Primary/PrimaryWidget.cs @@ -0,0 +1,24 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Hyperbar.Windows.Primary; + +public class PrimaryWidget : + IWidget +{ + public IWidgetBuilder Create() => + WidgetBuilder.Configure(args => + { + args.Id = Guid.Parse("cfdfe07c-d9d6-4174-ae41-988ca24d2e10"); + args.Name = "Primary commands"; + + }).ConfigureServices(args => + { + args.AddCache<(Guid ParentId, Guid Id), PrimaryCommandConfiguration>() + .AddCache() + .AddTransient, WidgetComponentProvider>() + .AddTransient, WidgetComponentFactory>() + .AddTransient, WidgetComponentEnumerator>() + .AddWidgetTemplate() + .AddHandler(); + }); +} \ No newline at end of file diff --git a/Hyperbar.Windows.Primary/PrimaryWidgetConfiguration.cs b/Hyperbar.Windows.Primary/PrimaryWidgetConfiguration.cs index 9c8abef..a38afb7 100644 --- a/Hyperbar.Windows.Primary/PrimaryWidgetConfiguration.cs +++ b/Hyperbar.Windows.Primary/PrimaryWidgetConfiguration.cs @@ -1,6 +1,6 @@ namespace Hyperbar.Windows.Primary; -public class PrimaryWidgetConfiguration +public class PrimaryWidgetConfiguration : WidgetConfiguration { public List Commands { get; set; } = []; } \ No newline at end of file diff --git a/Hyperbar.Windows.Primary/PrimaryWidgetConfigurationBuilder.cs b/Hyperbar.Windows.Primary/PrimaryWidgetConfigurationBuilder.cs deleted file mode 100644 index cea5dc8..0000000 --- a/Hyperbar.Windows.Primary/PrimaryWidgetConfigurationBuilder.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace Hyperbar.Windows.Primary; - -public class PrimaryWidgetConfigurationBuilder : - IWidgetBuilder -{ - public void Create(IServiceCollection services) => - WidgetBuilder.Config(services, config => - { - config.Id = Guid.Parse("cfdfe07c-d9d6-4174-ae41-988ca24d2e10"); - config.Name = "Primary commands"; - - services.AddConfiguration() - .AddCache<(Guid ParentId, Guid Id), PrimaryCommandConfiguration>() - .AddCache() - .AddTransient, WidgetComponentViewModelProvider>() - .AddTransient, WidgetComponentViewModelFactory>() - .AddTransient, WidgetComponentViewModelEnumerator>() - .AddWidgetTemplate() - .AddHandler(); - }); -} \ No newline at end of file diff --git a/Hyperbar.Windows.Primary/PrimaryWidgetViewModel.cs b/Hyperbar.Windows.Primary/PrimaryWidgetViewModel.cs index d89fdc0..8113be3 100644 --- a/Hyperbar.Windows.Primary/PrimaryWidgetViewModel.cs +++ b/Hyperbar.Windows.Primary/PrimaryWidgetViewModel.cs @@ -5,7 +5,7 @@ public class PrimaryWidgetViewModel(ITemplateFactory templateFactory, IServiceFactory serviceFactory, IMediator mediator, IDisposer disposer, - IViewModelEnumerator enumerator) : + IEnumerator enumerator) : ObservableCollectionViewModel(serviceFactory, mediator, disposer, enumerator), IWidgetViewModel, ITemplatedViewModel diff --git a/Hyperbar.Windows.Primary/WidgetComponentViewModelEnumerator.cs b/Hyperbar.Windows.Primary/WidgetComponentEnumerator.cs similarity index 88% rename from Hyperbar.Windows.Primary/WidgetComponentViewModelEnumerator.cs rename to Hyperbar.Windows.Primary/WidgetComponentEnumerator.cs index 43baf50..35b45a8 100644 --- a/Hyperbar.Windows.Primary/WidgetComponentViewModelEnumerator.cs +++ b/Hyperbar.Windows.Primary/WidgetComponentEnumerator.cs @@ -1,9 +1,9 @@ namespace Hyperbar.Windows.Primary; -public class WidgetComponentViewModelEnumerator(PrimaryWidgetConfiguration configuration, +public class WidgetComponentEnumerator(PrimaryWidgetConfiguration configuration, IFactory factory, ICache<(Guid ParentId, Guid Id), PrimaryCommandConfiguration> cache) : - IViewModelEnumerator + IEnumerator { public IEnumerable Next() { diff --git a/Hyperbar.Windows.Primary/WidgetComponentViewModelFactory.cs b/Hyperbar.Windows.Primary/WidgetComponentFactory.cs similarity index 98% rename from Hyperbar.Windows.Primary/WidgetComponentViewModelFactory.cs rename to Hyperbar.Windows.Primary/WidgetComponentFactory.cs index 7402328..4ad2509 100644 --- a/Hyperbar.Windows.Primary/WidgetComponentViewModelFactory.cs +++ b/Hyperbar.Windows.Primary/WidgetComponentFactory.cs @@ -2,7 +2,7 @@ namespace Hyperbar.Windows.Primary; -public class WidgetComponentViewModelFactory(IServiceFactory service, +public class WidgetComponentFactory(IServiceFactory service, IMediator mediator, ICache cache) : IFactory diff --git a/Hyperbar.Windows.Primary/WidgetComponentViewModelProvider.cs b/Hyperbar.Windows.Primary/WidgetComponentProvider.cs similarity index 79% rename from Hyperbar.Windows.Primary/WidgetComponentViewModelProvider.cs rename to Hyperbar.Windows.Primary/WidgetComponentProvider.cs index 455c98d..fec537c 100644 --- a/Hyperbar.Windows.Primary/WidgetComponentViewModelProvider.cs +++ b/Hyperbar.Windows.Primary/WidgetComponentProvider.cs @@ -1,6 +1,6 @@ namespace Hyperbar.Windows.Primary; -public class WidgetComponentViewModelProvider(ICache cache) : +public class WidgetComponentProvider(ICache cache) : IProvider { public IWidgetComponentViewModel? Get(PrimaryCommandConfiguration value) diff --git a/Hyperbar.Windows/App.xaml.cs b/Hyperbar.Windows/App.xaml.cs index 2fda8fc..7189c27 100644 --- a/Hyperbar.Windows/App.xaml.cs +++ b/Hyperbar.Windows/App.xaml.cs @@ -1,12 +1,11 @@ using Hyperbar.Windows.Controls; -using Hyperbar.Windows.MediaController; -using Hyperbar.Windows.Primary; using Hyperbar.Windows.UI; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Json; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; +using System.Reflection; namespace Hyperbar.Windows; @@ -19,17 +18,12 @@ public partial class App : { base.OnLaunched(args); - DispatcherQueueSynchronizationContext context = new(DispatcherQueue.GetForCurrentThread()); - SynchronizationContext.SetSynchronizationContext(context); - - IHost? host = Host.CreateDefaultBuilder() - .UseContentRoot(AppContext.BaseDirectory) + IHost? host = new HostBuilder() + .UseContentRoot(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + Assembly.GetEntryAssembly()?.GetName().Name!), true) .ConfigureAppConfiguration(config => { - config.SetBasePath(AppContext.BaseDirectory); config.AddJsonFile("Settings.json", true, true); - - config.Build(); }) .ConfigureServices((context, services) => { @@ -41,7 +35,7 @@ public partial class App : services.AddSingleton(); services.AddHostedService(); - services.AddConfiguration(); + services.AddConfiguration(args => { args.Placement = DesktopBarPlacemenet.Top; }); services.AddTransient(); services.AddTransient(); @@ -52,31 +46,36 @@ public partial class App : services.AddHandler(); - services.AddWidget(); - services.AddWidget(); + //services.AddWidget(); + //services.AddWidget(); - services.AddTransient(provider => - { - static IEnumerable Resolve(IServiceProvider services) - { - int index = 0; - foreach (WidgetContext widgetContext in services.GetServices()) - { - if (widgetContext.ServiceProvider.GetServices() is - IEnumerable viewModels) - { - yield return (WidgetContainerViewModel)ActivatorUtilities.CreateInstance(widgetContext.ServiceProvider, - typeof(WidgetContainerViewModel), viewModels, index % 2 == 1); + //services.AddTransient(provider => + //{ + // static IEnumerable Resolve(IServiceProvider services) + // { + // int index = 0; + // foreach (WidgetContext widgetContext in services.GetServices()) + // { + // if (widgetContext.ServiceProvider.GetService() is IWidget widget) + // { + // if (widgetContext.ServiceProvider.GetServices() is + // IEnumerable viewModels) + // { + // yield return (WidgetContainerViewModel)ActivatorUtilities.CreateInstance(widgetContext.ServiceProvider, + // typeof(WidgetContainerViewModel), viewModels, index % 2 == 1, widget.Id); - index++; - } - } - } + // index++; + // } + // } + // } + // } - return Resolve(provider); - }); + // return Resolve(provider); + //}); }) - .Build(); + .Build(); + + var d = host.Services.GetService(); await host.RunAsync(); } diff --git a/Hyperbar.Windows/Hyperbar.Windows.csproj b/Hyperbar.Windows/Hyperbar.Windows.csproj index ac508c9..0e35a3b 100644 --- a/Hyperbar.Windows/Hyperbar.Windows.csproj +++ b/Hyperbar.Windows/Hyperbar.Windows.csproj @@ -28,6 +28,10 @@ + + + + @@ -36,31 +40,13 @@ - - - - - - - - - - - - MSBuild:Compile - - - - - MSBuild:Compile - - - - - MSBuild:Compile - - true + + + + + + \ No newline at end of file diff --git a/Hyperbar.Windows/Lifecycles/ConfigurationChangedHandler.cs b/Hyperbar.Windows/Lifecycles/ConfigurationChangedHandler.cs index a2541e5..b184995 100644 --- a/Hyperbar.Windows/Lifecycles/ConfigurationChangedHandler.cs +++ b/Hyperbar.Windows/Lifecycles/ConfigurationChangedHandler.cs @@ -1,6 +1,6 @@ using Hyperbar.Windows.Controls; -namespace Hyperbar.Windows.Primary; +namespace Hyperbar.Windows; public class AppConfigurationChangedHandler(DesktopBar desktopFlyout, AppConfiguration configuration) : diff --git a/Hyperbar.Windows/Lifecycles/IServiceCollectionExtensions.cs b/Hyperbar.Windows/Lifecycles/IServiceCollectionExtensions.cs index ad75c4c..10e5bba 100644 --- a/Hyperbar.Windows/Lifecycles/IServiceCollectionExtensions.cs +++ b/Hyperbar.Windows/Lifecycles/IServiceCollectionExtensions.cs @@ -9,13 +9,11 @@ namespace Hyperbar.Windows { public static class IServiceCollectionExtensions { - public static IServiceCollection AddWidget(this IServiceCollection services) - where TWidgetBuilder : - IWidgetBuilder, new() + public static IServiceCollection AddWidget(this IServiceCollection services) + where TWidget : + IWidget, + new() { - DispatcherQueueSynchronizationContext context = new(DispatcherQueue.GetForCurrentThread()); - SynchronizationContext.SetSynchronizationContext(context); - IHost? host = new HostBuilder() .UseContentRoot(AppContext.BaseDirectory) .ConfigureAppConfiguration(config => @@ -48,8 +46,9 @@ namespace Hyperbar.Windows isolatedServices.AddContentTemplate(); isolatedServices.AddContentTemplate(); - TWidgetBuilder builder = new(); - builder.Create(isolatedServices); + TWidget widget = new(); + IWidgetBuilder builder = widget.Create(); + isolatedServices.AddRange(builder.Services); }).Build(); diff --git a/Hyperbar/Configuration/ConfigurationInitializer.cs b/Hyperbar/Configuration/ConfigurationInitializer.cs index 9bf5e14..b9bea88 100644 --- a/Hyperbar/Configuration/ConfigurationInitializer.cs +++ b/Hyperbar/Configuration/ConfigurationInitializer.cs @@ -1,6 +1,7 @@ namespace Hyperbar; public class ConfigurationInitializer(DefaultConfiguration defaults, + IConfigurationReader reader, IConfigurationWriter writer) : IInitializer where TConfiguration : @@ -9,9 +10,12 @@ public class ConfigurationInitializer(DefaultConfiguration(IConfigurationSource source, +public class ConfigurationMonitor(IConfigurationFile configurationFile, IConfigurationReader reader, IMediator mediator) : IInitializer where TConfiguration : @@ -19,16 +19,21 @@ public class ConfigurationMonitor(IConfigurationSource(IConfigurationSource source, - JsonSerializerOptions? serializerOptions = null) : +public class ConfigurationReader(IConfigurationSource source) : IConfigurationReader where TConfiguration : class, new() { - private static readonly Func defaultSerializerOptions = new(() => - { - return new JsonSerializerOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Converters = - { - new JsonStringEnumConverter() - } - }; - }); - public TConfiguration Read() { - if ((TryGet(out TConfiguration? value) ? value : new TConfiguration()) is TConfiguration configuration) + if ((source.TryGet(out TConfiguration? value) ? value : + new TConfiguration()) is TConfiguration configuration) { return configuration; } @@ -32,21 +16,15 @@ public class ConfigurationReader(IConfigurationSource(sectionValue.ToString(), serializerOptions ?? defaultSerializerOptions()); - return true; - } + configuration = value; + return true; } - value = default; + configuration = default; return false; } } diff --git a/Hyperbar/Configuration/ConfigurationSource.cs b/Hyperbar/Configuration/ConfigurationSource.cs index 642bc46..2839ab3 100644 --- a/Hyperbar/Configuration/ConfigurationSource.cs +++ b/Hyperbar/Configuration/ConfigurationSource.cs @@ -1,12 +1,129 @@ -namespace Hyperbar; +using Microsoft.Extensions.FileProviders; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Json.Serialization; -public class ConfigurationSource(string path, - string section) : +namespace Hyperbar; + +public class ConfigurationSource(IConfigurationFile configurationFile, + string section, + JsonSerializerOptions? serializerOptions = null) : IConfigurationSource where TConfiguration : class { - public string Path => path; + private readonly object lockingObject = new(); - public string Section => section; + private static readonly Func defaultSerializerOptions = new(() => + { + return new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + Converters = + { + new JsonStringEnumConverter() + } + }; + }); + + public void Set(TConfiguration value) + { + lock (lockingObject) + { + IFileInfo fileInfo = configurationFile.FileInfo; + + if (!File.Exists(fileInfo.PhysicalPath)) + { + string? fileDirectoryPath = Path.GetDirectoryName(fileInfo.PhysicalPath); + if (!string.IsNullOrEmpty(fileDirectoryPath)) + { + Directory.CreateDirectory(fileDirectoryPath); + } + + File.WriteAllText(fileInfo.PhysicalPath!, "{}"); + } + + static Stream OpenReadWrite(IFileInfo fileInfo) + { + return fileInfo.PhysicalPath is not null + ? new FileStream(fileInfo.PhysicalPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite) + : fileInfo.CreateReadStream(); + } + + using Stream stream = OpenReadWrite(fileInfo); + using StreamReader? reader = new(stream); + + string? content = reader.ReadToEnd(); + using JsonDocument jsonDocument = JsonDocument.Parse(content); + + using Stream stream2 = OpenReadWrite(fileInfo); + Utf8JsonWriter writer = new(stream2, new JsonWriterOptions() + { + Indented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }); + + writer.WriteStartObject(); + bool isWritten = false; + + JsonDocument optionsElement = JsonDocument.Parse(JsonSerializer.SerializeToUtf8Bytes(value, + serializerOptions ?? defaultSerializerOptions())); + + foreach (JsonProperty element in jsonDocument.RootElement.EnumerateObject()) + { + if (element.Name != section) + { + element.WriteTo(writer); + continue; + } + writer.WritePropertyName(element.Name); + optionsElement.WriteTo(writer); + isWritten = true; + } + + if (!isWritten) + { + writer.WritePropertyName(section); + optionsElement.WriteTo(writer); + } + + writer.WriteEndObject(); + writer.Flush(); + stream2.SetLength(stream2.Position); + } + } + + public bool TryGet(out TConfiguration? value) + { + lock (lockingObject) + { + IFileInfo fileInfo = configurationFile.FileInfo; + + if (File.Exists(fileInfo.PhysicalPath)) + { + static Stream OpenRead(IFileInfo fileInfo) + { + return fileInfo.PhysicalPath is not null + ? new FileStream(fileInfo.PhysicalPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite) + : fileInfo.CreateReadStream(); + } + + using Stream stream = OpenRead(fileInfo); + using StreamReader? reader = new(stream); + + string? content = reader.ReadToEnd(); + + using JsonDocument jsonDocument = JsonDocument.Parse(content); + if (jsonDocument.RootElement.TryGetProperty(section, out JsonElement sectionValue)) + { + value = JsonSerializer.Deserialize(sectionValue.ToString(), serializerOptions ?? defaultSerializerOptions()); + return true; + } + } + + value = default; + return false; + } + } } \ No newline at end of file diff --git a/Hyperbar/Configuration/ConfigurationWriter.cs b/Hyperbar/Configuration/ConfigurationWriter.cs index 3fbc16a..c08b365 100644 --- a/Hyperbar/Configuration/ConfigurationWriter.cs +++ b/Hyperbar/Configuration/ConfigurationWriter.cs @@ -1,28 +1,13 @@ -using System.Text.Encodings.Web; -using System.Text.Json; -using System.Text.Json.Serialization; +namespace Hyperbar; -namespace Hyperbar; - -public class ConfigurationWriter(IConfigurationSource source, - JsonSerializerOptions? serializerOptions = null) : +public class ConfigurationWriter(IConfigurationSource source) : IConfigurationWriter where TConfiguration : class, new() { - private static readonly Func defaultSerializerOptions = new(() => - { - return new JsonSerializerOptions - { - WriteIndented = true, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Converters = { new JsonStringEnumConverter() } - }; - }); - public void Write(Action updateDelegate) { - if ((TryGet(out TConfiguration? value) ? value : new TConfiguration()) is TConfiguration updatedValue) + if ((source.TryGet(out TConfiguration? value) ? value : new TConfiguration()) is TConfiguration updatedValue) { updateDelegate?.Invoke(updatedValue); Write(updatedValue); @@ -31,69 +16,6 @@ public class ConfigurationWriter(IConfigurationSource(sectionValue.ToString(), serializerOptions ?? defaultSerializerOptions()); - return true; - } - } - - value = default; - return false; + source.Set(value); } } \ No newline at end of file diff --git a/Hyperbar/Configuration/IConfigurationReader.cs b/Hyperbar/Configuration/IConfigurationReader.cs index 9441c75..5828d26 100644 --- a/Hyperbar/Configuration/IConfigurationReader.cs +++ b/Hyperbar/Configuration/IConfigurationReader.cs @@ -4,5 +4,7 @@ public interface IConfigurationReader where TConfiguration : class, new() { + bool TryRead(out TConfiguration? configuration); + TConfiguration Read(); } diff --git a/Hyperbar/Configuration/IConfigurationSource.cs b/Hyperbar/Configuration/IConfigurationSource.cs index 42d8946..9a3b3eb 100644 --- a/Hyperbar/Configuration/IConfigurationSource.cs +++ b/Hyperbar/Configuration/IConfigurationSource.cs @@ -1,10 +1,12 @@ -namespace Hyperbar; +using Microsoft.Extensions.FileProviders; + +namespace Hyperbar; public interface IConfigurationSource where TConfiguration : class { - string Path { get; } + bool TryGet(out TConfiguration? value); - string Section { get; } + void Set(TConfiguration value); } diff --git a/Hyperbar/Extensions/IHostBuilderExtensions.cs b/Hyperbar/Extensions/IHostBuilderExtensions.cs new file mode 100644 index 0000000..8140dce --- /dev/null +++ b/Hyperbar/Extensions/IHostBuilderExtensions.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.Hosting; + +namespace Hyperbar; + +public static class IHostBuilderExtensions +{ + public static IHostBuilder UseContentRoot(this IHostBuilder hostBuilder, + string contentRoot, + bool createDirectory) + { + if (createDirectory) + { + Directory.CreateDirectory(contentRoot); + } + + hostBuilder.UseContentRoot(contentRoot); + return hostBuilder; + } +} diff --git a/Hyperbar/Extensions/IServiceCollectionExtensions.cs b/Hyperbar/Extensions/IServiceCollectionExtensions.cs index 82ae307..9f6e1e3 100644 --- a/Hyperbar/Extensions/IServiceCollectionExtensions.cs +++ b/Hyperbar/Extensions/IServiceCollectionExtensions.cs @@ -1,12 +1,27 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.FileProviders.Physical; using Microsoft.Extensions.Hosting; using System.Text.Json; namespace Hyperbar; +public interface IConfigurationFile + where TConfiguration : + class +{ + IFileInfo FileInfo { get; } +} + +public class ConfigurationFile(IFileInfo fileInfo) : + IConfigurationFile + where TConfiguration : + class +{ + public IFileInfo FileInfo => fileInfo; +} + public static class IServiceCollectionExtensions { public static IServiceCollection AddCache(this IServiceCollection services) @@ -36,7 +51,7 @@ public static class IServiceCollectionExtensions return services.AddConfiguration(typeof(TConfiguration).Name, "Settings.json", null); } - public static IServiceCollection AddConfiguration(this IServiceCollection services, + public static IServiceCollection AddConfiguration(this IServiceCollection services, Action configurationDelegate) where TConfiguration : class, new() @@ -66,47 +81,34 @@ public static class IServiceCollectionExtensions { services.AddSingleton>(provider => { - string? jsonFilePath = null; + JsonSerializerOptions? defaultSerializer = null; + if (serializerDelegate is not null) + { + defaultSerializer = new JsonSerializerOptions(); + serializerDelegate.Invoke(defaultSerializer); + } + + return new ConfigurationSource(provider.GetRequiredService>(), section, defaultSerializer); + }); + + services.AddSingleton>(provider => + { + IFileInfo? fileInfo = null; if (provider.GetService() is IHostEnvironment hostEnvironment) { IFileProvider fileProvider = hostEnvironment.ContentRootFileProvider; - IFileInfo fileInfo = fileProvider.GetFileInfo(path); - - jsonFilePath = fileInfo.PhysicalPath; + fileInfo = fileProvider.GetFileInfo(path); } - jsonFilePath ??= Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path); - return new ConfigurationSource(jsonFilePath, section); - }); - - services.AddSingleton>(provider => - { - JsonSerializerOptions? defaultSerializer = null; - if (serializerDelegate is not null) - { - defaultSerializer = new JsonSerializerOptions(); - serializerDelegate.Invoke(defaultSerializer); - } - - return new ConfigurationReader(provider.GetRequiredService>(), - defaultSerializer); - }); - - services.AddSingleton>(provider => - { - JsonSerializerOptions? defaultSerializer = null; - if (serializerDelegate is not null) - { - defaultSerializer = new JsonSerializerOptions(); - serializerDelegate.Invoke(defaultSerializer); - } - - return new ConfigurationWriter(provider.GetRequiredService>(), - defaultSerializer); + fileInfo ??= new PhysicalFileInfo(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path))); + return new ConfigurationFile(fileInfo); }); services.AddSingleton>(); + services.AddSingleton, ConfigurationReader>(); + services.AddSingleton, ConfigurationWriter>(); + services.AddTransient(provider => new DefaultConfiguration(defaults)); services.AddTransient>(); @@ -151,8 +153,6 @@ public static class IServiceCollectionExtensions if (contract.GetGenericArguments() is { Length: 1 } arguments) { Type notificationType = arguments[0]; - - //services.TryAdd(new ServiceDescriptor(typeof(THandler), typeof(THandler), lifetime)); services.Add(new ServiceDescriptor(typeof(INotificationHandler<>).MakeGenericType(notificationType), typeof(THandler), lifetime)); } } @@ -182,14 +182,16 @@ public static class IServiceCollectionExtensions return services; } - //public static IServiceCollection AddNotificationPipeline(this IServiceCollection services) - // where TFromNotification : - // INotification - // where TToNotification : - // INotification, new() - //{ - // return services.AddHandler>(); - //} + public static IServiceCollection AddRange(this IServiceCollection services, + IServiceCollection fromServices) + { + foreach (ServiceDescriptor service in fromServices) + { + services.Add(service); + } + + return services; + } public static IServiceCollection AddWidgetTemplate(this IServiceCollection services) where TWidgetContent : diff --git a/Hyperbar/Lifecycles/Cache.cs b/Hyperbar/Lifecycles/Cache.cs index a6cc37e..c1bbf9b 100644 --- a/Hyperbar/Lifecycles/Cache.cs +++ b/Hyperbar/Lifecycles/Cache.cs @@ -21,7 +21,7 @@ public class Cache(IDisposer disposer) : public void Clear() => cache.Clear(); - public IEnumerator GetEnumerator() => cache.GetEnumerator(); + public System.Collections.Generic.IEnumerator GetEnumerator() => cache.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); @@ -57,7 +57,7 @@ public class Cache(IDisposer disposer) : public bool ContainsKey(TKey key) => cache.ContainsKey(key); - public IEnumerator> GetEnumerator() => cache.GetEnumerator(); + public System.Collections.Generic.IEnumerator> GetEnumerator() => cache.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); diff --git a/Hyperbar/Views/IViewModelEnumerator.cs b/Hyperbar/Views/IEnumerator.cs similarity index 57% rename from Hyperbar/Views/IViewModelEnumerator.cs rename to Hyperbar/Views/IEnumerator.cs index cc0decf..94c164a 100644 --- a/Hyperbar/Views/IViewModelEnumerator.cs +++ b/Hyperbar/Views/IEnumerator.cs @@ -1,6 +1,6 @@ namespace Hyperbar; -public interface IViewModelEnumerator +public interface IEnumerator { IEnumerable Next(); } diff --git a/Hyperbar/Views/IViewModelInitialization.cs b/Hyperbar/Views/IInitialization.cs similarity index 73% rename from Hyperbar/Views/IViewModelInitialization.cs rename to Hyperbar/Views/IInitialization.cs index 0faceab..ddb9bc2 100644 --- a/Hyperbar/Views/IViewModelInitialization.cs +++ b/Hyperbar/Views/IInitialization.cs @@ -2,7 +2,7 @@ namespace Hyperbar; -public interface IViewModelInitialization +public interface IInitialization { ICommand Initialize { get; } diff --git a/Hyperbar/Views/ObservableCollectionViewModel.cs b/Hyperbar/Views/ObservableCollectionViewModel.cs index 5487f16..2dcf467 100644 --- a/Hyperbar/Views/ObservableCollectionViewModel.cs +++ b/Hyperbar/Views/ObservableCollectionViewModel.cs @@ -18,7 +18,7 @@ public partial class ObservableCollectionViewModel : IDisposable { public ObservableCollection collection = []; - private readonly IViewModelEnumerator? enumerator; + private readonly IEnumerator? enumerator; public ObservableCollectionViewModel(IServiceFactory serviceFactory, IMediator mediator, @@ -36,7 +36,7 @@ public partial class ObservableCollectionViewModel : public ObservableCollectionViewModel(IServiceFactory serviceFactory, IMediator mediator, IDisposer disposer, - IViewModelEnumerator enumerator) + IEnumerator enumerator) { ServiceFactory = serviceFactory; Mediator = mediator; @@ -201,7 +201,7 @@ public partial class ObservableCollectionViewModel : public void Dispose() => Disposer.Dispose(this); - public IEnumerator GetEnumerator() => + public System.Collections.Generic.IEnumerator GetEnumerator() => collection.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => diff --git a/Hyperbar/Widgets/IWidget.cs b/Hyperbar/Widgets/IWidget.cs index 4f9dafc..90b46c7 100644 --- a/Hyperbar/Widgets/IWidget.cs +++ b/Hyperbar/Widgets/IWidget.cs @@ -2,9 +2,5 @@ public interface IWidget { - Guid Id { get; set; } - - string? Name { get; set; } - - string? Description { get; set; } + IWidgetBuilder Create(); } diff --git a/Hyperbar/Widgets/IWidgetAssemblyLoader.cs b/Hyperbar/Widgets/IWidgetAssemblyLoader.cs new file mode 100644 index 0000000..3929e0f --- /dev/null +++ b/Hyperbar/Widgets/IWidgetAssemblyLoader.cs @@ -0,0 +1,6 @@ +namespace Hyperbar +{ + public interface IWidgetAssemblyLoader + { + } +} \ No newline at end of file diff --git a/Hyperbar/Widgets/IWidgetBuilder.cs b/Hyperbar/Widgets/IWidgetBuilder.cs index 7365e98..ce1ae1f 100644 --- a/Hyperbar/Widgets/IWidgetBuilder.cs +++ b/Hyperbar/Widgets/IWidgetBuilder.cs @@ -4,5 +4,7 @@ namespace Hyperbar; public interface IWidgetBuilder { - void Create(IServiceCollection services); + WidgetConfiguration Configuration { get; } + + IServiceCollection Services { get; } } \ No newline at end of file diff --git a/Hyperbar/Widgets/IWidgetBuilderExtensions.cs b/Hyperbar/Widgets/IWidgetBuilderExtensions.cs new file mode 100644 index 0000000..b01cf62 --- /dev/null +++ b/Hyperbar/Widgets/IWidgetBuilderExtensions.cs @@ -0,0 +1,35 @@ +using Microsoft.Extensions.DependencyInjection; +using System.Reflection; +using System.Runtime.Loader; + +namespace Hyperbar; + +public class AssemblyProvider +{ + public static void Load() + { + string extensionsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Extensions"); + Directory.CreateDirectory(extensionsPath); + } + + public static IEnumerable Get(string path) + { + string extensionsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Extensions"); + + Directory.CreateDirectory(extensionsPath); + foreach (string assemblyPath in Directory.GetFiles(extensionsPath, "*.dll", SearchOption.AllDirectories)) + { + yield return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); + } + } +} + +public static class IWidgetBuilderExtensions +{ + public static IWidgetBuilder ConfigureServices(this IWidgetBuilder builder, + Action servicesDelegate) + { + servicesDelegate(builder.Services); + return builder; + } +} diff --git a/Hyperbar/Widgets/Widget.cs b/Hyperbar/Widgets/Widget.cs deleted file mode 100644 index 4519d6d..0000000 --- a/Hyperbar/Widgets/Widget.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Hyperbar; - -public class Widget : - IWidget -{ - public Guid Id { get; set; } = Guid.NewGuid(); - - public string? Name { get; set; } - - public string? Description { get; set; } -} diff --git a/Hyperbar/Widgets/WidgetBuilder.cs b/Hyperbar/Widgets/WidgetBuilder.cs new file mode 100644 index 0000000..1c46b83 --- /dev/null +++ b/Hyperbar/Widgets/WidgetBuilder.cs @@ -0,0 +1,22 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Hyperbar; + +public class WidgetBuilder(WidgetConfiguration configuration) : + IWidgetBuilder +{ + public IServiceCollection Services => new ServiceCollection(); + + public WidgetConfiguration Configuration => configuration; + + public static IWidgetBuilder Configure(Action configurationDelegate) + where TWidgetConfiguration : + WidgetConfiguration, + new() + { + TWidgetConfiguration configuration = new(); + configurationDelegate(configuration); + + return new WidgetBuilder(configuration); + } +} \ No newline at end of file diff --git a/Hyperbar/Widgets/WidgetConfiguration.cs b/Hyperbar/Widgets/WidgetConfiguration.cs index 00509de..3a3aba0 100644 --- a/Hyperbar/Widgets/WidgetConfiguration.cs +++ b/Hyperbar/Widgets/WidgetConfiguration.cs @@ -1,15 +1,10 @@ -using Microsoft.Extensions.DependencyInjection; +namespace Hyperbar; -namespace Hyperbar; - -public class WidgetBuilder +public abstract class WidgetConfiguration { - public static void Config(IServiceCollection services, - Action widgetDelegate) - { - Widget widget = new(); - widgetDelegate(widget); + public Guid Id { get; set; } = Guid.NewGuid(); - services.AddSingleton(widget); - } -} \ No newline at end of file + public string? Name { get; set; } + + public string? Description { get; set; } +} diff --git a/Hyperbar/Widgets/WidgetContext.cs b/Hyperbar/Widgets/WidgetContext.cs index 397edea..78c44b1 100644 --- a/Hyperbar/Widgets/WidgetContext.cs +++ b/Hyperbar/Widgets/WidgetContext.cs @@ -1,11 +1,28 @@ - -namespace Hyperbar; +namespace Hyperbar; public class WidgetContext(IServiceProvider serviceProvider) : IInitializer { public IServiceProvider ServiceProvider => serviceProvider; + public Task InitializeAsync() + { + throw new NotImplementedException(); + } +} + +public class WidgetMonitor : + IInitializer +{ + public Task InitializeAsync() + { + throw new NotImplementedException(); + } +} + +public class WidgetManager : + IInitializer +{ public Task InitializeAsync() { throw new NotImplementedException(); diff --git a/Hyperbar/Widgets/WidgetEnumerator.cs b/Hyperbar/Widgets/WidgetEnumerator.cs new file mode 100644 index 0000000..1b8260f --- /dev/null +++ b/Hyperbar/Widgets/WidgetEnumerator.cs @@ -0,0 +1,11 @@ + +namespace Hyperbar; + +public class WidgetEnumerator() : + IEnumerator +{ + public IEnumerable Next() + { + return null; + } +}