Initilize widget setting without starting its host

This commit is contained in:
TheXamlGuy
2024-01-31 22:33:23 +00:00
parent a2a5591502
commit 6dbe2db584
25 changed files with 125 additions and 83 deletions
@@ -1,30 +1,35 @@
using Windows.Media.Control; using Microsoft.Extensions.Hosting;
using Windows.Media.Control;
namespace Hyperbar.Widget.MediaController.Windows; namespace Hyperbar.Widget.MediaController.Windows;
public class MediaControllerManager(IMediator mediator, public class MediaControllerService(IMediator mediator,
IFactory<GlobalSystemMediaTransportControlsSession, MediaController> factory) : IFactory<GlobalSystemMediaTransportControlsSession, MediaController> factory) :
IInitializer IHostedService
{ {
private readonly AsyncLock asyncLock = new(); private readonly AsyncLock asyncLock = new();
private readonly List<KeyValuePair<GlobalSystemMediaTransportControlsSession, MediaController>> cache = []; private readonly List<KeyValuePair<GlobalSystemMediaTransportControlsSession, MediaController>> cache = [];
private GlobalSystemMediaTransportControlsSessionManager? mediaTransportControlsSessionManager; private GlobalSystemMediaTransportControlsSessionManager? mediaTransportControlsSessionManager;
public async Task InitializeAsync() public async Task StartAsync(CancellationToken cancellationToken)
{ {
mediaTransportControlsSessionManager = await GlobalSystemMediaTransportControlsSessionManager.RequestAsync(); mediaTransportControlsSessionManager = await GlobalSystemMediaTransportControlsSessionManager.RequestAsync();
mediaTransportControlsSessionManager.SessionsChanged += OnSessionsChanged; mediaTransportControlsSessionManager.SessionsChanged += OnSessionsChanged;
IReadOnlyList<GlobalSystemMediaTransportControlsSession> sessions = IReadOnlyList<GlobalSystemMediaTransportControlsSession> sessions =
mediaTransportControlsSessionManager.GetSessions(); mediaTransportControlsSessionManager.GetSessions();
foreach (GlobalSystemMediaTransportControlsSession session in sessions) foreach (GlobalSystemMediaTransportControlsSession session in sessions)
{ {
await InitializeSessionAsync(session); await InitializeSessionAsync(session);
} }
} }
public Task StopAsync(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
private async Task InitializeSessionAsync(GlobalSystemMediaTransportControlsSession session) private async Task InitializeSessionAsync(GlobalSystemMediaTransportControlsSession session)
{ {
if (factory.Create(session) is MediaController mediaController) if (factory.Create(session) is MediaController mediaController)
@@ -15,7 +15,7 @@ public class MediaControllerWidget :
.UseViewModelTemplate<MediaControllerWidgetViewModel, MediaControllerWidgetView>() .UseViewModelTemplate<MediaControllerWidgetViewModel, MediaControllerWidgetView>()
.ConfigureServices(args => .ConfigureServices(args =>
{ {
args.AddSingleton<IInitializer, MediaControllerManager>() args.AddHostedService<MediaControllerService>()
.AddTransient<IServiceScopeFactory<MediaController>, ServiceScopeFactory<MediaController>>() .AddTransient<IServiceScopeFactory<MediaController>, ServiceScopeFactory<MediaController>>()
.AddTransient<IServiceScopeProvider<MediaController>, ServiceScopeProvider<MediaController>>() .AddTransient<IServiceScopeProvider<MediaController>, ServiceScopeProvider<MediaController>>()
.AddCache<MediaController, IServiceScope>() .AddCache<MediaController, IServiceScope>()
@@ -30,8 +30,8 @@ public static class IServiceCollectionExtensions
services.AddHandler<WidgetViewModelEnumerator>(); services.AddHandler<WidgetViewModelEnumerator>();
services.AddTransient<IWidgetView, WidgetView>(); services.AddTransient<IWidgetView, WidgetView>();
services.AddTransient<IInitializer, WidgetResourceInitializer>(); services.AddTransient<IInitialization, WidgetResourceInitializer>();
services.AddTransient<IInitializer, WidgetXamlMetadataInitializer>(); services.AddTransient<IInitialization, WidgetXamlMetadataInitializer>();
services.AddContentTemplate<WidgetButtonViewModel, WidgetButtonView>(); services.AddContentTemplate<WidgetButtonViewModel, WidgetButtonView>();
services.AddContentTemplate<WidgetSplitButtonViewModel, WidgetSplitButtonView>(); services.AddContentTemplate<WidgetSplitButtonViewModel, WidgetSplitButtonView>();
@@ -4,7 +4,7 @@ using Windows.Storage;
namespace Hyperbar.Widget.Windows; namespace Hyperbar.Widget.Windows;
internal class WidgetResourceInitializer(IWidgetAssembly widgetAssembly) : internal class WidgetResourceInitializer(IWidgetAssembly widgetAssembly) :
IInitializer IInitialization
{ {
public async Task InitializeAsync() public async Task InitializeAsync()
{ {
@@ -4,7 +4,7 @@ namespace Hyperbar.Widget.Windows;
public class WidgetXamlMetadataInitializer(IWidgetAssembly widgetAssembly, public class WidgetXamlMetadataInitializer(IWidgetAssembly widgetAssembly,
IList<IXamlMetadataProvider> xamlMetadataProviders) : IList<IXamlMetadataProvider> xamlMetadataProviders) :
IInitializer IInitialization
{ {
public Task InitializeAsync() public Task InitializeAsync()
{ {
@@ -7,7 +7,7 @@ public static class IServiceCollectionExtensions
{ {
public static IServiceCollection AddWidget(this IServiceCollection services) public static IServiceCollection AddWidget(this IServiceCollection services)
{ {
services.AddTransient<IInitializer, WidgetExtensionInitializer>(); services.AddTransient<IInitialization, WidgetExtensionInitializer>();
services.AddTransient<IFactory<Type, IWidget>, WidgetFactory>(); services.AddTransient<IFactory<Type, IWidget>, WidgetFactory>();
services.AddHandler<WidgetExtensionEnumerator>(); services.AddHandler<WidgetExtensionEnumerator>();
+4 -4
View File
@@ -1,9 +1,9 @@
namespace Hyperbar.Widget; using Microsoft.Extensions.Hosting;
namespace Hyperbar.Widget;
public interface IWidgetHost : public interface IWidgetHost :
IInitializer IHost
{ {
WidgetConfiguration Configuration { get; } WidgetConfiguration Configuration { get; }
IServiceProvider Services { get; }
} }
+2 -1
View File
@@ -1,3 +1,4 @@
namespace Hyperbar.Widget; namespace Hyperbar.Widget;
public interface IWidgetViewModel : IDisposable; public interface IWidgetViewModel :
IDisposable;
+9 -4
View File
@@ -25,7 +25,7 @@ public class WidgetBuilder :
}) })
.ConfigureServices((context, services) => .ConfigureServices((context, services) =>
{ {
services.AddSingleton<IWidgetHost, WidgetHost>(); services.AddHostedService<WidgetService>();
services.AddScoped<IServiceFactory>(provider => services.AddScoped<IServiceFactory>(provider =>
new ServiceFactory((type, parameters) => new ServiceFactory((type, parameters) =>
ActivatorUtilities.CreateInstance(provider, type, parameters!))); ActivatorUtilities.CreateInstance(provider, type, parameters!)));
@@ -36,10 +36,13 @@ public class WidgetBuilder :
} }
public static IWidgetBuilder Create() => new WidgetBuilder(); public static IWidgetBuilder Create() => new WidgetBuilder();
public IWidgetHost Build() public IWidgetHost Build()
{ {
IHost host = hostBuilder.Build(); IHost host = hostBuilder.Build();
return host.Services.GetRequiredService<IWidgetHost>();
return (IWidgetHost)ActivatorUtilities.CreateInstance(host.Services,
typeof(WidgetHost), host);
} }
public IWidgetBuilder UseConfiguration<TConfiguration>(Action<TConfiguration> configurationDelegate) public IWidgetBuilder UseConfiguration<TConfiguration>(Action<TConfiguration> configurationDelegate)
@@ -60,7 +63,9 @@ public class WidgetBuilder :
hostBuilder.ConfigureServices(services => hostBuilder.ConfigureServices(services =>
{ {
services.AddHandler<WidgetConfigurationHandler>(); services.AddHandler<WidgetConfigurationHandler>();
services.AddConfiguration<WidgetConfiguration>(section: configuration.GetType().Name, configuration: configuration); services.AddConfiguration<WidgetConfiguration>(section: configuration.GetType().Name,
configuration: configuration);
services.AddConfiguration(configuration); services.AddConfiguration(configuration);
}); });
@@ -93,7 +98,7 @@ public class WidgetBuilder :
} }
public IWidgetBuilder UseViewModelTemplate<TWidgetContent, TWidgetTemplate>() public IWidgetBuilder UseViewModelTemplate<TWidgetContent, TWidgetTemplate>()
where TWidgetContent : where TWidgetContent :
IWidgetViewModel IWidgetViewModel
{ {
if (viewModelTemplateRegistered) if (viewModelTemplateRegistered)
+4 -4
View File
@@ -5,13 +5,13 @@ public class WidgetConfiguration
{ {
public string? Description { get; set; } public string? Description { get; set; }
[JsonInclude]
internal Guid Id { get; set; } = Guid.NewGuid();
public string? Name { get; set; } public string? Name { get; set; }
[JsonInclude] [JsonInclude]
internal bool IsAvailable { get; set; } internal Guid Id { get; set; } = Guid.NewGuid();
[JsonInclude]
internal bool Enabled { get; set; }
} }
public class WidgetConfiguration<TConfiguration>; public class WidgetConfiguration<TConfiguration>;
@@ -8,7 +8,7 @@ public class WidgetConfigurationHandler(IValue<WidgetAvailability> widgetAvailab
{ {
if (notification.Configuration is WidgetConfiguration configuration) if (notification.Configuration is WidgetConfiguration configuration)
{ {
await widgetAvailability.SetAsync(args => args with { Value = configuration.IsAvailable }); await widgetAvailability.SetAsync(args => args with { Value = configuration.Enabled });
} }
} }
} }
+5 -3
View File
@@ -2,8 +2,9 @@
namespace Hyperbar.Widget; namespace Hyperbar.Widget;
public class WidgetExtensionHandler(IProxyServiceCollection<IWidgetBuilder> typedServices, public class WidgetExtensionHandler(IServiceProvider provider,
IServiceProvider provider) : IMediator mediator,
IProxyServiceCollection<IWidgetBuilder> typedServices) :
INotificationHandler<Created<WidgetExtension>> INotificationHandler<Created<WidgetExtension>>
{ {
public async Task Handle(Created<WidgetExtension> notification, public async Task Handle(Created<WidgetExtension> notification,
@@ -21,7 +22,8 @@ public class WidgetExtensionHandler(IProxyServiceCollection<IWidgetBuilder> type
}); });
IWidgetHost host = builder.Build(); IWidgetHost host = builder.Build();
await host.InitializeAsync(); await mediator.PublishAsync(new Created<IWidgetHost>(host),
cancellationToken);
} }
} }
} }
@@ -1,7 +1,7 @@
namespace Hyperbar.Widget; namespace Hyperbar.Widget;
public class WidgetExtensionInitializer(IMediator mediator) : public class WidgetExtensionInitializer(IMediator mediator) :
IInitializer IInitialization
{ {
public async Task InitializeAsync() => public async Task InitializeAsync() =>
await mediator.PublishAsync<Enumerate<WidgetExtension>>(); await mediator.PublishAsync<Enumerate<WidgetExtension>>();
+22 -29
View File
@@ -1,59 +1,52 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Hyperbar.Widget; namespace Hyperbar.Widget;
public class WidgetHost : public sealed class WidgetHost :
INotificationHandler<Changed<WidgetAvailability>>,
IWidgetHost IWidgetHost
{ {
private readonly IEnumerable<IInitializer> initializers; private readonly IHost host;
private readonly IMediator mediator; private readonly IMediator mediator;
private readonly IProxyService<IMediator> proxyMediator; private readonly IProxyService<IMediator> proxyMediator;
private readonly IServiceProvider services;
public WidgetHost(IServiceProvider services, public WidgetHost(IHost host,
IMediator mediator, IMediator mediator,
IEnumerable<IInitializer> initializers,
IProxyService<IMediator> proxyMediator) IProxyService<IMediator> proxyMediator)
{ {
this.services = services; this.host = host;
this.mediator = mediator; this.mediator = mediator;
this.initializers = initializers;
this.proxyMediator = proxyMediator; this.proxyMediator = proxyMediator;
mediator.Subscribe(this); mediator.Subscribe(this);
} }
public WidgetConfiguration Configuration => public WidgetConfiguration Configuration =>
services.GetRequiredService<WidgetConfiguration>(); Services.GetRequiredService<WidgetConfiguration>();
public IServiceProvider Services => services; public IServiceProvider Services => host.Services;
public async Task Handle(Changed<WidgetAvailability> notification, public void Dispose()
CancellationToken cancellationToken)
{ {
if (notification.Value is WidgetAvailability widgetAvailability)
{
if (widgetAvailability.Value)
{
await StartAsync();
}
}
} }
public async Task InitializeAsync() public async Task StartAsync(CancellationToken cancellationToken = default)
{ {
foreach (IInitializer initializer in initializers) await host.StartAsync(cancellationToken);
{
await initializer.InitializeAsync();
}
}
private async Task StartAsync()
{
if (proxyMediator.Proxy is IMediator mediator) if (proxyMediator.Proxy is IMediator mediator)
{ {
await mediator.PublishAsync(new Started<IWidgetHost>(this)); await mediator.PublishAsync(new Started<IWidgetHost>(this),
cancellationToken);
} }
await this.mediator.PublishAsync(new Started<IWidgetHost>(this),
cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken = default)
{
await host.StopAsync(cancellationToken);
} }
} }
+21 -12
View File
@@ -3,25 +3,34 @@
namespace Hyperbar.Widget; namespace Hyperbar.Widget;
public class WidgetHostHandler(IMediator mediator) : public class WidgetHostHandler(IMediator mediator) :
INotificationHandler<Started<IWidgetHost>>, INotificationHandler<Created<IWidgetHost>>
INotificationHandler<Stopped<IWidgetHost>>
{ {
public async Task Handle(Started<IWidgetHost> notification, //public async Task Handle(Started<IWidgetHost> notification,
// CancellationToken cancellationToken)
//{
// if (notification.Value is IWidgetHost host)
// {
// if (host.Services.GetService<IWidgetViewModel>() is IWidgetViewModel viewModel)
// {
// await mediator.PublishAsync(new Created<IWidgetViewModel>(viewModel),
// nameof(WidgetViewModel), cancellationToken);
// }
// }
//}
public async Task Handle(Created<IWidgetHost> notification,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (notification.Value is IWidgetHost host) if (notification.Value is IWidgetHost host)
{ {
if (host.Services.GetService<IWidgetViewModel>() is IWidgetViewModel viewModel) if (host.Services.GetServices<IInitialization>() is
IEnumerable<IInitialization> initializations)
{ {
await mediator.PublishAsync(new Created<IWidgetViewModel>(viewModel), foreach (IInitialization initialization in initializations)
nameof(WidgetViewModel), cancellationToken); {
await initialization.InitializeAsync();
}
} }
} }
} }
public Task Handle(Stopped<IWidgetHost> notification,
CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
} }
+1 -1
View File
@@ -1,7 +1,7 @@
namespace Hyperbar.Widget; namespace Hyperbar.Widget;
public class WidgetMonitor : public class WidgetMonitor :
IInitializer IInitialization
{ {
public Task InitializeAsync() public Task InitializeAsync()
{ {
+27
View File
@@ -0,0 +1,27 @@
using Microsoft.Extensions.Hosting;
namespace Hyperbar.Widget;
public class WidgetService :
IHostedService
{
private readonly IEnumerable<IInitialization> initializers;
public WidgetService(IEnumerable<IInitialization> initializers)
{
this.initializers = initializers;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
foreach (IInitialization initializer in initializers)
{
await initializer.InitializeAsync();
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
+1 -1
View File
@@ -46,7 +46,7 @@ public partial class App :
args.Placement = DesktopBarPlacemenet.Top; args.Placement = DesktopBarPlacemenet.Top;
}); });
services.AddTransient<IInitializer, AppInitializer>(); services.AddTransient<IInitialization, AppInitializer>();
services.AddSingleton<DesktopBar>(); services.AddSingleton<DesktopBar>();
}) })
@@ -9,7 +9,7 @@ public class AppInitializer([FromKeyedServices(nameof(WidgetViewModel))] WidgetB
[FromKeyedServices(nameof(WidgetViewModel))] WidgetViewModel viewModel, [FromKeyedServices(nameof(WidgetViewModel))] WidgetViewModel viewModel,
DesktopBar desktopFlyout, DesktopBar desktopFlyout,
AppConfiguration configuration) : AppConfiguration configuration) :
IInitializer IInitialization
{ {
public Task InitializeAsync() public Task InitializeAsync()
{ {
@@ -5,7 +5,7 @@ public class ConfigurationInitializer<TConfiguration>(IConfigurationMonitor<TCon
IConfigurationWriter<TConfiguration> writer, IConfigurationWriter<TConfiguration> writer,
IConfigurationFactory<TConfiguration> factory) : IConfigurationFactory<TConfiguration> factory) :
IConfigurationInitializer<TConfiguration>, IConfigurationInitializer<TConfiguration>,
IInitializer IInitialization
where TConfiguration : where TConfiguration :
class class
{ {
@@ -2,6 +2,6 @@
namespace Hyperbar; namespace Hyperbar;
public interface IConfigurationMonitor<TConfiguration> : public interface IConfigurationMonitor<TConfiguration> :
IInitializer IInitialization
where TConfiguration : where TConfiguration :
class; class;
@@ -103,7 +103,7 @@ public static class IServiceCollectionExtensions
services.AddTransient<IConfigurationFactory<TConfiguration>>(provider => new ConfigurationFactory<TConfiguration>(() => services.AddTransient<IConfigurationFactory<TConfiguration>>(provider => new ConfigurationFactory<TConfiguration>(() =>
configuration ?? provider.GetRequiredService<TConfiguration>())); configuration ?? provider.GetRequiredService<TConfiguration>()));
services.AddTransient<IInitializer, ConfigurationInitializer<TConfiguration>>(); services.AddTransient<IInitialization, ConfigurationInitializer<TConfiguration>>();
services.AddTransient<IConfigurationInitializer<TConfiguration>, ConfigurationInitializer<TConfiguration>>(); services.AddTransient<IConfigurationInitializer<TConfiguration>, ConfigurationInitializer<TConfiguration>>();
services.AddTransient<IWritableConfiguration<TConfiguration>, WritableConfiguration<TConfiguration>>(); services.AddTransient<IWritableConfiguration<TConfiguration>, WritableConfiguration<TConfiguration>>();
+2 -2
View File
@@ -2,12 +2,12 @@
namespace Hyperbar; namespace Hyperbar;
public class AppService(IEnumerable<IInitializer> initializers) : public class AppService(IEnumerable<IInitialization> initializers) :
IHostedService IHostedService
{ {
public async Task StartAsync(CancellationToken cancellationToken) public async Task StartAsync(CancellationToken cancellationToken)
{ {
foreach (IInitializer initializer in initializers) foreach (IInitialization initializer in initializers)
{ {
await initializer.InitializeAsync(); await initializer.InitializeAsync();
} }
+1 -1
View File
@@ -2,7 +2,7 @@
namespace Hyperbar; namespace Hyperbar;
public interface IInitialization public interface IInitialization2
{ {
ICommand Initialize { get; } ICommand Initialize { get; }
+1 -1
View File
@@ -1,6 +1,6 @@
namespace Hyperbar; namespace Hyperbar;
public interface IInitializer public interface IInitialization
{ {
Task InitializeAsync(); Task InitializeAsync();
} }