diff --git a/Hyperbar.Windows.Primary/PrimaryWidgetConfigurationHandler.cs b/Hyperbar.Windows.Primary/PrimaryWidgetConfigurationHandler.cs index 08281fa..5601de7 100644 --- a/Hyperbar.Windows.Primary/PrimaryWidgetConfigurationHandler.cs +++ b/Hyperbar.Windows.Primary/PrimaryWidgetConfigurationHandler.cs @@ -1,62 +1,71 @@ - -namespace Hyperbar.Windows.Primary; +namespace Hyperbar.Windows.Primary; public class PrimaryWidgetConfigurationHandler(IMediator mediator, PrimaryWidgetConfiguration configuration, IFactory factory, - ICache cache) : + IProvider provider, + ICache<(Guid ParentId, Guid Id), PrimaryCommandConfiguration> cache) : INotificationHandler> { public async Task Handle(ConfigurationChanged notification, CancellationToken cancellationToken) { - List<(Guid ParentId, Guid Id, PrimaryCommandConfiguration Configuration)> items = []; + List> items = []; - void AddToItems(Guid parentId, Guid id, List configurations) + Stack<(Guid, List)> stack = new(); + stack.Push((Guid.Empty, configuration.Commands)); + + while (stack.Count > 0) { - if (configurations is null) + (Guid currentParentId, List currentConfigurations) = stack.Pop(); + foreach (PrimaryCommandConfiguration configuration in currentConfigurations) { - return; - } - - Stack<(Guid, List)> stack = new(); - stack.Push((parentId, configurations)); - - while (stack.Count > 0) - { - (Guid currentParentId, List currentConfigurations) = stack.Pop(); - foreach (PrimaryCommandConfiguration configuration in currentConfigurations) + items.Add(new KeyValuePair<(Guid ParentId, Guid Id), PrimaryCommandConfiguration>((currentParentId, configuration.Id), configuration)); + if (configuration.Commands is not null && configuration.Commands.Count > 0) { - items.Add((currentParentId, configuration.Id, configuration)); - if (configuration.Commands is not null && configuration.Commands.Count > 0) - { - stack.Push((configuration.Id, configuration.Commands)); - } + stack.Push((configuration.Id, configuration.Commands)); } } } - AddToItems(Guid.Empty, Guid.Empty, configuration.Commands); - - foreach (KeyValuePair item in cache - .Where(x => !items.Any(k => x.Key == k.Id))) + foreach (KeyValuePair<(Guid ParentId, Guid Id), PrimaryCommandConfiguration> added in + items.ExceptBy(cache.Select(x => x.Key.Id), x => x.Key.Id)) { - await mediator.PublishAsync(new Removed(item.Value), - nameof(PrimaryWidgetViewModel), - cancellationToken); - - cache.Remove(item.Key); - } - - foreach ((Guid ParentId, Guid Id, PrimaryCommandConfiguration Configuration) item in - items.Where(x => !cache.Any(k => x.Id == k.Key))) - { - if (factory.Create(item.Configuration) is IWidgetComponentViewModel viewModel) + if (added.Value is PrimaryCommandConfiguration configuration) { - await mediator.PublishAsync(new Inserted(item.Configuration.Order, viewModel), - nameof(PrimaryWidgetViewModel), - cancellationToken); + if (factory.Create(configuration) is IWidgetComponentViewModel viewModel) + { + await mediator.PublishAsync(new Inserted(configuration.Order, viewModel), + added.Key.ParentId == Guid.Empty ? nameof(PrimaryWidgetViewModel) : added.Key.ParentId, + cancellationToken); + } + + cache.Add(added.Key, added.Value); } } + + foreach (KeyValuePair<(Guid ParentId, Guid Id), PrimaryCommandConfiguration> removed in + cache.ExceptBy(items.Select(x => x.Key.Id), x => x.Key.Id)) + { + if (removed.Value is PrimaryCommandConfiguration configuration) + { + if (provider.Get(configuration) is IWidgetComponentViewModel viewModel) + { + await mediator.PublishAsync(new Removed(viewModel), + removed.Key.ParentId == Guid.Empty ? nameof(PrimaryWidgetViewModel) : removed.Key.ParentId, + cancellationToken); + + cache.Remove(removed.Key); + } + } + } + + //foreach (KeyValuePair item in cache + // .Where(x => !items.Any(k => x.Key == k.Id))) + //{ + // await mediator.PublishAsync(new Removed(item.Value), + // nameof(PrimaryWidgetViewModel), + // cancellationToken); + //} } } diff --git a/Hyperbar.Windows.Primary/PrimaryWidgetProvider.cs b/Hyperbar.Windows.Primary/PrimaryWidgetProvider.cs index ef7f0ce..5b75b92 100644 --- a/Hyperbar.Windows.Primary/PrimaryWidgetProvider.cs +++ b/Hyperbar.Windows.Primary/PrimaryWidgetProvider.cs @@ -8,7 +8,9 @@ public class PrimaryWidgetProvider : { public void Create(HostBuilderContext comtext, IServiceCollection services) => services.AddConfiguration() + .AddCache<(Guid ParentId, Guid Id), PrimaryCommandConfiguration>() .AddCache() + .AddTransient, WidgetComponentViewModelProvider>() .AddTransient, WidgetComponentViewModelFactory>() .AddTransient, WidgetComponentViewModelEnumerator>() .AddWidgetTemplate() diff --git a/Hyperbar.Windows.Primary/WidgetComponentViewModelEnumerator.cs b/Hyperbar.Windows.Primary/WidgetComponentViewModelEnumerator.cs index 6bf343e..43baf50 100644 --- a/Hyperbar.Windows.Primary/WidgetComponentViewModelEnumerator.cs +++ b/Hyperbar.Windows.Primary/WidgetComponentViewModelEnumerator.cs @@ -1,11 +1,28 @@ namespace Hyperbar.Windows.Primary; public class WidgetComponentViewModelEnumerator(PrimaryWidgetConfiguration configuration, - IFactory factory) : + IFactory factory, + ICache<(Guid ParentId, Guid Id), PrimaryCommandConfiguration> cache) : IViewModelEnumerator { public IEnumerable Next() { + Stack<(Guid, List)> stack = new(); + stack.Push((Guid.Empty, configuration.Commands)); + + while (stack.Count > 0) + { + (Guid currentParentId, List currentConfigurations) = stack.Pop(); + foreach (PrimaryCommandConfiguration configuration in currentConfigurations) + { + cache.Add((currentParentId, configuration.Id), configuration); + if (configuration.Commands is not null && configuration.Commands.Count > 0) + { + stack.Push((configuration.Id, configuration.Commands)); + } + } + } + foreach (PrimaryCommandConfiguration item in configuration.Commands.OrderBy(x => x.Order)) { yield return factory.Create(item); diff --git a/Hyperbar.Windows.Primary/WidgetComponentViewModelFactory.cs b/Hyperbar.Windows.Primary/WidgetComponentViewModelFactory.cs index 7402328..de4ce2d 100644 --- a/Hyperbar.Windows.Primary/WidgetComponentViewModelFactory.cs +++ b/Hyperbar.Windows.Primary/WidgetComponentViewModelFactory.cs @@ -2,6 +2,20 @@ namespace Hyperbar.Windows.Primary; +public class WidgetComponentViewModelProvider(ICache cache) : + IProvider +{ + public IWidgetComponentViewModel? Get(PrimaryCommandConfiguration value) + { + if (cache.TryGetValue(value.Id, out IWidgetComponentViewModel? viewModel)) + { + return viewModel; + } + + return default; + } +} + public class WidgetComponentViewModelFactory(IServiceFactory service, IMediator mediator, ICache cache) : diff --git a/Hyperbar/Extensions/IServiceCollectionExtensions.cs b/Hyperbar/Extensions/IServiceCollectionExtensions.cs index 645b36a..f41037f 100644 --- a/Hyperbar/Extensions/IServiceCollectionExtensions.cs +++ b/Hyperbar/Extensions/IServiceCollectionExtensions.cs @@ -12,6 +12,8 @@ public static class IServiceCollectionExtensions public static IServiceCollection AddCache(this IServiceCollection services) where TKey : notnull + where TValue : + notnull { services.AddScoped, Cache>(); services.AddTransient(provider => provider.GetService>()!.Select(x => x.Value)); diff --git a/Hyperbar/Lifecycles/Cache.cs b/Hyperbar/Lifecycles/Cache.cs index e75b3a9..a6cc37e 100644 --- a/Hyperbar/Lifecycles/Cache.cs +++ b/Hyperbar/Lifecycles/Cache.cs @@ -30,8 +30,10 @@ public class Cache(IDisposer disposer) : public class Cache(IDisposer disposer) : ICache - where TKey : notnull - where TValue : notnull + where TKey : + notnull + where TValue : + notnull { private readonly ConcurrentDictionary cache = new(); @@ -40,9 +42,13 @@ public class Cache(IDisposer disposer) : { cache.TryAdd(key, value); + disposer.Add(value, Disposable.Create(() => + { + Remove(key); + })); + disposer.Add(key, Disposable.Create(() => { - disposer.Dispose(value); Remove(key); })); } diff --git a/Hyperbar/Lifecycles/ICache.cs b/Hyperbar/Lifecycles/ICache.cs index d4dc3ce..865c742 100644 --- a/Hyperbar/Lifecycles/ICache.cs +++ b/Hyperbar/Lifecycles/ICache.cs @@ -1,6 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace Hyperbar; +namespace Hyperbar; public interface ICache : IEnumerable @@ -14,7 +12,10 @@ public interface ICache : public interface ICache : IEnumerable> - where TKey : notnull + where TKey : + notnull + where TValue : + notnull { void Add(TKey key, TValue value); diff --git a/Hyperbar/Lifecycles/IFactory.cs b/Hyperbar/Lifecycles/IFactory.cs index 7b73e95..46093c7 100644 --- a/Hyperbar/Lifecycles/IFactory.cs +++ b/Hyperbar/Lifecycles/IFactory.cs @@ -10,3 +10,15 @@ public interface IFactory { TService? Create(); } + + +public interface IProvider +{ + TService? Get(TParameter value); +} + + +public interface IProvider +{ + TService? Get(); +}