diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index 0c62553d4..df21cdfd2 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -35,15 +35,13 @@ + - - - diff --git a/src/Artemis.Core/DryIoc/CoreModule.cs b/src/Artemis.Core/DryIoc/CoreModule.cs new file mode 100644 index 000000000..0c41cb524 --- /dev/null +++ b/src/Artemis.Core/DryIoc/CoreModule.cs @@ -0,0 +1,48 @@ +using System; +using System.Reflection; +using Artemis.Core.DryIoc.Factories; +using Artemis.Core.Services; +using Artemis.Storage; +using Artemis.Storage.Migrations.Interfaces; +using Artemis.Storage.Repositories.Interfaces; +using DryIoc; + +namespace Artemis.Core.DryIoc; + +/// +/// The main of the Artemis Core that binds all services +/// +public class CoreModule : IModule +{ + /// + public void Load(IRegistrator builder) + { + Assembly coreAssembly = typeof(IArtemisService).Assembly; + Assembly storageAssembly = typeof(IRepository).Assembly; + + // Bind all services as singletons + builder.RegisterMany(new[] {coreAssembly}, type => type.IsAssignableTo(), Reuse.Singleton); + builder.RegisterMany(new[] {coreAssembly}, type => type.IsAssignableTo(), Reuse.Singleton, setup: Setup.With(condition: HasAccessToProtectedService)); + + // Bind storage + builder.RegisterDelegate(() => StorageManager.CreateRepository(Constants.DataFolder), Reuse.Singleton); + builder.Register(Reuse.Singleton); + builder.RegisterMany(new[] {storageAssembly}, type => type.IsAssignableTo(), Reuse.Singleton); + + // Bind migrations + builder.RegisterMany(new[] { storageAssembly }, type => type.IsAssignableTo(), Reuse.Singleton, nonPublicServiceTypes: true); + + builder.Register(Reuse.Singleton); + builder.Register(made: Made.Of(_ => ServiceInfo.Of(), factory => factory.CreatePluginSettings(Arg.Index(0)), r => r.Parent.ImplementationType)); + builder.Register(Reuse.Singleton); + builder.Register(made: Made.Of(_ => ServiceInfo.Of(), f => f.CreateLogger(Arg.Index(0)), r => r.Parent.ImplementationType)); + } + + private bool HasAccessToProtectedService(Request request) + { + // Plugin assembly locations may not be set for some reason, that case it's also not allowed >:( + return request.Parent.ImplementationType != null && + !string.IsNullOrWhiteSpace(request.Parent.ImplementationType.Assembly.Location) && + !request.Parent.ImplementationType.Assembly.Location.StartsWith(Constants.PluginsFolder); + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Ninject/LoggerProvider.cs b/src/Artemis.Core/DryIoc/Factories/LoggerFactory.cs similarity index 64% rename from src/Artemis.Core/Ninject/LoggerProvider.cs rename to src/Artemis.Core/DryIoc/Factories/LoggerFactory.cs index 5759557c6..ba5e90db7 100644 --- a/src/Artemis.Core/Ninject/LoggerProvider.cs +++ b/src/Artemis.Core/DryIoc/Factories/LoggerFactory.cs @@ -1,17 +1,16 @@ -using System; +using System; using System.IO; -using Ninject.Activation; using Serilog; using Serilog.Core; using Serilog.Events; -namespace Artemis.Core.Ninject; +namespace Artemis.Core.DryIoc.Factories; -internal class LoggerProvider : Provider +internal class LoggerFactory : ILoggerFactory { internal static readonly LoggingLevelSwitch LoggingLevelSwitch = new(LogEventLevel.Verbose); - private static readonly ILogger Logger = new LoggerConfiguration() + internal static readonly ILogger Logger = new LoggerConfiguration() .Enrich.FromLogContext() .WriteTo.File(Path.Combine(Constants.LogsFolder, "Artemis log-.log"), rollingInterval: RollingInterval.Day, @@ -24,12 +23,10 @@ internal class LoggerProvider : Provider .MinimumLevel.ControlledBy(LoggingLevelSwitch) .CreateLogger(); - protected override ILogger CreateInstance(IContext context) + /// + public ILogger CreateLogger(Type type) { - Type? requestingType = context.Request.ParentContext?.Plan?.Type; - if (requestingType != null) - return Logger.ForContext(requestingType); - return Logger; + return Logger.ForContext(type); } } @@ -40,4 +37,9 @@ internal class ArtemisSink : ILogEventSink { LogStore.Emit(logEvent); } +} + +internal interface ILoggerFactory +{ + ILogger CreateLogger(Type type); } \ No newline at end of file diff --git a/src/Artemis.Core/Ninject/PluginSettingsProvider.cs b/src/Artemis.Core/DryIoc/Factories/PluginSettingsFactory.cs similarity index 51% rename from src/Artemis.Core/Ninject/PluginSettingsProvider.cs rename to src/Artemis.Core/DryIoc/Factories/PluginSettingsFactory.cs index 3fb83fda8..7684b2b43 100644 --- a/src/Artemis.Core/Ninject/PluginSettingsProvider.cs +++ b/src/Artemis.Core/DryIoc/Factories/PluginSettingsFactory.cs @@ -1,35 +1,26 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Artemis.Core.Services; using Artemis.Storage.Repositories.Interfaces; -using Ninject.Activation; -namespace Artemis.Core.Ninject; +namespace Artemis.Core.DryIoc.Factories; -// TODO: Investigate if this can't just be set as a constant on the plugin child kernel -internal class PluginSettingsProvider : Provider +internal class PluginSettingsFactory : IPluginSettingsFactory { private static readonly List PluginSettings = new(); private readonly IPluginManagementService _pluginManagementService; private readonly IPluginRepository _pluginRepository; - public PluginSettingsProvider(IPluginRepository pluginRepository, IPluginManagementService pluginManagementService) + public PluginSettingsFactory(IPluginRepository pluginRepository, IPluginManagementService pluginManagementService) { _pluginRepository = pluginRepository; _pluginManagementService = pluginManagementService; } - protected override PluginSettings CreateInstance(IContext context) + public PluginSettings CreatePluginSettings(Type type) { - IRequest parentRequest = context.Request.ParentRequest; - if (parentRequest == null) - throw new ArtemisCoreException("PluginSettings couldn't be injected, failed to get the injection parent request"); - - // First try by PluginInfo parameter - Plugin? plugin = parentRequest.Parameters.FirstOrDefault(p => p.Name == "Plugin")?.GetValue(context, null) as Plugin; - // Fall back to assembly based detection - if (plugin == null) - plugin = _pluginManagementService.GetPluginByAssembly(parentRequest.Service.Assembly); + Plugin? plugin = _pluginManagementService.GetPluginByAssembly(type.Assembly); if (plugin == null) throw new ArtemisCoreException("PluginSettings can only be injected with the PluginInfo parameter provided " + @@ -46,4 +37,9 @@ internal class PluginSettingsProvider : Provider return settings; } } +} + +internal interface IPluginSettingsFactory +{ + PluginSettings CreatePluginSettings(Type type); } \ No newline at end of file diff --git a/src/Artemis.Core/DryIoc/IModule.cs b/src/Artemis.Core/DryIoc/IModule.cs new file mode 100644 index 000000000..08b3247a9 --- /dev/null +++ b/src/Artemis.Core/DryIoc/IModule.cs @@ -0,0 +1,15 @@ +using DryIoc; + +namespace Artemis.Core.DryIoc; + +/** + * Represents a service module. + */ +public interface IModule +{ + /// + /// Registers the services provided by the module. + /// + /// The builder to register the services with. + void Load(IRegistrator builder); +} \ No newline at end of file diff --git a/src/Artemis.Core/DryIoc/PluginModule.cs b/src/Artemis.Core/DryIoc/PluginModule.cs new file mode 100644 index 000000000..d6ae8dd07 --- /dev/null +++ b/src/Artemis.Core/DryIoc/PluginModule.cs @@ -0,0 +1,26 @@ +using System; +using System.Linq; +using Artemis.Core.Services; +using DryIoc; + +namespace Artemis.Core.DryIoc; + +internal class PluginModule : IModule +{ + public PluginModule(Plugin plugin) + { + Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin)); + } + + public Plugin Plugin { get; } + + /// + public void Load(IRegistrator builder) + { + builder.RegisterInstance(Plugin, setup: Setup.With(preventDisposal: true)); + + // Bind plugin service interfaces, DryIoc expects at least one match when calling RegisterMany so ensure there is something to register first + if (Plugin.Assembly != null && Plugin.Assembly.GetTypes().Any(t => t.IsAssignableTo())) + builder.RegisterMany(new[] {Plugin.Assembly}, type => type.IsAssignableTo(), Reuse.Singleton, ifAlreadyRegistered: IfAlreadyRegistered.Keep); + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/ProfileCategory.cs b/src/Artemis.Core/Models/Profile/ProfileCategory.cs index 603bfdf08..13a3e2f4b 100644 --- a/src/Artemis.Core/Models/Profile/ProfileCategory.cs +++ b/src/Artemis.Core/Models/Profile/ProfileCategory.cs @@ -10,6 +10,11 @@ namespace Artemis.Core; /// public class ProfileCategory : CorePropertyChanged, IStorageModel { + /// + /// Represents an empty profile category. + /// + public static readonly ProfileCategory Empty = new("Empty", -1); + private readonly List _profileConfigurations = new(); private bool _isCollapsed; private bool _isSuspended; diff --git a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs index b349acfd1..06a2090d3 100644 --- a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs +++ b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs @@ -11,6 +11,11 @@ namespace Artemis.Core; /// public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable { + /// + /// Represents an empty profile. + /// + public static readonly ProfileConfiguration Empty = new(ProfileCategory.Empty, "Empty", "Empty"); + private ActivationBehaviour _activationBehaviour; private bool _activationConditionMet; private ProfileCategory _category; diff --git a/src/Artemis.Core/Ninject/CoreModule.cs b/src/Artemis.Core/Ninject/CoreModule.cs deleted file mode 100644 index 14d1c08dc..000000000 --- a/src/Artemis.Core/Ninject/CoreModule.cs +++ /dev/null @@ -1,83 +0,0 @@ -using Artemis.Core.Services; -using Artemis.Storage; -using Artemis.Storage.Migrations.Interfaces; -using Artemis.Storage.Repositories.Interfaces; -using LiteDB; -using Ninject.Activation; -using Ninject.Extensions.Conventions; -using Ninject.Modules; -using Ninject.Planning.Bindings.Resolvers; -using Serilog; - -namespace Artemis.Core.Ninject; - -/// -/// The main of the Artemis Core that binds all services -/// -public class CoreModule : NinjectModule -{ - /// - public override void Load() - { - if (Kernel == null) - throw new ArtemisCoreException("Failed to bind Ninject Core module, kernel is null."); - - Kernel.Components.Remove(); - - // Bind all services as singletons - Kernel.Bind(x => - { - x.FromThisAssembly() - .IncludingNonPublicTypes() - .SelectAllClasses() - .InheritedFrom() - .BindAllInterfaces() - .Configure(c => c.InSingletonScope()); - }); - - // Bind all protected services as singletons - Kernel.Bind(x => - { - x.FromThisAssembly() - .IncludingNonPublicTypes() - .SelectAllClasses() - .InheritedFrom() - .BindAllInterfaces() - .Configure(c => c.When(HasAccessToProtectedService).InSingletonScope()); - }); - - Kernel.Bind().ToMethod(_ => StorageManager.CreateRepository(Constants.DataFolder)).InSingletonScope(); - Kernel.Bind().ToSelf().InSingletonScope(); - - // Bind all migrations as singletons - Kernel.Bind(x => - { - x.FromAssemblyContaining() - .IncludingNonPublicTypes() - .SelectAllClasses() - .InheritedFrom() - .BindAllInterfaces() - .Configure(c => c.InSingletonScope()); - }); - - // Bind all repositories as singletons - Kernel.Bind(x => - { - x.FromAssemblyContaining() - .IncludingNonPublicTypes() - .SelectAllClasses() - .InheritedFrom() - .BindAllInterfaces() - .Configure(c => c.InSingletonScope()); - }); - - Kernel.Bind().ToProvider(); - Kernel.Bind().ToProvider(); - Kernel.Bind().ToSelf(); - } - - private bool HasAccessToProtectedService(IRequest r) - { - return r.ParentRequest != null && !r.ParentRequest.Service.Assembly.Location.StartsWith(Constants.PluginsFolder); - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Ninject/PluginModule.cs b/src/Artemis.Core/Ninject/PluginModule.cs deleted file mode 100644 index 612685567..000000000 --- a/src/Artemis.Core/Ninject/PluginModule.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using Artemis.Core.Services; -using Ninject.Extensions.Conventions; -using Ninject.Modules; -using Ninject.Planning.Bindings.Resolvers; - -namespace Artemis.Core.Ninject; - -internal class PluginModule : NinjectModule -{ - public PluginModule(Plugin plugin) - { - Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin)); - } - - public Plugin Plugin { get; } - - public override void Load() - { - if (Kernel == null) - throw new ArtemisCoreException("Failed to bind plugin child module, kernel is null."); - - Kernel.Components.Remove(); - - Kernel.Bind().ToConstant(Plugin).InTransientScope(); - - // Bind plugin service interfaces - Kernel.Bind(x => - { - x.From(Plugin.Assembly) - .IncludingNonPublicTypes() - .SelectAllClasses() - .InheritedFrom() - .BindAllInterfaces() - .Configure(c => c.InSingletonScope()); - }); - - // Plugin developers may not use an interface so bind the plugin services to themselves - // Sadly if they do both, the kernel will treat the interface and the base type as two different singletons - // perhaps we can avoid that, but I'm not sure how - Kernel.Bind(x => - { - x.From(Plugin.Assembly) - .IncludingNonPublicTypes() - .SelectAllClasses() - .InheritedFrom() - .BindToSelf() - .Configure(c => c.InSingletonScope()); - }); - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Ninject/SettingsServiceProvider.cs b/src/Artemis.Core/Ninject/SettingsServiceProvider.cs deleted file mode 100644 index a7c022ae6..000000000 --- a/src/Artemis.Core/Ninject/SettingsServiceProvider.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Artemis.Core.Services; -using Ninject; -using Ninject.Activation; - -namespace Artemis.Core.Ninject; - -internal class SettingsServiceProvider : Provider -{ - private readonly SettingsService _instance; - - public SettingsServiceProvider(IKernel kernel) - { - // This is not lazy, but the core is always going to be using this anyway - _instance = kernel.Get(); - } - - protected override ISettingsService CreateInstance(IContext context) - { - IRequest parentRequest = context.Request.ParentRequest; - if (parentRequest == null || typeof(PluginFeature).IsAssignableFrom(parentRequest.Service)) - throw new ArtemisPluginException($"SettingsService can not be injected into a plugin. Inject {nameof(PluginSettings)} instead."); - - return _instance; - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs b/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs index 67d5ce8d4..0c51a5cf4 100644 --- a/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs +++ b/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs @@ -1,9 +1,7 @@ using System; using System.IO; using System.Linq; -using Ninject; using RGB.NET.Core; -using Serilog; namespace Artemis.Core.DeviceProviders; @@ -26,14 +24,7 @@ public abstract class DeviceProvider : PluginFeature /// The RGB.NET device provider backing this Artemis device provider /// public IRGBDeviceProvider RgbDeviceProvider { get; } - - /// - /// TODO: Make internal while still injecting. - /// A logger used by the device provider internally, ignore this - /// - [Inject] - public ILogger? Logger { get; set; } - + /// /// A boolean indicating whether this device provider detects the physical layout of connected keyboards. /// diff --git a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs index 4279b2810..3e245f9c4 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs +++ b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs @@ -1,6 +1,5 @@ using System; using Artemis.Storage.Entities.Profile; -using Ninject; namespace Artemis.Core.LayerBrushes; @@ -63,7 +62,7 @@ public class LayerBrushDescriptor if (layer == null) throw new ArgumentNullException(nameof(layer)); - BaseLayerBrush brush = (BaseLayerBrush) Provider.Plugin.Kernel!.Get(LayerBrushType); + BaseLayerBrush brush = (BaseLayerBrush) Provider.Plugin.Resolve(LayerBrushType); brush.Layer = layer; brush.Descriptor = this; brush.LayerBrushEntity = entity ?? new LayerBrushEntity {ProviderId = Provider.Id, BrushType = LayerBrushType.FullName}; diff --git a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs b/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs index 196461c45..93ea5e0ed 100644 --- a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs +++ b/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs @@ -1,7 +1,6 @@ using System; using Artemis.Core.LayerEffects.Placeholder; using Artemis.Storage.Entities.Profile; -using Ninject; namespace Artemis.Core.LayerEffects; @@ -80,7 +79,7 @@ public class LayerEffectDescriptor if (LayerEffectType == null) throw new ArtemisCoreException("Cannot create an instance of a layer effect because this descriptor is not a placeholder but is still missing its LayerEffectType"); - BaseLayerEffect effect = (BaseLayerEffect) Provider.Plugin.Kernel!.Get(LayerEffectType); + BaseLayerEffect effect = (BaseLayerEffect) Provider.Plugin.Resolve(LayerEffectType); effect.ProfileElement = renderElement; effect.Descriptor = this; if (entity != null) diff --git a/src/Artemis.Core/Plugins/Plugin.cs b/src/Artemis.Core/Plugins/Plugin.cs index 4c0d2cfb9..45b469146 100644 --- a/src/Artemis.Core/Plugins/Plugin.cs +++ b/src/Artemis.Core/Plugins/Plugin.cs @@ -7,8 +7,8 @@ using System.Linq; using System.Reflection; using Artemis.Core.DeviceProviders; using Artemis.Storage.Entities.Plugins; +using DryIoc; using McMaster.NETCore.Plugins; -using Ninject; namespace Artemis.Core; @@ -88,9 +88,9 @@ public class Plugin : CorePropertyChanged, IDisposable public PluginBootstrapper? Bootstrapper { get; internal set; } /// - /// The Ninject kernel of the plugin + /// Gets the IOC container of the plugin, only use this for advanced IOC operations, otherwise see and /// - public IKernel? Kernel { get; internal set; } + public IContainer? Container { get; internal set; } /// /// The PluginLoader backing this plugin @@ -165,16 +165,66 @@ public class Plugin : CorePropertyChanged, IDisposable } /// - /// Gets an instance of the specified service using the plugins dependency injection container. - /// Note: To use parameters reference Ninject and use directly. + /// Gets an instance of the specified service using the plugins dependency injection container. /// + /// Arguments to supply to the service. /// The service to resolve. /// An instance of the service. - public T Get() + /// + public T Resolve(params object?[] arguments) { - if (Kernel == null) - throw new ArtemisPluginException("Cannot use Get before the plugin finished loading"); - return Kernel.Get(); + if (Container == null) + throw new ArtemisPluginException("Cannot use Resolve before the plugin finished loading"); + return Container.Resolve(args: arguments); + } + + /// + /// Gets an instance of the specified service using the plugins dependency injection container. + /// + /// The type of service to resolve. + /// Arguments to supply to the service. + /// An instance of the service. + /// + public object Resolve(Type type, params object?[] arguments) + { + if (Container == null) + throw new ArtemisPluginException("Cannot use Resolve before the plugin finished loading"); + return Container.Resolve(type, args: arguments); + } + + /// + /// Registers service of type implemented by type. + /// + /// The scope in which the service should live, if you are not sure leave it on singleton. + /// The service to register. + /// The implementation of the service to register. + public void Register(PluginServiceScope scope = PluginServiceScope.Singleton) where TImplementation : TService + { + IReuse reuse = scope switch + { + PluginServiceScope.Transient => Reuse.Transient, + PluginServiceScope.Singleton => Reuse.Singleton, + PluginServiceScope.Scoped => Reuse.Scoped, + _ => throw new ArgumentOutOfRangeException(nameof(scope), scope, null) + }; + Container.Register(reuse); + } + + /// + /// Registers implementation type with itself as service type. + /// + /// The scope in which the service should live, if you are not sure leave it on singleton. + /// The implementation of the service to register. + public void Register(PluginServiceScope scope = PluginServiceScope.Singleton) + { + IReuse reuse = scope switch + { + PluginServiceScope.Transient => Reuse.Transient, + PluginServiceScope.Singleton => Reuse.Singleton, + PluginServiceScope.Scoped => Reuse.Scoped, + _ => throw new ArgumentOutOfRangeException(nameof(scope), scope, null) + }; + Container.Register(reuse); } /// @@ -218,7 +268,7 @@ public class Plugin : CorePropertyChanged, IDisposable feature.Instance?.Dispose(); SetEnabled(false); - Kernel?.Dispose(); + Container?.Dispose(); PluginLoader?.Dispose(); GC.Collect(); @@ -340,4 +390,26 @@ public class Plugin : CorePropertyChanged, IDisposable Dispose(true); GC.SuppressFinalize(this); } +} + +/// +/// Represents a scope in which a plugin service is injected by the IOC container. +/// +public enum PluginServiceScope +{ + /// + /// Services in this scope are never reused, a new instance is injected each time. + /// + Transient, + + /// + /// Services in this scope are reused for as long as the plugin lives, the same instance is injected each time. + /// + Singleton, + + /// + /// Services in this scope are reused within a container scope, this is an advanced setting you shouldn't need. + /// To learn more see the DryIoc docs. + /// + Scoped } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/PluginFeatureInfo.cs b/src/Artemis.Core/Plugins/PluginFeatureInfo.cs index b1dfbdc7b..ccd9f4c9f 100644 --- a/src/Artemis.Core/Plugins/PluginFeatureInfo.cs +++ b/src/Artemis.Core/Plugins/PluginFeatureInfo.cs @@ -1,10 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Artemis.Core.DeviceProviders; -using Artemis.Core.LayerBrushes; -using Artemis.Core.LayerEffects; -using Artemis.Core.Modules; using Artemis.Storage.Entities.Plugins; using Humanizer; using Newtonsoft.Json; diff --git a/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs b/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs index be52ac01f..0795ab261 100644 --- a/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs +++ b/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs @@ -1,9 +1,8 @@ using System; using System.Threading.Tasks; using System.Timers; +using Artemis.Core.DryIoc.Factories; using Artemis.Core.Modules; -using Artemis.Core.Services; -using Ninject; using Serilog; namespace Artemis.Core; @@ -11,7 +10,7 @@ namespace Artemis.Core; /// /// Represents a registration for a timed plugin update /// -public class TimedUpdateRegistration : IDisposable +public sealed class TimedUpdateRegistration : IDisposable { private readonly object _lock = new(); private readonly ILogger _logger; @@ -21,9 +20,7 @@ public class TimedUpdateRegistration : IDisposable internal TimedUpdateRegistration(PluginFeature feature, TimeSpan interval, Action action, string? name) { - if (CoreService.Kernel == null) - throw new ArtemisCoreException("Cannot create a TimedUpdateRegistration before initializing the Core"); - _logger = CoreService.Kernel.Get(); + _logger = LoggerFactory.Logger.ForContext(); Feature = feature; Interval = interval; @@ -38,9 +35,7 @@ public class TimedUpdateRegistration : IDisposable internal TimedUpdateRegistration(PluginFeature feature, TimeSpan interval, Func asyncAction, string? name) { - if (CoreService.Kernel == null) - throw new ArtemisCoreException("Cannot create a TimedUpdateRegistration before initializing the Core"); - _logger = CoreService.Kernel.Get(); + _logger = LoggerFactory.Logger.ForContext(); Feature = feature; Interval = interval; @@ -125,33 +120,13 @@ public class TimedUpdateRegistration : IDisposable } /// - public sealed override string ToString() + public override string ToString() { if (Interval.TotalSeconds >= 1) return $"{Name} ({Interval.TotalSeconds} sec)"; return $"{Name} ({Interval.TotalMilliseconds} ms)"; } - /// - /// Releases the unmanaged resources used by the object and optionally releases the managed resources. - /// - /// - /// to release both managed and unmanaged resources; - /// to release only unmanaged resources. - /// - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - Stop(); - - Feature.Enabled -= FeatureOnEnabled; - Feature.Disabled -= FeatureOnDisabled; - - _disposed = true; - } - } - private void TimerOnElapsed(object? sender, ElapsedEventArgs e) { if (!Feature.IsEnabled) @@ -204,9 +179,12 @@ public class TimedUpdateRegistration : IDisposable /// public void Dispose() { - Dispose(true); - Feature.Profiler.ClearMeasurements(ToString()); + Stop(); - GC.SuppressFinalize(this); + Feature.Enabled -= FeatureOnEnabled; + Feature.Disabled -= FeatureOnDisabled; + + _disposed = true; + Feature.Profiler.ClearMeasurements(ToString()); } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index 81d8232ab..933d3d3c3 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; -using Artemis.Core.Ninject; +using Artemis.Core.DryIoc.Factories; using Artemis.Core.ScriptingProviders; using Artemis.Storage; +using DryIoc; using HidSharp; -using Ninject; using RGB.NET.Core; using Serilog; using Serilog.Events; @@ -20,7 +20,6 @@ namespace Artemis.Core.Services; /// internal class CoreService : ICoreService { - internal static IKernel? Kernel; private readonly Stopwatch _frameStopWatch; private readonly ILogger _logger; private readonly PluginSetting _loggingLevel; @@ -36,7 +35,7 @@ internal class CoreService : ICoreService private DateTime _lastFrameRateSample; // ReSharper disable UnusedParameter.Local - public CoreService(IKernel kernel, + public CoreService(IContainer container, ILogger logger, StorageMigrationService _1, // injected to ensure migration runs early ISettingsService settingsService, @@ -47,8 +46,7 @@ internal class CoreService : ICoreService IScriptingService scriptingService, IProcessMonitorService _2) { - Kernel = kernel; - Constants.CorePlugin.Kernel = kernel; + Constants.CorePlugin.Container = container; _logger = logger; _pluginManagementService = pluginManagementService; @@ -85,19 +83,19 @@ internal class CoreService : ICoreService if (parts.Length == 2 && Enum.TryParse(typeof(LogEventLevel), parts[1], true, out object? logLevelArgument)) { _logger.Information("Setting logging level to {loggingLevel} from startup argument", (LogEventLevel) logLevelArgument!); - LoggerProvider.LoggingLevelSwitch.MinimumLevel = (LogEventLevel) logLevelArgument; + LoggerFactory.LoggingLevelSwitch.MinimumLevel = (LogEventLevel) logLevelArgument; } else { _logger.Warning("Failed to set log level from startup argument {argument}", argument); _logger.Information("Setting logging level to {loggingLevel}", _loggingLevel.Value); - LoggerProvider.LoggingLevelSwitch.MinimumLevel = _loggingLevel.Value; + LoggerFactory.LoggingLevelSwitch.MinimumLevel = _loggingLevel.Value; } } else { _logger.Information("Setting logging level to {loggingLevel}", _loggingLevel.Value); - LoggerProvider.LoggingLevelSwitch.MinimumLevel = _loggingLevel.Value; + LoggerFactory.LoggingLevelSwitch.MinimumLevel = _loggingLevel.Value; } } @@ -195,12 +193,6 @@ internal class CoreService : ICoreService public bool ProfileRenderingDisabled { get; set; } public bool IsElevated { get; set; } - public void Dispose() - { - // Dispose services - _pluginManagementService.Dispose(); - } - public bool IsInitialized { get; set; } public void Initialize() diff --git a/src/Artemis.Core/Services/Interfaces/ICoreService.cs b/src/Artemis.Core/Services/Interfaces/ICoreService.cs index 66de54365..5830815ba 100644 --- a/src/Artemis.Core/Services/Interfaces/ICoreService.cs +++ b/src/Artemis.Core/Services/Interfaces/ICoreService.cs @@ -5,7 +5,7 @@ namespace Artemis.Core.Services; /// /// A service that initializes the Core and manages the render loop /// -public interface ICoreService : IArtemisService, IDisposable +public interface ICoreService : IArtemisService { /// /// Gets whether the or not the core has been initialized diff --git a/src/Artemis.Core/Services/NodeService.cs b/src/Artemis.Core/Services/NodeService.cs index f09b20d04..7cae6709b 100644 --- a/src/Artemis.Core/Services/NodeService.cs +++ b/src/Artemis.Core/Services/NodeService.cs @@ -5,8 +5,8 @@ using System.Reflection; using System.Security.Cryptography; using System.Text; using Artemis.Storage.Entities.Profile.Nodes; +using DryIoc; using Newtonsoft.Json; -using Ninject; using SkiaSharp; namespace Artemis.Core.Services; @@ -15,17 +15,17 @@ internal class NodeService : INodeService { #region Constants - private static readonly Type TYPE_NODE = typeof(INode); + private static readonly Type TypeNode = typeof(INode); #endregion - private readonly IKernel _kernel; + private readonly IContainer _container; #region Constructors - public NodeService(IKernel kernel) + public NodeService(IContainer container) { - _kernel = kernel; + _container = container; } #endregion @@ -69,7 +69,7 @@ internal class NodeService : INodeService if (plugin == null) throw new ArgumentNullException(nameof(plugin)); if (nodeType == null) throw new ArgumentNullException(nameof(nodeType)); - if (!TYPE_NODE.IsAssignableFrom(nodeType)) throw new ArgumentException("Node has to be a base type of the Node-Type.", nameof(nodeType)); + if (!TypeNode.IsAssignableFrom(nodeType)) throw new ArgumentException("Node has to be a base type of the Node-Type.", nameof(nodeType)); NodeAttribute? nodeAttribute = nodeType.GetCustomAttribute(); string name = nodeAttribute?.Name ?? nodeType.Name; @@ -106,8 +106,10 @@ internal class NodeService : INodeService private INode CreateNode(INodeScript script, NodeEntity? entity, Type nodeType) { - INode node = _kernel.Get(nodeType) as INode ?? throw new InvalidOperationException($"Node {nodeType} is not an INode"); - + INode node = _container.Resolve(nodeType) as INode ?? throw new InvalidOperationException($"Node {nodeType} is not an INode"); + if (node is Node concreteNode) + concreteNode.Container = _container; + if (entity != null) { node.X = entity.X; diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs index 1e113ab95..9565f6320 100644 --- a/src/Artemis.Core/Services/PluginManagementService.cs +++ b/src/Artemis.Core/Services/PluginManagementService.cs @@ -5,19 +5,15 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; -using System.Runtime.Loader; using System.Threading.Tasks; using Artemis.Core.DeviceProviders; -using Artemis.Core.Ninject; +using Artemis.Core.DryIoc; using Artemis.Storage.Entities.General; using Artemis.Storage.Entities.Plugins; using Artemis.Storage.Entities.Surface; using Artemis.Storage.Repositories.Interfaces; +using DryIoc; using McMaster.NETCore.Plugins; -using Ninject; -using Ninject.Extensions.ChildKernel; -using Ninject.Parameters; -using Ninject.Planning.Bindings.Resolvers; using RGB.NET.Core; using Serilog; @@ -29,7 +25,7 @@ namespace Artemis.Core.Services; internal class PluginManagementService : IPluginManagementService { private readonly IDeviceRepository _deviceRepository; - private readonly IKernel _kernel; + private readonly IContainer _container; private readonly ILogger _logger; private readonly IPluginRepository _pluginRepository; private readonly List _plugins; @@ -37,9 +33,9 @@ internal class PluginManagementService : IPluginManagementService private bool _disposed; private bool _isElevated; - public PluginManagementService(IKernel kernel, ILogger logger, IPluginRepository pluginRepository, IDeviceRepository deviceRepository, IQueuedActionRepository queuedActionRepository) + public PluginManagementService(IContainer container, ILogger logger, IPluginRepository pluginRepository, IDeviceRepository deviceRepository, IQueuedActionRepository queuedActionRepository) { - _kernel = kernel; + _container = container; _logger = logger; _pluginRepository = pluginRepository; _deviceRepository = deviceRepository; @@ -198,6 +194,10 @@ internal class PluginManagementService : IPluginManagementService public void Dispose() { + // Disposal happens manually before container disposal but the container doesn't know that so a 2nd call will be made + if (_disposed) + return; + _disposed = true; UnloadPlugins(); } @@ -340,11 +340,11 @@ internal class PluginManagementService : IPluginManagementService configure.IsUnloadable = true; configure.LoadInMemory = true; configure.PreferSharedTypes = true; - + // Resolving failed, try a loaded assembly but ignoring the version configure.DefaultContext.Resolving += (context, assemblyName) => context.Assemblies.FirstOrDefault(a => a.GetName().Name == assemblyName.Name); }); - + try { plugin.Assembly = plugin.PluginLoader.LoadDefaultAssembly(); @@ -406,7 +406,7 @@ internal class PluginManagementService : IPluginManagementService OnPluginLoaded(new PluginEventArgs(plugin)); return plugin; } - + public void EnablePlugin(Plugin plugin, bool saveState, bool ignorePluginLock) { if (!plugin.Info.IsCompatible) @@ -431,10 +431,17 @@ internal class PluginManagementService : IPluginManagementService if (!plugin.Info.ArePrerequisitesMet()) throw new ArtemisPluginPrerequisiteException(plugin.Info, "Cannot enable a plugin whose prerequisites aren't all met"); - // Create the Ninject child kernel and load the module - plugin.Kernel = new ChildKernel(_kernel, new PluginModule(plugin)); - // The kernel used by Core is unforgiving about missing bindings, no need to be so hard on plugin devs - plugin.Kernel.Components.Add(); + // Create a child container for the plugin, be a bit more forgiving about concrete types + plugin.Container = _container.CreateChild(newRules: _container.Rules.WithConcreteTypeDynamicRegistrations()); + try + { + new PluginModule(plugin).Load(plugin.Container); + } + catch (Exception e) + { + _logger.Error(e, "Failed to register plugin services for plugin {plugin}, skipping enabling", plugin); + return; + } OnPluginEnabling(new PluginEventArgs(plugin)); @@ -446,11 +453,8 @@ internal class PluginManagementService : IPluginManagementService { try { - plugin.Kernel.Bind(featureInfo.FeatureType).ToSelf().InSingletonScope(); - - // Include Plugin as a parameter for the PluginSettingsProvider - IParameter[] parameters = {new Parameter("Plugin", plugin, false)}; - PluginFeature instance = (PluginFeature) plugin.Kernel.Get(featureInfo.FeatureType, parameters); + plugin.Container.Register(featureInfo.FeatureType, reuse: Reuse.Singleton); + PluginFeature instance = (PluginFeature) plugin.Container.Resolve(featureInfo.FeatureType); // Get the PluginFeature attribute which contains extra info on the feature featureInfo.Instance = instance; @@ -526,8 +530,8 @@ internal class PluginManagementService : IPluginManagementService plugin.SetEnabled(false); - plugin.Kernel?.Dispose(); - plugin.Kernel = null; + plugin.Container?.Dispose(); + plugin.Container = null; GC.Collect(); GC.WaitForPendingFinalizers(); diff --git a/src/Artemis.Core/Services/RgbService.cs b/src/Artemis.Core/Services/RgbService.cs index a3471e729..753becc66 100644 --- a/src/Artemis.Core/Services/RgbService.cs +++ b/src/Artemis.Core/Services/RgbService.cs @@ -9,7 +9,7 @@ using Artemis.Core.Services.Models; using Artemis.Core.SkiaSharp; using Artemis.Storage.Entities.Surface; using Artemis.Storage.Repositories.Interfaces; -using Ninject; +using DryIoc; using RGB.NET.Core; using Serilog; @@ -20,31 +20,36 @@ namespace Artemis.Core.Services; /// internal class RgbService : IRgbService { - private readonly IDeviceRepository _deviceRepository; - private readonly List _devices; - private readonly List _enabledDevices; - private readonly IKernel _kernel; private readonly ILogger _logger; private readonly IPluginManagementService _pluginManagementService; + private readonly IDeviceRepository _deviceRepository; + private readonly LazyEnumerable _graphicsContextProviders; + private readonly PluginSetting _preferredGraphicsContext; private readonly PluginSetting _renderScaleSetting; - private readonly ISettingsService _settingsService; private readonly PluginSetting _targetFrameRateSetting; + + private readonly List _devices; + private readonly List _enabledDevices; private readonly SKTextureBrush _textureBrush = new(null) {CalculationMode = RenderMode.Absolute}; private Dictionary _ledMap; private ListLedGroup? _surfaceLedGroup; private SKTexture? _texture; - public RgbService(ILogger logger, IKernel kernel, ISettingsService settingsService, IPluginManagementService pluginManagementService, IDeviceRepository deviceRepository) + public RgbService(ILogger logger, + ISettingsService settingsService, + IPluginManagementService pluginManagementService, + IDeviceRepository deviceRepository, + LazyEnumerable graphicsContextProviders) { _logger = logger; - _kernel = kernel; - _settingsService = settingsService; _pluginManagementService = pluginManagementService; _deviceRepository = deviceRepository; + _graphicsContextProviders = graphicsContextProviders; + _targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 30); _renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.25); - _preferredGraphicsContext = _settingsService.GetSetting("Core.PreferredGraphicsContext", "Software"); + _preferredGraphicsContext = settingsService.GetSetting("Core.PreferredGraphicsContext", "Software"); Surface = new RGBSurface(); Utilities.RenderScaleMultiplier = (int) (1 / _renderScaleSetting.Value); @@ -226,7 +231,7 @@ internal class RgbService : IRgbService { _logger.Verbose("[AddDeviceProvider] Updating the LED group"); UpdateLedGroup(); - + _logger.Verbose("[AddDeviceProvider] Resuming rendering after adding {DeviceProvider}", deviceProvider.GetType().Name); if (changedRenderPaused) SetRenderPaused(false); @@ -257,7 +262,7 @@ internal class RgbService : IRgbService { _logger.Verbose("[RemoveDeviceProvider] Updating the LED group"); UpdateLedGroup(); - + _logger.Verbose("[RemoveDeviceProvider] Resuming rendering after adding {DeviceProvider}", deviceProvider.GetType().Name); if (changedRenderPaused) SetRenderPaused(false); @@ -372,7 +377,8 @@ internal class RgbService : IRgbService return; } - List providers = _kernel.Get>(); + + List providers = _graphicsContextProviders.ToList(); if (!providers.Any()) { _logger.Warning("No graphics context provider found, defaulting to software rendering"); diff --git a/src/Artemis.Core/Services/ScriptingService.cs b/src/Artemis.Core/Services/ScriptingService.cs index ef9b8a5ad..baeee28e9 100644 --- a/src/Artemis.Core/Services/ScriptingService.cs +++ b/src/Artemis.Core/Services/ScriptingService.cs @@ -2,10 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Reflection; using Artemis.Core.ScriptingProviders; -using Ninject; -using Ninject.Parameters; namespace Artemis.Core.Services; @@ -51,11 +48,7 @@ internal class ScriptingService : IScriptingService if (provider == null) throw new ArtemisCoreException($"Can't create script instance as there is no matching scripting provider found for the script ({scriptConfiguration.ScriptingProviderId})."); - script = (GlobalScript) provider.Plugin.Kernel!.Get( - provider.GlobalScriptType, - CreateScriptConstructorArgument(provider.GlobalScriptType, scriptConfiguration) - ); - + script = (GlobalScript) provider.Plugin.Resolve(provider.GlobalScriptType, scriptConfiguration); script.ScriptingProvider = provider; script.ScriptingService = this; scriptConfiguration.Script = script; @@ -82,12 +75,7 @@ internal class ScriptingService : IScriptingService if (provider == null) throw new ArtemisCoreException($"Can't create script instance as there is no matching scripting provider found for the script ({scriptConfiguration.ScriptingProviderId})."); - script = (ProfileScript) provider.Plugin.Kernel!.Get( - provider.ProfileScriptType, - CreateScriptConstructorArgument(provider.ProfileScriptType, profile), - CreateScriptConstructorArgument(provider.ProfileScriptType, scriptConfiguration) - ); - + script = (ProfileScript) provider.Plugin.Resolve(provider.ProfileScriptType, profile, scriptConfiguration); script.ScriptingProvider = provider; scriptConfiguration.Script = script; provider.InternalScripts.Add(script); @@ -113,21 +101,6 @@ internal class ScriptingService : IScriptingService } } - private ConstructorArgument CreateScriptConstructorArgument(Type scriptType, object value) - { - // Limit to one constructor, there's no need to have more and it complicates things anyway - ConstructorInfo[] constructors = scriptType.GetConstructors(); - if (constructors.Length != 1) - throw new ArtemisCoreException("Scripts must have exactly one constructor"); - - // Find the ScriptConfiguration parameter, it is required by the base constructor so its there for sure - ParameterInfo? configurationParameter = constructors.First().GetParameters().FirstOrDefault(p => value.GetType().IsAssignableFrom(p.ParameterType)); - - if (configurationParameter?.Name == null) - throw new ArtemisCoreException($"Couldn't find a valid constructor argument on {scriptType.Name} with type {value.GetType().Name}"); - return new ConstructorArgument(configurationParameter.Name, value); - } - private void InitializeProfileScripts(Profile profile) { // Initialize the scripts on the profile diff --git a/src/Artemis.Core/Services/WebServer/WebApiControllerRegistration.cs b/src/Artemis.Core/Services/WebServer/WebApiControllerRegistration.cs index 7c8e204d7..1a6375a11 100644 --- a/src/Artemis.Core/Services/WebServer/WebApiControllerRegistration.cs +++ b/src/Artemis.Core/Services/WebServer/WebApiControllerRegistration.cs @@ -1,6 +1,5 @@ using System; using EmbedIO.WebApi; -using Ninject; namespace Artemis.Core.Services; @@ -8,7 +7,7 @@ internal class WebApiControllerRegistration : WebApiControllerRegistration wh { public WebApiControllerRegistration(PluginFeature feature) : base(feature, typeof(T)) { - Factory = () => feature.Plugin.Kernel!.Get(); + Factory = () => feature.Plugin.Resolve(); } public Func Factory { get; set; } diff --git a/src/Artemis.Core/Services/WebServer/WebModuleRegistration.cs b/src/Artemis.Core/Services/WebServer/WebModuleRegistration.cs index c75f81eed..450ac7435 100644 --- a/src/Artemis.Core/Services/WebServer/WebModuleRegistration.cs +++ b/src/Artemis.Core/Services/WebServer/WebModuleRegistration.cs @@ -1,6 +1,6 @@ using System; using EmbedIO; -using Ninject; +using DryIoc; namespace Artemis.Core.Services; @@ -27,7 +27,7 @@ internal class WebModuleRegistration if (Create != null) return Create(); if (WebModuleType != null) - return (IWebModule) Feature.Plugin.Kernel!.Get(WebModuleType); + return (IWebModule) Feature.Plugin.Resolve(WebModuleType); throw new ArtemisCoreException("WebModuleRegistration doesn't have a create function nor a web module type :("); } } \ No newline at end of file diff --git a/src/Artemis.Core/VisualScripting/NodeData.cs b/src/Artemis.Core/VisualScripting/NodeData.cs index 1769cb821..5b0c678e2 100644 --- a/src/Artemis.Core/VisualScripting/NodeData.cs +++ b/src/Artemis.Core/VisualScripting/NodeData.cs @@ -1,6 +1,5 @@ using System; using Artemis.Storage.Entities.Profile.Nodes; -using Castle.Core.Internal; namespace Artemis.Core; diff --git a/src/Artemis.Core/VisualScripting/Nodes/Node.cs b/src/Artemis.Core/VisualScripting/Nodes/Node.cs index a6906ab57..5ff7dd254 100644 --- a/src/Artemis.Core/VisualScripting/Nodes/Node.cs +++ b/src/Artemis.Core/VisualScripting/Nodes/Node.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Artemis.Core.Events; +using DryIoc; namespace Artemis.Core; @@ -103,6 +104,8 @@ public abstract class Node : BreakableModel, INode /// public override string BrokenDisplayName => Name; + internal IContainer Container { get; set; } = null!; + #endregion #region Construtors diff --git a/src/Artemis.Core/VisualScripting/Nodes/NodeTStorageTViewModel.cs b/src/Artemis.Core/VisualScripting/Nodes/NodeTStorageTViewModel.cs index 1b4109714..98965c154 100644 --- a/src/Artemis.Core/VisualScripting/Nodes/NodeTStorageTViewModel.cs +++ b/src/Artemis.Core/VisualScripting/Nodes/NodeTStorageTViewModel.cs @@ -1,8 +1,5 @@ -using System.Linq; -using System.Reflection; using Artemis.Core; -using Ninject; -using Ninject.Parameters; +using DryIoc; /// /// Represents a kind of node inside a containing storage value of type @@ -22,26 +19,13 @@ public abstract class Node : Node, ICustomViewMo { } - [Inject] - internal IKernel Kernel { get; set; } = null!; - /// /// Called when a view model is required /// /// public virtual TViewModel GetViewModel(NodeScript nodeScript) { - // Limit to one constructor, there's no need to have more and it complicates things anyway - ConstructorInfo[] constructors = typeof(TViewModel).GetConstructors(); - if (constructors.Length != 1) - throw new ArtemisCoreException("Node VMs must have exactly one constructor"); - - // Find the ScriptConfiguration parameter, it is required by the base constructor so its there for sure - ParameterInfo? configurationParameter = constructors.First().GetParameters().FirstOrDefault(p => GetType().IsAssignableFrom(p.ParameterType)); - - if (configurationParameter?.Name == null) - throw new ArtemisCoreException($"Couldn't find a valid constructor argument on {typeof(TViewModel).Name} with type {GetType().Name}"); - return Kernel.Get(new ConstructorArgument(configurationParameter.Name, this), new ConstructorArgument("script", nodeScript)); + return Container.Resolve(args: new object[] {this, nodeScript}); } /// diff --git a/src/Artemis.Storage/StorageMigrationService.cs b/src/Artemis.Storage/StorageMigrationService.cs index 4ae1e6c81..169144e5c 100644 --- a/src/Artemis.Storage/StorageMigrationService.cs +++ b/src/Artemis.Storage/StorageMigrationService.cs @@ -10,10 +10,10 @@ namespace Artemis.Storage; public class StorageMigrationService { private readonly ILogger _logger; - private readonly List _migrations; + private readonly IList _migrations; private readonly LiteRepository _repository; - public StorageMigrationService(ILogger logger, LiteRepository repository, List migrations) + public StorageMigrationService(ILogger logger, LiteRepository repository, IList migrations) { _logger = logger; _repository = repository; diff --git a/src/Artemis.UI.Linux/App.axaml.cs b/src/Artemis.UI.Linux/App.axaml.cs index 0ef14c578..f3fdb04cf 100644 --- a/src/Artemis.UI.Linux/App.axaml.cs +++ b/src/Artemis.UI.Linux/App.axaml.cs @@ -5,7 +5,7 @@ using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using Avalonia.Threading; -using Ninject; +using DryIoc; using ReactiveUI; namespace Artemis.UI.Linux; @@ -13,12 +13,12 @@ namespace Artemis.UI.Linux; public class App : Application { private ApplicationStateManager? _applicationStateManager; - private StandardKernel? _kernel; + private IContainer? _container; public override void Initialize() { - _kernel = ArtemisBootstrapper.Bootstrap(this); - Program.CreateLogger(_kernel); + _container = ArtemisBootstrapper.Bootstrap(this); + Program.CreateLogger(_container); RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; AvaloniaXamlLoader.Load(this); @@ -32,15 +32,15 @@ public class App : Application ArtemisBootstrapper.Initialize(); if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - _applicationStateManager = new ApplicationStateManager(_kernel!, desktop.Args); + _applicationStateManager = new ApplicationStateManager(_container!, desktop.Args); } private void RegisterProviders() { - IInputService inputService = _kernel.Get(); + IInputService inputService = _container.Resolve(); try { - inputService.AddInputProvider(_kernel.Get()); + inputService.AddInputProvider(_container.Resolve(LinuxInputProvider.Id)); } catch { diff --git a/src/Artemis.UI.Linux/ApplicationStateManager.cs b/src/Artemis.UI.Linux/ApplicationStateManager.cs index 8c0182610..997c19ef3 100644 --- a/src/Artemis.UI.Linux/ApplicationStateManager.cs +++ b/src/Artemis.UI.Linux/ApplicationStateManager.cs @@ -11,7 +11,7 @@ using Artemis.UI.Shared.Services; using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Threading; -using Ninject; +using DryIoc; namespace Artemis.UI.Linux; @@ -22,23 +22,23 @@ public class ApplicationStateManager // ReSharper disable once NotAccessedField.Local - Kept in scope to ensure it does not get released private Mutex? _artemisMutex; - public ApplicationStateManager(IKernel kernel, string[] startupArguments) + public ApplicationStateManager(IContainer container, string[] startupArguments) { - _windowService = kernel.Get(); + _windowService = container.Resolve(); StartupArguments = startupArguments; Core.Utilities.ShutdownRequested += UtilitiesOnShutdownRequested; Core.Utilities.RestartRequested += UtilitiesOnRestartRequested; - // On OS shutdown dispose the kernel just so device providers get a chance to clean up + // On OS shutdown dispose the IOC container just so device providers get a chance to clean up if (Application.Current?.ApplicationLifetime is IControlledApplicationLifetime controlledApplicationLifetime) controlledApplicationLifetime.Exit += (_, _) => { RunForcedShutdownIfEnabled(); - // Dispose plugins before disposing the kernel because plugins might access services during dispose - kernel.Get().Dispose(); - kernel.Dispose(); + // Dispose plugins before disposing the IOC container because plugins might access services during dispose + container.Resolve().Dispose(); + container.Dispose(); }; } diff --git a/src/Artemis.UI.Linux/DryIoc/LinuxModule.cs b/src/Artemis.UI.Linux/DryIoc/LinuxModule.cs new file mode 100644 index 000000000..142e8b667 --- /dev/null +++ b/src/Artemis.UI.Linux/DryIoc/LinuxModule.cs @@ -0,0 +1,17 @@ +using Artemis.Core.DryIoc; +using Artemis.Core.Services; +using Artemis.UI.Linux.Providers.Input; +using DryIoc; + +namespace Artemis.UI.Linux.DryIoc; + +public class LinuxModule : IModule +{ + + /// + public void Load(IRegistrator builder) + { + builder.Register(serviceKey: LinuxInputProvider.Id); + } + +} \ No newline at end of file diff --git a/src/Artemis.UI.Linux/Program.cs b/src/Artemis.UI.Linux/Program.cs index fe8b2b984..707f0e692 100644 --- a/src/Artemis.UI.Linux/Program.cs +++ b/src/Artemis.UI.Linux/Program.cs @@ -1,7 +1,7 @@ using System; using Avalonia; using Avalonia.ReactiveUI; -using Ninject; +using DryIoc; using Serilog; namespace Artemis.UI.Linux; @@ -33,8 +33,8 @@ internal class Program return AppBuilder.Configure().UsePlatformDetect().LogToTrace().UseReactiveUI(); } - public static void CreateLogger(IKernel kernel) + public static void CreateLogger(IContainer container) { - Logger = kernel.Get().ForContext(); + Logger = container.Resolve().ForContext(); } } \ No newline at end of file diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs b/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs index e735a8ed9..62866cb00 100644 --- a/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs +++ b/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs @@ -26,6 +26,8 @@ public class LinuxInputProvider : InputProvider _readers.Add(reader); } } + + public static Guid Id { get; } = new("72a6fe5c-b11e-4886-bd48-b3ff5d9006c1"); #region Overrides of InputProvider diff --git a/src/Artemis.UI.MacOS/App.axaml.cs b/src/Artemis.UI.MacOS/App.axaml.cs index abbee91f2..f1aed23d3 100644 --- a/src/Artemis.UI.MacOS/App.axaml.cs +++ b/src/Artemis.UI.MacOS/App.axaml.cs @@ -2,19 +2,19 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; using Avalonia.Threading; -using Ninject; +using DryIoc; using ReactiveUI; namespace Artemis.UI.MacOS; public class App : Application { - private StandardKernel? _kernel; + private IContainer? _container; public override void Initialize() { - _kernel = ArtemisBootstrapper.Bootstrap(this); - Program.CreateLogger(_kernel); + _container = ArtemisBootstrapper.Bootstrap(this); + Program.CreateLogger(_container); RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; AvaloniaXamlLoader.Load(this); } diff --git a/src/Artemis.UI.MacOS/Program.cs b/src/Artemis.UI.MacOS/Program.cs index 8434a7831..47fd8622d 100644 --- a/src/Artemis.UI.MacOS/Program.cs +++ b/src/Artemis.UI.MacOS/Program.cs @@ -1,7 +1,7 @@ using System; using Avalonia; using Avalonia.ReactiveUI; -using Ninject; +using DryIoc; using Serilog; namespace Artemis.UI.MacOS; @@ -33,8 +33,8 @@ internal class Program return AppBuilder.Configure().UsePlatformDetect().LogToTrace().UseReactiveUI(); } - public static void CreateLogger(IKernel kernel) + public static void CreateLogger(IContainer container) { - Logger = kernel.Get().ForContext(); + Logger = container.Resolve().ForContext(); } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/DryIoc/SharedUIModule.cs b/src/Artemis.UI.Shared/DryIoc/SharedUIModule.cs new file mode 100644 index 000000000..be6fcced3 --- /dev/null +++ b/src/Artemis.UI.Shared/DryIoc/SharedUIModule.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using Artemis.Core.DryIoc; +using Artemis.UI.Shared.Services; +using DryIoc; + +namespace Artemis.UI.Shared.DryIoc; + +/// +/// The main of the Artemis Shared UI toolkit that binds all services +/// +public class SharedUIModule : IModule +{ + /// + public void Load(IRegistrator builder) + { + Assembly artemisShared = typeof(IArtemisSharedUIService).GetAssembly(); + builder.RegisterMany(new[] { artemisShared }, type => type.IsAssignableTo(), Reuse.Singleton); + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Ninject/SharedUIModule.cs b/src/Artemis.UI.Shared/Ninject/SharedUIModule.cs deleted file mode 100644 index 5e4b205f1..000000000 --- a/src/Artemis.UI.Shared/Ninject/SharedUIModule.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using Artemis.UI.Shared.Services; -using Ninject.Extensions.Conventions; -using Ninject.Modules; - -namespace Artemis.UI.Shared.Ninject; - -/// -/// The main of the Artemis Shared UI toolkit that binds all services -/// -public class SharedUIModule : NinjectModule -{ - /// - public override void Load() - { - if (Kernel == null) - throw new ArgumentNullException("Kernel shouldn't be null here."); - - // Bind all shared UI services as singletons - Kernel.Bind(x => - { - x.FromAssemblyContaining() - .IncludingNonPublicTypes() - .SelectAllClasses() - .InheritedFrom() - .BindAllInterfaces() - .Configure(c => c.InSingletonScope()); - }); - } -} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/Builders/ContentDialogBuilder.cs b/src/Artemis.UI.Shared/Services/Builders/ContentDialogBuilder.cs index 663d37dbb..275345b0e 100644 --- a/src/Artemis.UI.Shared/Services/Builders/ContentDialogBuilder.cs +++ b/src/Artemis.UI.Shared/Services/Builders/ContentDialogBuilder.cs @@ -3,9 +3,8 @@ using System.Linq; using System.Threading.Tasks; using System.Windows.Input; using Avalonia.Controls; +using DryIoc; using FluentAvalonia.UI.Controls; -using Ninject; -using Ninject.Parameters; using ReactiveUI; namespace Artemis.UI.Shared.Services.Builders; @@ -16,13 +15,13 @@ namespace Artemis.UI.Shared.Services.Builders; public class ContentDialogBuilder { private readonly ContentDialog _contentDialog; - private readonly IKernel _kernel; + private readonly IContainer _container; private readonly Window _parent; private ContentDialogViewModelBase? _viewModel; - internal ContentDialogBuilder(IKernel kernel, Window parent) + internal ContentDialogBuilder(IContainer container, Window parent) { - _kernel = kernel; + _container = container; _parent = parent; _contentDialog = new ContentDialog { @@ -129,12 +128,11 @@ public class ContentDialogBuilder /// /// The type of the view model to host. /// The resulting view model. - /// Optional parameters to pass to the constructor of the view model, case and order sensitive. + /// Optional parameters to pass to the constructor of the view model. /// The builder that can be used to further build the dialog. - public ContentDialogBuilder WithViewModel(out T viewModel, params (string name, object? value)[] parameters) where T : ContentDialogViewModelBase + public ContentDialogBuilder WithViewModel(out T viewModel, params object[] parameters) where T : ContentDialogViewModelBase { - IParameter[] paramsArray = parameters.Select(kv => new ConstructorArgument(kv.name, kv.value)).Cast().ToArray(); - viewModel = _kernel.Get(paramsArray); + viewModel = _container.Resolve(parameters); viewModel.ContentDialog = _contentDialog; _contentDialog.Content = viewModel; diff --git a/src/Artemis.UI.Shared/Services/DataModelUIService.cs b/src/Artemis.UI.Shared/Services/DataModelUIService.cs index 9b9ef00cb..f7fe353f6 100644 --- a/src/Artemis.UI.Shared/Services/DataModelUIService.cs +++ b/src/Artemis.UI.Shared/Services/DataModelUIService.cs @@ -8,22 +8,21 @@ using Artemis.Core.Services; using Artemis.UI.Shared.DataModelVisualization; using Artemis.UI.Shared.DataModelVisualization.Shared; using Artemis.UI.Shared.DefaultTypes.DataModel.Display; -using Ninject; -using Ninject.Parameters; +using DryIoc; namespace Artemis.UI.Shared.Services; internal class DataModelUIService : IDataModelUIService { private readonly IDataModelService _dataModelService; - private readonly IKernel _kernel; + private readonly IContainer _container; private readonly List _registeredDataModelDisplays; private readonly List _registeredDataModelEditors; - public DataModelUIService(IDataModelService dataModelService, IKernel kernel) + public DataModelUIService(IDataModelService dataModelService, IContainer container) { _dataModelService = dataModelService; - _kernel = kernel; + _container = container; _registeredDataModelEditors = new List(); _registeredDataModelDisplays = new List(); @@ -36,18 +35,8 @@ internal class DataModelUIService : IDataModelUIService // This assumes the type can be converted, that has been checked when the VM was created if (initialValue != null && initialValue.GetType() != registration.SupportedType) initialValue = Convert.ChangeType(initialValue, registration.SupportedType); - - IParameter[] parameters = - { - new ConstructorArgument("targetDescription", description), - new ConstructorArgument("initialValue", initialValue) - }; - - // If this ever happens something is likely wrong with the plugin unload detection - if (registration.Plugin.Kernel == null) - throw new ArtemisSharedUIException("Cannot InstantiateDataModelInputViewModel for a registration by an uninitialized plugin"); - - DataModelInputViewModel viewModel = (DataModelInputViewModel) registration.Plugin.Kernel.Get(registration.ViewModelType, parameters); + + DataModelInputViewModel viewModel = (DataModelInputViewModel) registration.Plugin.Resolve(registration.ViewModelType, description, initialValue); viewModel.CompatibleConversionTypes = registration.CompatibleConversionTypes; return viewModel; } @@ -133,7 +122,7 @@ internal class DataModelUIService : IDataModelUIService return existing; } - _kernel.Bind(viewModelType).ToSelf(); + _container.Register(viewModelType, ifAlreadyRegistered: IfAlreadyRegistered.Replace); // Create the registration DataModelVisualizationRegistration registration = new(this, RegistrationType.Input, plugin, supportedType, viewModelType) @@ -162,7 +151,7 @@ internal class DataModelUIService : IDataModelUIService return existing; } - _kernel.Bind(viewModelType).ToSelf(); + _container.Register(viewModelType); DataModelVisualizationRegistration registration = new(this, RegistrationType.Display, plugin, supportedType, viewModelType); _registeredDataModelDisplays.Add(registration); return registration; @@ -178,7 +167,8 @@ internal class DataModelUIService : IDataModelUIService registration.Unsubscribe(); _registeredDataModelEditors.Remove(registration); - _kernel.Unbind(registration.ViewModelType); + _container.Unregister(registration.ViewModelType); + _container.ClearCache(registration.ViewModelType); } } } @@ -192,7 +182,8 @@ internal class DataModelUIService : IDataModelUIService registration.Unsubscribe(); _registeredDataModelDisplays.Remove(registration); - _kernel.Unbind(registration.ViewModelType); + _container.Unregister(registration.ViewModelType); + _container.ClearCache(registration.ViewModelType); } } } @@ -205,21 +196,11 @@ internal class DataModelUIService : IDataModelUIService DataModelVisualizationRegistration? match = _registeredDataModelDisplays.FirstOrDefault(d => d.SupportedType == propertyType); if (match != null) - { - // If this ever happens something is likely wrong with the plugin unload detection - if (match.Plugin.Kernel == null) - throw new ArtemisSharedUIException("Cannot GetDataModelDisplayViewModel for a registration by an uninitialized plugin"); - - result = (DataModelDisplayViewModel) match.Plugin.Kernel.Get(match.ViewModelType); - } + result = (DataModelDisplayViewModel) match.Plugin.Resolve(match.ViewModelType); else if (!fallBackToDefault) - { result = null; - } else - { - result = _kernel.Get(); - } + result = _container.Resolve(); if (result != null) result.PropertyDescription = description; diff --git a/src/Artemis.UI.Shared/Services/Interfaces/IWindowService.cs b/src/Artemis.UI.Shared/Services/Interfaces/IWindowService.cs index b8ae9dc9c..ff4394fde 100644 --- a/src/Artemis.UI.Shared/Services/Interfaces/IWindowService.cs +++ b/src/Artemis.UI.Shared/Services/Interfaces/IWindowService.cs @@ -16,7 +16,7 @@ public interface IWindowService : IArtemisSharedUIService /// /// The type of view model to create /// The created view model - TViewModel ShowWindow(params (string name, object value)[] parameters); + TViewModel ShowWindow(params object[] parameters); /// /// Given a ViewModel, show its corresponding View as a window @@ -37,7 +37,7 @@ public interface IWindowService : IArtemisSharedUIService /// /// The type of view model to create /// The created view model - Task ShowDialogAsync(params (string name, object value)[] parameters); + Task ShowDialogAsync(params object[] parameters); /// /// Given a ViewModel, show its corresponding View as a dialog @@ -60,7 +60,7 @@ public interface IWindowService : IArtemisSharedUIService /// The view model type /// The return type /// A task containing the return value of type - Task ShowDialogAsync(params (string name, object? value)[] parameters) where TViewModel : DialogViewModelBase; + Task ShowDialogAsync(params object[] parameters) where TViewModel : DialogViewModelBase; /// /// Shows a content dialog asking the user to confirm an action diff --git a/src/Artemis.UI.Shared/Services/NodeEditor/Commands/UpdateStorage.cs b/src/Artemis.UI.Shared/Services/NodeEditor/Commands/UpdateStorage.cs index 1c07d14b5..c0b10d093 100644 --- a/src/Artemis.UI.Shared/Services/NodeEditor/Commands/UpdateStorage.cs +++ b/src/Artemis.UI.Shared/Services/NodeEditor/Commands/UpdateStorage.cs @@ -1,5 +1,4 @@ using System; -using Artemis.Core; namespace Artemis.UI.Shared.Services.NodeEditor.Commands; diff --git a/src/Artemis.UI.Shared/Services/PropertyInput/PropertyInputService.cs b/src/Artemis.UI.Shared/Services/PropertyInput/PropertyInputService.cs index ec23d0850..6f91fbdfe 100644 --- a/src/Artemis.UI.Shared/Services/PropertyInput/PropertyInputService.cs +++ b/src/Artemis.UI.Shared/Services/PropertyInput/PropertyInputService.cs @@ -3,19 +3,18 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Artemis.Core; -using Ninject; -using Ninject.Parameters; +using DryIoc; namespace Artemis.UI.Shared.Services.PropertyInput; internal class PropertyInputService : IPropertyInputService { - private readonly IKernel _kernel; + private readonly IContainer _container; private readonly List _registeredPropertyEditors; - public PropertyInputService(IKernel kernel) + public PropertyInputService(IContainer container) { - _kernel = kernel; + _container = container; _registeredPropertyEditors = new List(); RegisteredPropertyEditors = new ReadOnlyCollection(_registeredPropertyEditors); } @@ -55,7 +54,7 @@ internal class PropertyInputService : IPropertyInputService return existing; } - _kernel.Bind(viewModelType).ToSelf(); + _container.Register(viewModelType); PropertyInputRegistration registration = new(this, plugin, supportedType, viewModelType); _registeredPropertyEditors.Add(registration); return registration; @@ -71,7 +70,8 @@ internal class PropertyInputService : IPropertyInputService registration.Unsubscribe(); _registeredPropertyEditors.Remove(registration); - _kernel.Unbind(registration.ViewModelType); + _container.Unregister(registration.ViewModelType); + _container.ClearCache(registration.ViewModelType); } } } @@ -110,10 +110,9 @@ internal class PropertyInputService : IPropertyInputService if (viewModelType == null) return null; - ConstructorArgument parameter = new("layerProperty", layerProperty); // ReSharper disable once InconsistentlySynchronizedField // When you've just spent the last 2 hours trying to figure out a deadlock and reach this line, I'm so, so sorry. I thought this would be fine. - IKernel kernel = registration?.Plugin.Kernel ?? _kernel; - return (PropertyInputViewModel) kernel.Get(viewModelType, parameter); + IContainer container = registration?.Plugin.Container ?? _container; + return (PropertyInputViewModel) container.Resolve(viewModelType, args: new object[] { layerProperty }); } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/Window/WindowService.cs b/src/Artemis.UI.Shared/Services/Window/WindowService.cs index 9a5b33206..5678ed75b 100644 --- a/src/Artemis.UI.Shared/Services/Window/WindowService.cs +++ b/src/Artemis.UI.Shared/Services/Window/WindowService.cs @@ -6,26 +6,27 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Threading; +using DryIoc; using FluentAvalonia.UI.Controls; -using Ninject; -using Ninject.Parameters; namespace Artemis.UI.Shared.Services; internal class WindowService : IWindowService { - private readonly IKernel _kernel; + private readonly IContainer _container; private bool _exceptionDialogOpen; - public WindowService(IKernel kernel) + public WindowService(IContainer container) { - _kernel = kernel; + _container = container; } - public T ShowWindow(params (string name, object value)[] parameters) + public T ShowWindow(params object[] parameters) { - IParameter[] paramsArray = parameters.Select(kv => new ConstructorArgument(kv.name, kv.value)).Cast().ToArray(); - T viewModel = _kernel.Get(paramsArray)!; + T viewModel = _container.Resolve(parameters); + if (viewModel == null) + throw new ArtemisSharedUIException($"Failed to show window for VM of type {typeof(T).Name}, could not create instance."); + ShowWindow(viewModel); return viewModel; } @@ -53,10 +54,12 @@ internal class WindowService : IWindowService return window; } - public async Task ShowDialogAsync(params (string name, object value)[] parameters) + public async Task ShowDialogAsync(params object[] parameters) { - IParameter[] paramsArray = parameters.Select(kv => new ConstructorArgument(kv.name, kv.value)).Cast().ToArray(); - T viewModel = _kernel.Get(paramsArray)!; + T viewModel = _container.Resolve(parameters); + if (viewModel == null) + throw new ArtemisSharedUIException($"Failed to show window for VM of type {typeof(T).Name}, could not create instance."); + await ShowDialogAsync(viewModel); return viewModel; } @@ -79,10 +82,12 @@ internal class WindowService : IWindowService await window.ShowDialog(parent); } - public async Task ShowDialogAsync(params (string name, object? value)[] parameters) where TViewModel : DialogViewModelBase + public async Task ShowDialogAsync(params object[] parameters) where TViewModel : DialogViewModelBase { - IParameter[] paramsArray = parameters.Select(kv => new ConstructorArgument(kv.name, kv.value)).Cast().ToArray(); - TViewModel viewModel = _kernel.Get(paramsArray)!; + TViewModel viewModel = _container.Resolve(parameters); + if (viewModel == null) + throw new ArtemisSharedUIException($"Failed to show window for VM of type {typeof(TViewModel).Name}, could not create instance."); + return await ShowDialogAsync(viewModel); } @@ -129,7 +134,7 @@ internal class WindowService : IWindowService { try { - await ShowDialogAsync(new ExceptionDialogViewModel(title, exception, _kernel.Get())); + await ShowDialogAsync(new ExceptionDialogViewModel(title, exception, _container.Resolve())); } finally { @@ -143,7 +148,7 @@ internal class WindowService : IWindowService Window? currentWindow = GetCurrentWindow(); if (currentWindow == null) throw new ArtemisSharedUIException("Can't show a content dialog without any windows being shown."); - return new ContentDialogBuilder(_kernel, currentWindow); + return new ContentDialogBuilder(_container, currentWindow); } public OpenFolderDialogBuilder CreateOpenFolderDialog() diff --git a/src/Artemis.UI.Windows/App.axaml.cs b/src/Artemis.UI.Windows/App.axaml.cs index c41c00aa1..38f0389a7 100644 --- a/src/Artemis.UI.Windows/App.axaml.cs +++ b/src/Artemis.UI.Windows/App.axaml.cs @@ -7,21 +7,21 @@ using System.Net.Http; using System.Threading; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Windows.Ninject; +using Artemis.UI.Windows.DryIoc; using Artemis.UI.Windows.Providers.Input; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using Avalonia.Threading; -using Ninject; +using DryIoc; using ReactiveUI; namespace Artemis.UI.Windows; public class App : Application { - private StandardKernel? _kernel; + private IContainer? _container; private bool _shutDown; public override void Initialize() @@ -33,8 +33,8 @@ public class App : Application Environment.Exit(1); } - _kernel = ArtemisBootstrapper.Bootstrap(this, new WindowsModule()); - Program.CreateLogger(_kernel); + _container = ArtemisBootstrapper.Bootstrap(this, new WindowsModule()); + Program.CreateLogger(_container); RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; AvaloniaXamlLoader.Load(this); } @@ -45,14 +45,14 @@ public class App : Application return; ArtemisBootstrapper.Initialize(); - _applicationStateManager = new ApplicationStateManager(_kernel!, desktop.Args); - RegisterProviders(_kernel!); + _applicationStateManager = new ApplicationStateManager(_container!, desktop.Args); + RegisterProviders(_container!); } - private void RegisterProviders(StandardKernel standardKernel) + private void RegisterProviders(IContainer container) { - IInputService inputService = standardKernel.Get(); - inputService.AddInputProvider(standardKernel.Get()); + IInputService inputService = container.Resolve(); + inputService.AddInputProvider(container.Resolve(serviceKey: WindowsInputProvider.Id)); } private bool FocusExistingInstance() diff --git a/src/Artemis.UI.Windows/ApplicationStateManager.cs b/src/Artemis.UI.Windows/ApplicationStateManager.cs index 1630c95ef..a14b50248 100644 --- a/src/Artemis.UI.Windows/ApplicationStateManager.cs +++ b/src/Artemis.UI.Windows/ApplicationStateManager.cs @@ -10,7 +10,7 @@ using Artemis.UI.Windows.Utilities; using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Threading; -using Ninject; +using DryIoc; namespace Artemis.UI.Windows; @@ -18,7 +18,7 @@ public class ApplicationStateManager { private const int SM_SHUTTINGDOWN = 0x2000; - public ApplicationStateManager(IKernel kernel, string[] startupArguments) + public ApplicationStateManager(IContainer container, string[] startupArguments) { StartupArguments = startupArguments; IsElevated = new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator); @@ -26,19 +26,19 @@ public class ApplicationStateManager Core.Utilities.ShutdownRequested += UtilitiesOnShutdownRequested; Core.Utilities.RestartRequested += UtilitiesOnRestartRequested; - // On Windows shutdown dispose the kernel just so device providers get a chance to clean up + // On Windows shutdown dispose the IOC container just so device providers get a chance to clean up if (Application.Current?.ApplicationLifetime is IControlledApplicationLifetime controlledApplicationLifetime) controlledApplicationLifetime.Exit += (_, _) => { RunForcedShutdownIfEnabled(); - // Dispose plugins before disposing the kernel because plugins might access services during dispose - kernel.Get().Dispose(); - kernel.Dispose(); + // Dispose plugins before disposing the IOC container because plugins might access services during dispose + container.Resolve().Dispose(); + container.Dispose(); }; // Inform the Core about elevation status - kernel.Get().IsElevated = IsElevated; + container.Resolve().IsElevated = IsElevated; } public string[] StartupArguments { get; } diff --git a/src/Artemis.UI.Windows/DryIoc/WindowsModule.cs b/src/Artemis.UI.Windows/DryIoc/WindowsModule.cs new file mode 100644 index 000000000..96b8b7ec7 --- /dev/null +++ b/src/Artemis.UI.Windows/DryIoc/WindowsModule.cs @@ -0,0 +1,22 @@ +using Artemis.Core.DryIoc; +using Artemis.Core.Providers; +using Artemis.Core.Services; +using Artemis.UI.Shared.Providers; +using Artemis.UI.Windows.Providers; +using Artemis.UI.Windows.Providers.Input; +using DryIoc; + +namespace Artemis.UI.Windows.DryIoc; + +public class WindowsModule : IModule +{ + /// + public void Load(IRegistrator builder) + { + builder.Register(Reuse.Singleton); + builder.Register(Reuse.Singleton); + builder.Register(Reuse.Singleton); + builder.Register(); + builder.Register(serviceKey: WindowsInputProvider.Id); + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Windows/Ninject/WindowsModule.cs b/src/Artemis.UI.Windows/Ninject/WindowsModule.cs deleted file mode 100644 index e85c5fe83..000000000 --- a/src/Artemis.UI.Windows/Ninject/WindowsModule.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Artemis.Core.Providers; -using Artemis.UI.Shared.Providers; -using Artemis.UI.Windows.Providers; -using Ninject.Modules; - -namespace Artemis.UI.Windows.Ninject; - -public class WindowsModule : NinjectModule -{ - #region Overrides of NinjectModule - - /// - public override void Load() - { - Kernel!.Bind().To().InSingletonScope(); - Kernel!.Bind().To().InSingletonScope(); - Kernel!.Bind().To().InSingletonScope(); - Kernel!.Bind().To(); - } - - #endregion -} \ No newline at end of file diff --git a/src/Artemis.UI.Windows/Program.cs b/src/Artemis.UI.Windows/Program.cs index 98c99b14d..80d8d625f 100644 --- a/src/Artemis.UI.Windows/Program.cs +++ b/src/Artemis.UI.Windows/Program.cs @@ -1,7 +1,7 @@ using System; using Avalonia; using Avalonia.ReactiveUI; -using Ninject; +using DryIoc; using Serilog; namespace Artemis.UI.Windows; @@ -41,8 +41,8 @@ internal class Program .UseReactiveUI(); } - public static void CreateLogger(IKernel kernel) + public static void CreateLogger(IContainer container) { - Logger = kernel.Get().ForContext(); + Logger = container.Resolve().ForContext(); } } \ No newline at end of file diff --git a/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs b/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs index 1091fca54..ef8f168ec 100644 --- a/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs +++ b/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs @@ -37,6 +37,8 @@ public class WindowsInputProvider : InputProvider RawInputDevice.RegisterDevice(HidUsageAndPage.Mouse, RawInputDeviceFlags.InputSink, _sponge.Handle.Handle); } + public static Guid Id { get; } = new("6737b204-ffb1-4cd9-8776-9fb851db303a"); + #region Overrides of InputProvider diff --git a/src/Artemis.UI.Windows/Providers/UpdateProvider.cs b/src/Artemis.UI.Windows/Providers/UpdateProvider.cs index 42df93619..d3d20081e 100644 --- a/src/Artemis.UI.Windows/Providers/UpdateProvider.cs +++ b/src/Artemis.UI.Windows/Providers/UpdateProvider.cs @@ -201,7 +201,7 @@ public class UpdateProvider : IUpdateProvider, IDisposable { if (windowOpen) { - bool update = await _windowService.ShowDialogAsync(("channel", channel)); + bool update = await _windowService.ShowDialogAsync(channel); if (update) await RunInstaller(channel, false); } diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 04e578c41..65fd23482 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -22,6 +22,7 @@ + @@ -32,7 +33,7 @@ - + diff --git a/src/Artemis.UI/ArtemisBootstrapper.cs b/src/Artemis.UI/ArtemisBootstrapper.cs index 901388bf8..2e4a57937 100644 --- a/src/Artemis.UI/ArtemisBootstrapper.cs +++ b/src/Artemis.UI/ArtemisBootstrapper.cs @@ -3,53 +3,54 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Reactive; using Artemis.Core; -using Artemis.Core.Ninject; +using Artemis.Core.DryIoc; +using Artemis.UI.DryIoc; using Artemis.UI.Exceptions; -using Artemis.UI.Ninject; using Artemis.UI.Screens.Root; using Artemis.UI.Shared.DataModelPicker; -using Artemis.UI.Shared.Ninject; +using Artemis.UI.Shared.DryIoc; using Artemis.UI.Shared.Services; -using Artemis.VisualScripting.Ninject; +using Artemis.VisualScripting.DryIoc; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; -using Ninject; -using Ninject.Modules; +using DryIoc; using ReactiveUI; -using Splat.Ninject; +using Splat.DryIoc; namespace Artemis.UI; public static class ArtemisBootstrapper { - private static StandardKernel? _kernel; + private static Container? _container; private static Application? _application; - public static StandardKernel Bootstrap(Application application, params INinjectModule[] modules) + public static IContainer Bootstrap(Application application, params IModule[] modules) { - if (_application != null || _kernel != null) + if (_application != null || _container != null) throw new ArtemisUIException("UI already bootstrapped"); Utilities.PrepareFirstLaunch(); _application = application; - _kernel = new StandardKernel(); - _kernel.Settings.InjectNonPublic = true; + _container = new Container(rules => rules.WithConcreteTypeDynamicRegistrations() + .WithoutThrowOnRegisteringDisposableTransient()); - _kernel.Load(); - _kernel.Load(); - _kernel.Load(); - _kernel.Load(); - _kernel.Load(modules); - _kernel.UseNinjectDependencyResolver(); + new CoreModule().Load(_container); + new UIModule().Load(_container); + new SharedUIModule().Load(_container); + new NoStringDryIocModule().Load(_container); + foreach (IModule module in modules) + module.Load(_container); - return _kernel; + _container.UseDryIocDependencyResolver(); + + return _container; } public static void Initialize() { - if (_application == null || _kernel == null) + if (_application == null || _container == null) throw new ArtemisUIException("UI not yet bootstrapped"); if (_application.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) return; @@ -59,16 +60,16 @@ public static class ArtemisBootstrapper // Don't shut down when the last window closes, we might still be active in the tray desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown; // Create the root view model that drives the UI - RootViewModel rootViewModel = _kernel.Get(); + RootViewModel rootViewModel = _container.Resolve(); // Apply the root view model to the data context of the application so that tray icon commands work _application.DataContext = rootViewModel; RxApp.DefaultExceptionHandler = Observer.Create(DisplayUnhandledException); - DataModelPicker.DataModelUIService = _kernel.Get(); + DataModelPicker.DataModelUIService = _container.Resolve(); } private static void DisplayUnhandledException(Exception exception) { - _kernel?.Get().ShowExceptionDialog("Exception", exception); + _container?.Resolve().ShowExceptionDialog("Exception", exception); } } \ No newline at end of file diff --git a/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs b/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs index e0d3138ce..26c548dca 100644 --- a/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs +++ b/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs @@ -59,14 +59,14 @@ public class BrushPropertyInputViewModel : PropertyInputViewModel protected override void ApplyInputValue() { - if (LayerProperty.ProfileElement is not Layer layer || SelectedDescriptor == null) + if (LayerProperty.ProfileElement is not Layer layer || layer.LayerBrush == null || SelectedDescriptor == null) return; _profileEditorService.ExecuteCommand(new ChangeLayerBrush(layer, SelectedDescriptor)); if (layer.LayerBrush?.Presets != null && layer.LayerBrush.Presets.Any()) Dispatcher.UIThread.InvokeAsync(() => _windowService.CreateContentDialog() .WithTitle("Select preset") - .WithViewModel(out LayerBrushPresetViewModel _, ("layerBrush", layer.LayerBrush)) + .WithViewModel(out LayerBrushPresetViewModel _, layer.LayerBrush) .WithDefaultButton(ContentDialogButton.Close) .WithCloseButtonText("Use defaults") .ShowAsync()); diff --git a/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs b/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs new file mode 100644 index 000000000..ed71b2c6e --- /dev/null +++ b/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs @@ -0,0 +1,477 @@ +using System.Collections.ObjectModel; +using System.Reactive; +using Artemis.Core; +using Artemis.Core.LayerBrushes; +using Artemis.Core.LayerEffects; +using Artemis.Core.ScriptingProviders; +using Artemis.UI.Screens.Device; +using Artemis.UI.Screens.Plugins; +using Artemis.UI.Screens.ProfileEditor; +using Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes; +using Artemis.UI.Screens.ProfileEditor.ProfileTree; +using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints; +using Artemis.UI.Screens.ProfileEditor.Properties; +using Artemis.UI.Screens.ProfileEditor.Properties.DataBinding; +using Artemis.UI.Screens.ProfileEditor.Properties.Timeline; +using Artemis.UI.Screens.ProfileEditor.Properties.Tree; +using Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers; +using Artemis.UI.Screens.Scripting; +using Artemis.UI.Screens.Settings; +using Artemis.UI.Screens.Sidebar; +using Artemis.UI.Screens.SurfaceEditor; +using Artemis.UI.Screens.VisualScripting; +using Artemis.UI.Screens.VisualScripting.Pins; +using DryIoc; +using ReactiveUI; + +namespace Artemis.UI.DryIoc.Factories; + +public interface IVmFactory +{ +} + +public interface IDeviceVmFactory : IVmFactory +{ + DevicePropertiesViewModel DevicePropertiesViewModel(ArtemisDevice device); + DeviceSettingsViewModel DeviceSettingsViewModel(ArtemisDevice device, DevicesTabViewModel devicesTabViewModel); + DeviceDetectInputViewModel DeviceDetectInputViewModel(ArtemisDevice device); + DevicePropertiesTabViewModel DevicePropertiesTabViewModel(ArtemisDevice device); + DeviceInfoTabViewModel DeviceInfoTabViewModel(ArtemisDevice device); + DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device, ObservableCollection selectedLeds); + InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection selectedLeds); +} +public class DeviceFactory : IDeviceVmFactory +{ + private readonly IContainer _container; + + public DeviceFactory(IContainer container) + { + _container = container; + } + + public DevicePropertiesViewModel DevicePropertiesViewModel(ArtemisDevice device) + { + return _container.Resolve(new object[] { device }); + } + + public DeviceSettingsViewModel DeviceSettingsViewModel(ArtemisDevice device, DevicesTabViewModel devicesTabViewModel) + { + return _container.Resolve(new object[] { device, devicesTabViewModel }); + } + + public DeviceDetectInputViewModel DeviceDetectInputViewModel(ArtemisDevice device) + { + return _container.Resolve(new object[] { device }); + } + + public DevicePropertiesTabViewModel DevicePropertiesTabViewModel(ArtemisDevice device) + { + return _container.Resolve(new object[] { device }); + } + + public DeviceInfoTabViewModel DeviceInfoTabViewModel(ArtemisDevice device) + { + return _container.Resolve(new object[] { device }); + } + + public DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device, ObservableCollection selectedLeds) + { + return _container.Resolve(new object[] { device, selectedLeds }); + } + + public InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection selectedLeds) + { + return _container.Resolve(new object[] { device, selectedLeds }); + } +} + +public interface ISettingsVmFactory : IVmFactory +{ + PluginSettingsViewModel PluginSettingsViewModel(Plugin plugin); + PluginViewModel PluginViewModel(Plugin plugin, ReactiveCommand? reload); + PluginFeatureViewModel PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo, bool showShield); +} +public class SettingsVmFactory : ISettingsVmFactory +{ + private readonly IContainer _container; + + public SettingsVmFactory(IContainer container) + { + _container = container; + } + + public PluginSettingsViewModel PluginSettingsViewModel(Plugin plugin) + { + return _container.Resolve(new object[] { plugin }); + } + + public PluginViewModel PluginViewModel(Plugin plugin, ReactiveCommand? reload) + { + return _container.Resolve(new object?[] { plugin, reload }); + } + + public PluginFeatureViewModel PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo, bool showShield) + { + return _container.Resolve(new object[] { pluginFeatureInfo, showShield }); + } +} + +public interface ISidebarVmFactory : IVmFactory +{ + SidebarViewModel? SidebarViewModel(IScreen hostScreen); + SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory); + SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration); +} +public class SidebarVmFactory : ISidebarVmFactory +{ + private readonly IContainer _container; + + public SidebarVmFactory(IContainer container) + { + _container = container; + } + + public SidebarViewModel? SidebarViewModel(IScreen hostScreen) + { + return _container.Resolve(new object[] { hostScreen }); + } + + public SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory) + { + return _container.Resolve(new object[] { profileCategory }); + } + + public SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration) + { + return _container.Resolve(new object[] { profileConfiguration }); + } +} + +public interface ISurfaceVmFactory : IVmFactory +{ + SurfaceDeviceViewModel SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel); + ListDeviceViewModel ListDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel); +} +public class SurfaceVmFactory : ISurfaceVmFactory +{ + private readonly IContainer _container; + + public SurfaceVmFactory(IContainer container) + { + _container = container; + } + + public SurfaceDeviceViewModel SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel) + { + return _container.Resolve(new object[] { device, surfaceEditorViewModel }); + } + + public ListDeviceViewModel ListDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel) + { + return _container.Resolve(new object[] { device, surfaceEditorViewModel }); + } +} + +public interface IPrerequisitesVmFactory : IVmFactory +{ + PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall); +} +public class PrerequisitesVmFactory : IPrerequisitesVmFactory +{ + private readonly IContainer _container; + + public PrerequisitesVmFactory(IContainer container) + { + _container = container; + } + + public PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall) + { + return _container.Resolve(new object[] { pluginPrerequisite, uninstall }); + } +} + +public interface IProfileEditorVmFactory : IVmFactory +{ + ProfileEditorViewModel ProfileEditorViewModel(IScreen hostScreen); + FolderTreeItemViewModel FolderTreeItemViewModel(TreeItemViewModel? parent, Folder folder); + LayerTreeItemViewModel LayerTreeItemViewModel(TreeItemViewModel? parent, Layer layer); + LayerShapeVisualizerViewModel LayerShapeVisualizerViewModel(Layer layer); + LayerVisualizerViewModel LayerVisualizerViewModel(Layer layer); +} +public class ProfileEditorVmFactory : IProfileEditorVmFactory +{ + private readonly IContainer _container; + + public ProfileEditorVmFactory(IContainer container) + { + _container = container; + } + + public FolderTreeItemViewModel FolderTreeItemViewModel(TreeItemViewModel? parent, Folder folder) + { + return _container.Resolve(new object?[] { parent, folder }); + } + + public LayerShapeVisualizerViewModel LayerShapeVisualizerViewModel(Layer layer) + { + return _container.Resolve(new object[] { layer }); + } + + public LayerTreeItemViewModel LayerTreeItemViewModel(TreeItemViewModel? parent, Layer layer) + { + return _container.Resolve(new object?[] { parent, layer }); + } + + public LayerVisualizerViewModel LayerVisualizerViewModel(Layer layer) + { + return _container.Resolve(new object[] { layer }); + } + + public ProfileEditorViewModel ProfileEditorViewModel(IScreen hostScreen) + { + return _container.Resolve(new object[] { hostScreen }); + } +} + +public interface ILayerPropertyVmFactory : IVmFactory +{ + PropertyViewModel PropertyViewModel(ILayerProperty layerProperty); + PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup); + PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerBrush layerBrush); + PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerEffect layerEffect); + + TreeGroupViewModel TreeGroupViewModel(PropertyGroupViewModel propertyGroupViewModel); + + TimelineViewModel TimelineViewModel(ObservableCollection propertyGroupViewModels); + TimelineGroupViewModel TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel); +} +public class LayerPropertyVmFactory : ILayerPropertyVmFactory +{ + private readonly IContainer _container; + + public LayerPropertyVmFactory(IContainer container) + { + _container = container; + } + + public PropertyViewModel PropertyViewModel(ILayerProperty layerProperty) + { + return _container.Resolve(new object[] { layerProperty }); + } + + public PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup) + { + return _container.Resolve(new object[] { layerPropertyGroup }); + } + + public PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerBrush layerBrush) + { + return _container.Resolve(new object[] { layerPropertyGroup, layerBrush }); + } + + public PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerEffect layerEffect) + { + return _container.Resolve(new object[] { layerPropertyGroup, layerEffect }); + } + + public TreeGroupViewModel TreeGroupViewModel(PropertyGroupViewModel propertyGroupViewModel) + { + return _container.Resolve(new object[] { propertyGroupViewModel }); + } + + public TimelineViewModel TimelineViewModel(ObservableCollection propertyGroupViewModels) + { + return _container.Resolve(new object[] { propertyGroupViewModels }); + } + + public TimelineGroupViewModel TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel) + { + return _container.Resolve(new object[] { propertyGroupViewModel }); + } +} + +public interface IDataBindingVmFactory : IVmFactory +{ + DataBindingViewModel DataBindingViewModel(); +} +public class DataBindingVmFactory : IDataBindingVmFactory +{ + private readonly IContainer _container; + + public DataBindingVmFactory(IContainer container) + { + _container = container; + } + + public DataBindingViewModel DataBindingViewModel() + { + return _container.Resolve(); + } +} + +public interface IPropertyVmFactory +{ + ITreePropertyViewModel TreePropertyViewModel(ILayerProperty layerProperty, PropertyViewModel propertyViewModel); + ITimelinePropertyViewModel TimelinePropertyViewModel(ILayerProperty layerProperty, PropertyViewModel propertyViewModel); +} + +public interface INodeVmFactory : IVmFactory +{ + NodeScriptViewModel NodeScriptViewModel(NodeScript nodeScript, bool isPreview); + NodePickerViewModel NodePickerViewModel(NodeScript nodeScript); + NodeViewModel NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node); + CableViewModel CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to); + DragCableViewModel DragCableViewModel(PinViewModel pinViewModel); + InputPinViewModel InputPinViewModel(IPin inputPin, NodeScriptViewModel nodeScriptViewModel); + OutputPinViewModel OutputPinViewModel(IPin outputPin, NodeScriptViewModel nodeScriptViewModel); + InputPinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel); + OutputPinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel); +} +public class NodeVmFactory : INodeVmFactory +{ + private readonly IContainer _container; + + public NodeVmFactory(IContainer container) + { + _container = container; + } + + public NodeScriptViewModel NodeScriptViewModel(NodeScript nodeScript, bool isPreview) + { + return _container.Resolve(new object[] { nodeScript, isPreview }); + } + + public NodePickerViewModel NodePickerViewModel(NodeScript nodeScript) + { + return _container.Resolve(new object[] { nodeScript }); + } + + public NodeViewModel NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node) + { + return _container.Resolve(new object[] { nodeScriptViewModel, node }); + } + + public CableViewModel CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to) + { + return _container.Resolve(new object[] { nodeScriptViewModel, from, to }); + } + + public DragCableViewModel DragCableViewModel(PinViewModel pinViewModel) + { + return _container.Resolve(new object[] { pinViewModel }); + } + + public InputPinViewModel InputPinViewModel(IPin inputPin, NodeScriptViewModel nodeScriptViewModel) + { + return _container.Resolve(new object[] { inputPin, nodeScriptViewModel }); + } + + public OutputPinViewModel OutputPinViewModel(IPin outputPin, NodeScriptViewModel nodeScriptViewModel) + { + return _container.Resolve(new object[] { outputPin, nodeScriptViewModel }); + } + + public InputPinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel) + { + return _container.Resolve(new object[] { inputPinCollection, nodeScriptViewModel }); + } + + public OutputPinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel) + { + return _container.Resolve(new object[] { outputPinCollection, nodeScriptViewModel }); + } +} + +public interface IConditionVmFactory : IVmFactory +{ + AlwaysOnConditionViewModel AlwaysOnConditionViewModel(AlwaysOnCondition alwaysOnCondition); + PlayOnceConditionViewModel PlayOnceConditionViewModel(PlayOnceCondition playOnceCondition); + StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition); + EventConditionViewModel EventConditionViewModel(EventCondition eventCondition); +} +public class ConditionVmFactory : IConditionVmFactory +{ + private readonly IContainer _container; + + public ConditionVmFactory(IContainer container) + { + _container = container; + } + + public AlwaysOnConditionViewModel AlwaysOnConditionViewModel(AlwaysOnCondition alwaysOnCondition) + { + return _container.Resolve(new object[] { alwaysOnCondition }); + } + + public PlayOnceConditionViewModel PlayOnceConditionViewModel(PlayOnceCondition playOnceCondition) + { + return _container.Resolve(new object[] { playOnceCondition }); + } + + public StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition) + { + return _container.Resolve(new object[] { staticCondition }); + } + + public EventConditionViewModel EventConditionViewModel(EventCondition eventCondition) + { + return _container.Resolve(new object[] { eventCondition }); + } +} + +public interface ILayerHintVmFactory : IVmFactory +{ + CategoryAdaptionHintViewModel CategoryAdaptionHintViewModel(Layer layer, CategoryAdaptionHint adaptionHint); + DeviceAdaptionHintViewModel DeviceAdaptionHintViewModel(Layer layer, DeviceAdaptionHint adaptionHint); + KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(Layer layer, KeyboardSectionAdaptionHint adaptionHint); +} +public class LayerHintVmFactory : ILayerHintVmFactory +{ + private readonly IContainer _container; + + public LayerHintVmFactory(IContainer container) + { + _container = container; + } + + public CategoryAdaptionHintViewModel CategoryAdaptionHintViewModel(Layer layer, CategoryAdaptionHint adaptionHint) + { + return _container.Resolve(new object[] { layer, adaptionHint }); + } + + public DeviceAdaptionHintViewModel DeviceAdaptionHintViewModel(Layer layer, DeviceAdaptionHint adaptionHint) + { + return _container.Resolve(new object[] { layer, adaptionHint }); + } + + public KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(Layer layer, KeyboardSectionAdaptionHint adaptionHint) + { + return _container.Resolve(new object[] { layer, adaptionHint }); + } +} + +public interface IScriptVmFactory : IVmFactory +{ + ScriptConfigurationViewModel ScriptConfigurationViewModel(ScriptConfiguration scriptConfiguration); + ScriptConfigurationViewModel ScriptConfigurationViewModel(Profile profile, ScriptConfiguration scriptConfiguration); +} +public class ScriptVmFactory : IScriptVmFactory +{ + private readonly IContainer _container; + + public ScriptVmFactory(IContainer container) + { + _container = container; + } + + public ScriptConfigurationViewModel ScriptConfigurationViewModel(ScriptConfiguration scriptConfiguration) + { + return _container.Resolve(new object[] { scriptConfiguration }); + } + + public ScriptConfigurationViewModel ScriptConfigurationViewModel(Profile profile, ScriptConfiguration scriptConfiguration) + { + return _container.Resolve(new object[] { profile, scriptConfiguration }); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/DryIoc/InstanceProviders/LayerPropertyViewModelInstanceProvider.cs b/src/Artemis.UI/DryIoc/InstanceProviders/LayerPropertyViewModelInstanceProvider.cs new file mode 100644 index 000000000..108caeb84 --- /dev/null +++ b/src/Artemis.UI/DryIoc/InstanceProviders/LayerPropertyViewModelInstanceProvider.cs @@ -0,0 +1,47 @@ +using System; +using Artemis.Core; +using Artemis.UI.DryIoc.Factories; +using Artemis.UI.Exceptions; +using Artemis.UI.Screens.ProfileEditor.Properties; +using Artemis.UI.Screens.ProfileEditor.Properties.Timeline; +using Artemis.UI.Screens.ProfileEditor.Properties.Tree; +using DryIoc; + +namespace Artemis.UI.DryIoc.InstanceProviders; + +public class PropertyVmFactory : IPropertyVmFactory +{ + private readonly IContainer _container; + + public PropertyVmFactory(IContainer container) + { + _container = container; + } + + public ITimelinePropertyViewModel TimelinePropertyViewModel(ILayerProperty layerProperty, PropertyViewModel propertyViewModel) + { + // Find LayerProperty type + Type? layerPropertyType = layerProperty.GetType(); + while (layerPropertyType != null && (!layerPropertyType.IsGenericType || layerPropertyType.GetGenericTypeDefinition() != typeof(LayerProperty<>))) + layerPropertyType = layerPropertyType.BaseType; + if (layerPropertyType == null) + throw new ArtemisUIException("Could not find the LayerProperty type"); + + Type? genericType = typeof(TimelinePropertyViewModel<>).MakeGenericType(layerPropertyType.GetGenericArguments()); + return (ITimelinePropertyViewModel)_container.Resolve(genericType, new object[] { layerProperty, propertyViewModel }); + } + + public ITreePropertyViewModel TreePropertyViewModel(ILayerProperty layerProperty, PropertyViewModel propertyViewModel) + { + // Find LayerProperty type + Type? layerPropertyType = layerProperty.GetType(); + while (layerPropertyType != null && (!layerPropertyType.IsGenericType || layerPropertyType.GetGenericTypeDefinition() != typeof(LayerProperty<>))) + layerPropertyType = layerPropertyType.BaseType; + if (layerPropertyType == null) + throw new ArtemisUIException("Could not find the LayerProperty type"); + + Type? genericType = typeof(TreePropertyViewModel<>).MakeGenericType(layerPropertyType.GetGenericArguments()); + + return (ITreePropertyViewModel)_container.Resolve(genericType, new object[] { layerProperty, propertyViewModel }); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/DryIoc/UiModule.cs b/src/Artemis.UI/DryIoc/UiModule.cs new file mode 100644 index 000000000..652f730d1 --- /dev/null +++ b/src/Artemis.UI/DryIoc/UiModule.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using Artemis.Core.DryIoc; +using Artemis.UI.DryIoc.Factories; +using Artemis.UI.DryIoc.InstanceProviders; +using Artemis.UI.Screens; +using Artemis.UI.Screens.VisualScripting; +using Artemis.UI.Services.Interfaces; +using Artemis.UI.Shared; +using Artemis.UI.Shared.Services.NodeEditor; +using Artemis.UI.Shared.Services.ProfileEditor; +using Avalonia.Platform; +using Avalonia.Shared.PlatformSupport; +using DryIoc; + +namespace Artemis.UI.DryIoc; + +public class UIModule : IModule +{ + public void Load(IRegistrator builder) + { + Assembly thisAssembly = typeof(UIModule).Assembly; + + builder.RegisterInstance(new AssetLoader(), IfAlreadyRegistered.Throw); + builder.Register(Reuse.Singleton); + + builder.RegisterMany(new[] { thisAssembly }, type => type.IsAssignableTo()); + builder.RegisterMany(new[] { thisAssembly }, type => type.IsAssignableTo(), ifAlreadyRegistered: IfAlreadyRegistered.Replace); + builder.RegisterMany(new[] { thisAssembly }, type => type.IsAssignableTo() && type.IsInterface); + builder.RegisterMany(new[] { thisAssembly }, type => type.IsAssignableTo() && type != typeof(PropertyVmFactory)); + + builder.Register(Reuse.Singleton); + builder.Register(Reuse.Singleton); + + builder.RegisterMany(new[] { thisAssembly }, type => type.IsAssignableTo(), Reuse.Singleton); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Models/NodesClipboardModel.cs b/src/Artemis.UI/Models/NodesClipboardModel.cs index 842d5348d..42cd9832f 100644 --- a/src/Artemis.UI/Models/NodesClipboardModel.cs +++ b/src/Artemis.UI/Models/NodesClipboardModel.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using Artemis.Core; using Artemis.Storage.Entities.Profile.Nodes; -using FluentAvalonia.Core; namespace Artemis.UI.Models; diff --git a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs deleted file mode 100644 index 06d0b3dfa..000000000 --- a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System.Collections.ObjectModel; -using System.Reactive; -using Artemis.Core; -using Artemis.Core.LayerBrushes; -using Artemis.Core.LayerEffects; -using Artemis.Core.ScriptingProviders; -using Artemis.UI.Screens.Device; -using Artemis.UI.Screens.Plugins; -using Artemis.UI.Screens.ProfileEditor; -using Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes; -using Artemis.UI.Screens.ProfileEditor.ProfileTree; -using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints; -using Artemis.UI.Screens.ProfileEditor.Properties; -using Artemis.UI.Screens.ProfileEditor.Properties.DataBinding; -using Artemis.UI.Screens.ProfileEditor.Properties.Timeline; -using Artemis.UI.Screens.ProfileEditor.Properties.Tree; -using Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers; -using Artemis.UI.Screens.Scripting; -using Artemis.UI.Screens.Settings; -using Artemis.UI.Screens.Sidebar; -using Artemis.UI.Screens.SurfaceEditor; -using Artemis.UI.Screens.VisualScripting; -using Artemis.UI.Screens.VisualScripting.Pins; -using ReactiveUI; - -namespace Artemis.UI.Ninject.Factories; - -public interface IVmFactory -{ -} - -public interface IDeviceVmFactory : IVmFactory -{ - DevicePropertiesViewModel DevicePropertiesViewModel(ArtemisDevice device); - DeviceSettingsViewModel DeviceSettingsViewModel(ArtemisDevice device, DevicesTabViewModel devicesTabViewModel); - DeviceDetectInputViewModel DeviceDetectInputViewModel(ArtemisDevice device); - DevicePropertiesTabViewModel DevicePropertiesTabViewModel(ArtemisDevice device); - DeviceInfoTabViewModel DeviceInfoTabViewModel(ArtemisDevice device); - DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device, ObservableCollection selectedLeds); - InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection selectedLeds); -} - -public interface ISettingsVmFactory : IVmFactory -{ - PluginSettingsViewModel PluginSettingsViewModel(Plugin plugin); - PluginViewModel PluginViewModel(Plugin plugin, ReactiveCommand? reload); - PluginFeatureViewModel PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo, bool showShield); -} - -public interface ISidebarVmFactory : IVmFactory -{ - SidebarViewModel? SidebarViewModel(IScreen hostScreen); - SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory); - SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration); -} - -public interface ISurfaceVmFactory : IVmFactory -{ - SurfaceDeviceViewModel SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel); - ListDeviceViewModel ListDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel); -} - -public interface IPrerequisitesVmFactory : IVmFactory -{ - PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall); -} - -public interface IProfileEditorVmFactory : IVmFactory -{ - ProfileEditorViewModel ProfileEditorViewModel(IScreen hostScreen); - FolderTreeItemViewModel FolderTreeItemViewModel(TreeItemViewModel? parent, Folder folder); - LayerTreeItemViewModel LayerTreeItemViewModel(TreeItemViewModel? parent, Layer layer); - LayerShapeVisualizerViewModel LayerShapeVisualizerViewModel(Layer layer); - LayerVisualizerViewModel LayerVisualizerViewModel(Layer layer); -} - -public interface ILayerPropertyVmFactory : IVmFactory -{ - PropertyViewModel PropertyViewModel(ILayerProperty layerProperty); - PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup); - PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerBrush layerBrush); - PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerEffect layerEffect); - - TreeGroupViewModel TreeGroupViewModel(PropertyGroupViewModel propertyGroupViewModel); - - TimelineViewModel TimelineViewModel(ObservableCollection propertyGroupViewModels); - TimelineGroupViewModel TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel); -} - -public interface IDataBindingVmFactory : IVmFactory -{ - DataBindingViewModel DataBindingViewModel(); -} - -public interface IPropertyVmFactory -{ - ITreePropertyViewModel TreePropertyViewModel(ILayerProperty layerProperty, PropertyViewModel propertyViewModel); - ITimelinePropertyViewModel TimelinePropertyViewModel(ILayerProperty layerProperty, PropertyViewModel propertyViewModel); -} - -public interface INodeVmFactory : IVmFactory -{ - NodeScriptViewModel NodeScriptViewModel(NodeScript nodeScript, bool isPreview); - NodePickerViewModel NodePickerViewModel(NodeScript nodeScript); - NodeViewModel NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node); - CableViewModel CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to); - DragCableViewModel DragCableViewModel(PinViewModel pinViewModel); - InputPinViewModel InputPinViewModel(IPin inputPin, NodeScriptViewModel nodeScriptViewModel); - OutputPinViewModel OutputPinViewModel(IPin outputPin, NodeScriptViewModel nodeScriptViewModel); - InputPinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel); - OutputPinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel); -} - -public interface IConditionVmFactory : IVmFactory -{ - AlwaysOnConditionViewModel AlwaysOnConditionViewModel(AlwaysOnCondition alwaysOnCondition); - PlayOnceConditionViewModel PlayOnceConditionViewModel(PlayOnceCondition playOnceCondition); - StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition); - EventConditionViewModel EventConditionViewModel(EventCondition eventCondition); -} - -public interface ILayerHintVmFactory : IVmFactory -{ - CategoryAdaptionHintViewModel CategoryAdaptionHintViewModel(Layer layer, CategoryAdaptionHint adaptionHint); - DeviceAdaptionHintViewModel DeviceAdaptionHintViewModel(Layer layer, DeviceAdaptionHint adaptionHint); - KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(Layer layer, KeyboardSectionAdaptionHint adaptionHint); -} - -public interface IScriptVmFactory : IVmFactory -{ - ScriptConfigurationViewModel ScriptConfigurationViewModel(ScriptConfiguration scriptConfiguration); - ScriptConfigurationViewModel ScriptConfigurationViewModel(Profile profile, ScriptConfiguration scriptConfiguration); -} \ No newline at end of file diff --git a/src/Artemis.UI/Ninject/InstanceProviders/LayerPropertyViewModelInstanceProvider.cs b/src/Artemis.UI/Ninject/InstanceProviders/LayerPropertyViewModelInstanceProvider.cs deleted file mode 100644 index 9e0a40c4f..000000000 --- a/src/Artemis.UI/Ninject/InstanceProviders/LayerPropertyViewModelInstanceProvider.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Reflection; -using Artemis.Core; -using Artemis.UI.Screens.ProfileEditor.Properties.Timeline; -using Artemis.UI.Screens.ProfileEditor.Properties.Tree; -using Ninject.Extensions.Factory; - -namespace Artemis.UI.Ninject.InstanceProviders; - -public class LayerPropertyViewModelInstanceProvider : StandardInstanceProvider -{ - protected override Type GetType(MethodInfo methodInfo, object[] arguments) - { - if (methodInfo.ReturnType != typeof(ITreePropertyViewModel) && methodInfo.ReturnType != typeof(ITimelinePropertyViewModel)) - return base.GetType(methodInfo, arguments); - - // Find LayerProperty type - Type? layerPropertyType = arguments[0].GetType(); - while (layerPropertyType != null && (!layerPropertyType.IsGenericType || layerPropertyType.GetGenericTypeDefinition() != typeof(LayerProperty<>))) - layerPropertyType = layerPropertyType.BaseType; - if (layerPropertyType == null) - return base.GetType(methodInfo, arguments); - - if (methodInfo.ReturnType == typeof(ITreePropertyViewModel)) - return typeof(TreePropertyViewModel<>).MakeGenericType(layerPropertyType.GetGenericArguments()); - if (methodInfo.ReturnType == typeof(ITimelinePropertyViewModel)) - return typeof(TimelinePropertyViewModel<>).MakeGenericType(layerPropertyType.GetGenericArguments()); - - return base.GetType(methodInfo, arguments); - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Ninject/UiModule.cs b/src/Artemis.UI/Ninject/UiModule.cs deleted file mode 100644 index 41a355fbb..000000000 --- a/src/Artemis.UI/Ninject/UiModule.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using Artemis.UI.Ninject.Factories; -using Artemis.UI.Ninject.InstanceProviders; -using Artemis.UI.Screens; -using Artemis.UI.Screens.VisualScripting; -using Artemis.UI.Services.Interfaces; -using Artemis.UI.Shared; -using Artemis.UI.Shared.Services.NodeEditor; -using Artemis.UI.Shared.Services.ProfileEditor; -using Avalonia.Platform; -using Avalonia.Shared.PlatformSupport; -using Ninject.Extensions.Conventions; -using Ninject.Extensions.Factory; -using Ninject.Modules; -using Ninject.Planning.Bindings.Resolvers; - -namespace Artemis.UI.Ninject; - -public class UIModule : NinjectModule -{ - public override void Load() - { - if (Kernel == null) - throw new ArgumentNullException("Kernel shouldn't be null here."); - - Kernel.Components.Add(); - Kernel.Bind().ToConstant(new AssetLoader()); - - Kernel.Bind(x => - { - x.FromThisAssembly() - .SelectAllClasses() - .InheritedFrom() - .BindToSelf(); - }); - - Kernel.Bind(x => - { - x.FromThisAssembly() - .SelectAllClasses() - .InheritedFrom() - .BindAllBaseClasses(); - }); - - Kernel.Bind(x => - { - x.FromThisAssembly() - .SelectAllClasses() - .InheritedFrom() - .BindAllInterfaces(); - }); - - // Bind UI factories - Kernel.Bind(x => - { - x.FromThisAssembly() - .SelectAllInterfaces() - .InheritedFrom() - .BindToFactory(); - }); - - Kernel.Bind().To(); - Kernel.Bind().ToFactory(() => new LayerPropertyViewModelInstanceProvider()); - - // Bind all UI services as singletons - Kernel.Bind(x => - { - x.FromThisAssembly() - .SelectAllClasses() - .InheritedFrom() - .BindAllInterfaces() - .Configure(c => c.InSingletonScope()); - }); - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs b/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs index d0200cb70..87ee3ae20 100644 --- a/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs +++ b/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs @@ -4,7 +4,7 @@ using System.Reactive; using System.Reactive.Disposables; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Shared; using ReactiveUI; using RGB.NET.Core; diff --git a/src/Artemis.UI/Screens/Device/DeviceSettingsViewModel.cs b/src/Artemis.UI/Screens/Device/DeviceSettingsViewModel.cs index 01a293411..52faba0d3 100644 --- a/src/Artemis.UI/Screens/Device/DeviceSettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Device/DeviceSettingsViewModel.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.Settings; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; @@ -82,7 +82,7 @@ public class DeviceSettingsViewModel : ActivatableViewModelBase await _windowService.CreateContentDialog() .WithTitle($"{Device.RgbDevice.DeviceInfo.DeviceName} - Detect input") - .WithViewModel(out DeviceDetectInputViewModel? viewModel, ("device", Device)) + .WithViewModel(out DeviceDetectInputViewModel viewModel, Device) .WithCloseButtonText("Cancel") .ShowAsync(); diff --git a/src/Artemis.UI/Screens/Device/Tabs/DeviceLogicalLayoutDialogViewModel.cs b/src/Artemis.UI/Screens/Device/Tabs/DeviceLogicalLayoutDialogViewModel.cs index b3f25f1f4..47afd8fdf 100644 --- a/src/Artemis.UI/Screens/Device/Tabs/DeviceLogicalLayoutDialogViewModel.cs +++ b/src/Artemis.UI/Screens/Device/Tabs/DeviceLogicalLayoutDialogViewModel.cs @@ -54,7 +54,7 @@ public class DeviceLogicalLayoutDialogViewModel : ContentDialogViewModelBase { await windowService.CreateContentDialog() .WithTitle("Select logical layout") - .WithViewModel(out DeviceLogicalLayoutDialogViewModel vm, ("device", device)) + .WithViewModel(out DeviceLogicalLayoutDialogViewModel vm, device) .WithCloseButtonText("Cancel") .WithDefaultButton(ContentDialogButton.Primary) .HavingPrimaryButton(b => b.WithText("Select").WithCommand(vm.ApplyLogicalLayout)) diff --git a/src/Artemis.UI/Screens/Device/Tabs/DevicePhysicalLayoutDialogViewModel.cs b/src/Artemis.UI/Screens/Device/Tabs/DevicePhysicalLayoutDialogViewModel.cs index ca6361d81..52e13f6bc 100644 --- a/src/Artemis.UI/Screens/Device/Tabs/DevicePhysicalLayoutDialogViewModel.cs +++ b/src/Artemis.UI/Screens/Device/Tabs/DevicePhysicalLayoutDialogViewModel.cs @@ -25,7 +25,7 @@ public class DevicePhysicalLayoutDialogViewModel : ContentDialogViewModelBase { await windowService.CreateContentDialog() .WithTitle("Select physical layout") - .WithViewModel(out DevicePhysicalLayoutDialogViewModel vm, ("device", device)) + .WithViewModel(out DevicePhysicalLayoutDialogViewModel vm, device) .WithCloseButtonText("Cancel") .ShowAsync(); diff --git a/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesInstallDialogViewModel.cs b/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesInstallDialogViewModel.cs index 4a483373a..b2a698040 100644 --- a/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesInstallDialogViewModel.cs +++ b/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesInstallDialogViewModel.cs @@ -7,7 +7,7 @@ using System.Reactive.Disposables; using System.Threading; using System.Threading.Tasks; using Artemis.Core; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using Avalonia.Threading; @@ -89,7 +89,7 @@ public class PluginPrerequisitesInstallDialogViewModel : ContentDialogViewModelB { await windowService.CreateContentDialog() .WithTitle("Plugin prerequisites") - .WithViewModel(out PluginPrerequisitesInstallDialogViewModel vm, ("subjects", subjects)) + .WithViewModel(out PluginPrerequisitesInstallDialogViewModel vm, subjects) .WithCloseButtonText("Cancel") .HavingPrimaryButton(b => b.WithText("Install").WithCommand(vm.Install)) .WithDefaultButton(ContentDialogButton.Primary) diff --git a/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesUninstallDialogViewModel.cs b/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesUninstallDialogViewModel.cs index d67ff075a..5bbd3e44d 100644 --- a/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesUninstallDialogViewModel.cs +++ b/src/Artemis.UI/Screens/Plugins/Dialogs/PluginPrerequisitesUninstallDialogViewModel.cs @@ -8,7 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using Avalonia.Threading; @@ -74,7 +74,7 @@ public class PluginPrerequisitesUninstallDialogViewModel : ContentDialogViewMode { await windowService.CreateContentDialog() .WithTitle("Plugin prerequisites") - .WithViewModel(out PluginPrerequisitesUninstallDialogViewModel vm, ("subjects", subjects)) + .WithViewModel(out PluginPrerequisitesUninstallDialogViewModel vm, subjects) .WithCloseButtonText(cancelLabel) .HavingPrimaryButton(b => b.WithText("Uninstall").WithCommand(vm.Uninstall)) .WithDefaultButton(ContentDialogButton.Primary) diff --git a/src/Artemis.UI/Screens/Plugins/PluginSettingsViewModel.cs b/src/Artemis.UI/Screens/Plugins/PluginSettingsViewModel.cs index 6f9d2322c..9d3e64329 100644 --- a/src/Artemis.UI/Screens/Plugins/PluginSettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Plugins/PluginSettingsViewModel.cs @@ -4,7 +4,7 @@ using System.Reactive; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using ReactiveUI; diff --git a/src/Artemis.UI/Screens/Plugins/PluginViewModel.cs b/src/Artemis.UI/Screens/Plugins/PluginViewModel.cs index a9b6b037e..24102dc8c 100644 --- a/src/Artemis.UI/Screens/Plugins/PluginViewModel.cs +++ b/src/Artemis.UI/Screens/Plugins/PluginViewModel.cs @@ -13,8 +13,8 @@ using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.Builders; using Avalonia.Controls; using Avalonia.Threading; +using DryIoc; using Material.Icons; -using Ninject; using ReactiveUI; namespace Artemis.UI.Screens.Plugins; @@ -209,8 +209,7 @@ public class PluginViewModel : ActivatableViewModelBase try { - PluginConfigurationViewModel? viewModel = Plugin.Kernel!.Get(Plugin.ConfigurationDialog.Type) as PluginConfigurationViewModel; - if (viewModel == null) + if (Plugin.Resolve(Plugin.ConfigurationDialog.Type) is not PluginConfigurationViewModel viewModel) throw new ArtemisUIException($"The type of a plugin configuration dialog must inherit {nameof(PluginConfigurationViewModel)}"); _window = _windowService.ShowWindow(new PluginSettingsWindowViewModel(viewModel)); diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionViewModel.cs index 570c2391c..7333571c8 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/EventConditionViewModel.cs @@ -78,7 +78,7 @@ public class EventConditionViewModel : ActivatableViewModelBase private async Task ExecuteOpenEditor() { - await _windowService.ShowDialogAsync(("nodeScript", _eventCondition.Script)); + await _windowService.ShowDialogAsync(_eventCondition.Script); await _profileEditorService.SaveProfileAsync(); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/StaticConditionViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/StaticConditionViewModel.cs index 470be0bc0..086c67091 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/StaticConditionViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/ConditionTypes/StaticConditionViewModel.cs @@ -51,7 +51,7 @@ public class StaticConditionViewModel : ActivatableViewModelBase private async Task ExecuteOpenEditor() { - await _windowService.ShowDialogAsync(("nodeScript", _staticCondition.Script)); + await _windowService.ShowDialogAsync(_staticCondition.Script); await _profileEditorService.SaveProfileAsync(); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/DisplayConditionScriptViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/DisplayConditionScriptViewModel.cs index 260270e6b..87b0a3104 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/DisplayConditionScriptViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/DisplayConditionScriptViewModel.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Reactive.Linq; using Artemis.Core; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Shared; using Artemis.UI.Shared.Services.ProfileEditor; using Artemis.UI.Shared.Services.ProfileEditor.Commands; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs index a722b3f3d..b7cf96087 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarViewModel.cs @@ -137,10 +137,7 @@ public class MenuBarViewModel : ActivatableViewModelBase if (ProfileConfiguration == null) return; - await _windowService.ShowDialogAsync( - ("profileCategory", ProfileConfiguration.Category), - ("profileConfiguration", ProfileConfiguration) - ); + await _windowService.ShowDialogAsync(ProfileConfiguration.Category, ProfileConfiguration); } private async Task ExecuteViewScripts() @@ -148,7 +145,7 @@ public class MenuBarViewModel : ActivatableViewModelBase if (ProfileConfiguration?.Profile == null) return; - await _windowService.ShowDialogAsync(("profile", ProfileConfiguration.Profile)); + await _windowService.ShowDialogAsync(ProfileConfiguration.Profile); await _profileEditorService.SaveProfileAsync(); } diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogViewModel.cs index baac1b81f..bb33b620b 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogViewModel.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Reactive.Linq; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints; using Artemis.UI.Shared; using Avalonia.Controls.Mixins; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs index bb8e7492e..c8c54bdca 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemViewModel.cs @@ -4,8 +4,8 @@ using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; using Artemis.Storage.Entities.Profile; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Extensions; -using Artemis.UI.Ninject.Factories; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.ProfileEditor; using Artemis.UI.Shared.Services.ProfileEditor.Commands; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs index 526c5412d..f3c63fc4e 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemViewModel.cs @@ -4,8 +4,8 @@ using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; using Artemis.Storage.Entities.Profile; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Extensions; -using Artemis.UI.Ninject.Factories; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.ProfileEditor; using Artemis.UI.Shared.Services.ProfileEditor.Commands; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeViewModel.cs index 012ef9070..adbd6153d 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeViewModel.cs @@ -7,7 +7,7 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Threading.Tasks; using Artemis.Core; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.ProfileEditor; using ReactiveUI; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs index 95e9b7f01..1ff9b311a 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs @@ -7,8 +7,8 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using System.Threading.Tasks; using Artemis.Core; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Extensions; -using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; @@ -274,7 +274,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase if (ProfileElement is not Layer layer) return; - await _windowService.ShowDialogAsync(("layer", layer)); + await _windowService.ShowDialogAsync(layer); await ProfileEditorService.SaveProfileAsync(); } diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingViewModel.cs index cb155b447..078452a81 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingViewModel.cs @@ -4,8 +4,8 @@ using System.Reactive.Linq; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Extensions; -using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.VisualScripting; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; @@ -88,7 +88,7 @@ public class DataBindingViewModel : ActivatableViewModelBase try { _editorOpen = true; - await _windowService.ShowDialogAsync(("nodeScript", LayerProperty.BaseDataBinding.Script)); + await _windowService.ShowDialogAsync(LayerProperty.BaseDataBinding.Script); await _profileEditorService.SaveProfileAsync(); } finally diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesViewModel.cs index 6471d49c8..c44a41f48 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesViewModel.cs @@ -10,7 +10,7 @@ using Artemis.Core; using Artemis.Core.LayerBrushes; using Artemis.Core.LayerEffects; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.ProfileEditor.Playback; using Artemis.UI.Screens.ProfileEditor.Properties.DataBinding; using Artemis.UI.Screens.ProfileEditor.Properties.Dialogs; @@ -124,7 +124,7 @@ public class PropertiesViewModel : ActivatableViewModelBase await _windowService.CreateContentDialog() .WithTitle("Add layer effect") - .WithViewModel(out AddEffectViewModel _, ("renderProfileElement", ProfileElement)) + .WithViewModel(out AddEffectViewModel _, ProfileElement) .WithCloseButtonText("Cancel") .ShowAsync(); } diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertyGroupViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertyGroupViewModel.cs index 0689a7ed2..bb0c78c20 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertyGroupViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertyGroupViewModel.cs @@ -6,7 +6,7 @@ using System.Reflection; using Artemis.Core; using Artemis.Core.LayerBrushes; using Artemis.Core.LayerEffects; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.ProfileEditor.Properties.Timeline; using Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes; using Artemis.UI.Screens.ProfileEditor.Properties.Tree; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertyViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertyViewModel.cs index bfb6b2353..2caf34931 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertyViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertyViewModel.cs @@ -1,7 +1,7 @@ using System; using System.Collections.ObjectModel; using Artemis.Core; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.ProfileEditor.Properties.Timeline; using Artemis.UI.Screens.ProfileEditor.Properties.Tree; using DynamicData; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/TimelineSegmentViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/TimelineSegmentViewModel.cs index cebf376f0..b2d7687f4 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/TimelineSegmentViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Segments/TimelineSegmentViewModel.cs @@ -225,7 +225,7 @@ public abstract class TimelineSegmentViewModel : ActivatableViewModelBase { await _windowService.CreateContentDialog() .WithTitle("Edit segment length") - .WithViewModel(out TimelineSegmentEditViewModel vm, ("segmentLength", Length)) + .WithViewModel(out TimelineSegmentEditViewModel vm, Length) .HavingPrimaryButton(b => b.WithText("Save").WithAction(() => { if (_profileElement != null) diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreeGroupViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreeGroupViewModel.cs index c870e291b..9a5409908 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreeGroupViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreeGroupViewModel.cs @@ -1,6 +1,5 @@ using System; using System.Collections.ObjectModel; -using System.Linq; using System.Reactive; using System.Reactive.Disposables; using System.Reflection; @@ -18,8 +17,6 @@ using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.Builders; using Artemis.UI.Shared.Services.ProfileEditor; using Artemis.UI.Shared.Services.ProfileEditor.Commands; -using Ninject; -using Ninject.Parameters; using ReactiveUI; namespace Artemis.UI.Screens.ProfileEditor.Properties.Tree; @@ -88,12 +85,7 @@ public class TreeGroupViewModel : ActivatableViewModelBase if (constructors.Length != 1) throw new ArtemisUIException("Brush configuration dialogs must have exactly one constructor"); - // Find the BaseLayerBrush parameter, it is required by the base constructor so its there for sure - ParameterInfo brushParameter = constructors.First().GetParameters().First(p => typeof(BaseLayerBrush).IsAssignableFrom(p.ParameterType)); - ConstructorArgument argument = new(brushParameter.Name!, LayerBrush); - BrushConfigurationViewModel viewModel = - (BrushConfigurationViewModel) LayerBrush.Descriptor.Provider.Plugin.Kernel!.Get(configurationViewModel.Type, argument); - + BrushConfigurationViewModel viewModel = (BrushConfigurationViewModel) LayerBrush.Descriptor.Provider.Plugin.Resolve(configurationViewModel.Type, LayerBrush); _brushConfigurationWindowViewModel = new BrushConfigurationWindowViewModel(viewModel, configurationViewModel); await _windowService.ShowDialogAsync(_brushConfigurationWindowViewModel); @@ -118,12 +110,7 @@ public class TreeGroupViewModel : ActivatableViewModelBase if (constructors.Length != 1) throw new ArtemisUIException("Effect configuration dialogs must have exactly one constructor"); - // Find the BaseLayerEffect parameter, it is required by the base constructor so its there for sure - ParameterInfo effectParameter = constructors.First().GetParameters().First(p => typeof(BaseLayerEffect).IsAssignableFrom(p.ParameterType)); - ConstructorArgument argument = new(effectParameter.Name!, LayerEffect); - EffectConfigurationViewModel viewModel = - (EffectConfigurationViewModel) LayerEffect.Descriptor.Provider.Plugin.Kernel!.Get(configurationViewModel.Type, argument); - + EffectConfigurationViewModel viewModel = (EffectConfigurationViewModel) LayerEffect.Descriptor.Provider.Plugin.Resolve(configurationViewModel.Type, LayerEffect); _effectConfigurationWindowViewModel = new EffectConfigurationWindowViewModel(viewModel, configurationViewModel); await _windowService.ShowDialogAsync(_effectConfigurationWindowViewModel); @@ -143,7 +130,7 @@ public class TreeGroupViewModel : ActivatableViewModelBase await _windowService.CreateContentDialog() .WithTitle("Rename layer effect") - .WithViewModel(out LayerEffectRenameViewModel vm, ("layerEffect", LayerEffect)) + .WithViewModel(out LayerEffectRenameViewModel vm, LayerEffect) .HavingPrimaryButton(b => b.WithText("Confirm").WithCommand(vm.Confirm)) .WithCloseButtonText("Cancel") .WithDefaultButton(ContentDialogButton.Primary) diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorViewModel.cs index 4e767743d..256595ce8 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorViewModel.cs @@ -7,7 +7,7 @@ using System.Reactive.Disposables; using System.Reactive.Linq; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers; using Artemis.UI.Shared; using Artemis.UI.Shared.Services.ProfileEditor; diff --git a/src/Artemis.UI/Screens/Root/RootViewModel.cs b/src/Artemis.UI/Screens/Root/RootViewModel.cs index b9175e9ed..b2ba9e8cd 100644 --- a/src/Artemis.UI/Screens/Root/RootViewModel.cs +++ b/src/Artemis.UI/Screens/Root/RootViewModel.cs @@ -3,15 +3,14 @@ using System.Linq; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Models; -using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.Sidebar; using Artemis.UI.Services.Interfaces; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.MainWindow; using Avalonia; -using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Platform; using Avalonia.Threading; diff --git a/src/Artemis.UI/Screens/Scripting/ScriptConfigurationViewModel.cs b/src/Artemis.UI/Screens/Scripting/ScriptConfigurationViewModel.cs index 02ea67370..6bba01f5d 100644 --- a/src/Artemis.UI/Screens/Scripting/ScriptConfigurationViewModel.cs +++ b/src/Artemis.UI/Screens/Scripting/ScriptConfigurationViewModel.cs @@ -44,7 +44,7 @@ public class ScriptConfigurationViewModel : ActivatableViewModelBase { ContentDialogResult contentDialogResult = await _windowService.CreateContentDialog() .WithTitle("Edit script") - .WithViewModel(out ScriptConfigurationEditViewModel vm, ("scriptConfiguration", scriptConfiguration)) + .WithViewModel(out ScriptConfigurationEditViewModel vm, scriptConfiguration) .WithCloseButtonText("Cancel") .HavingPrimaryButton(b => b.WithText("Confirm").WithCommand(vm.Submit)) .HavingSecondaryButton(b => b.WithText("Delete")) diff --git a/src/Artemis.UI/Screens/Scripting/ScriptsDialogViewModel.cs b/src/Artemis.UI/Screens/Scripting/ScriptsDialogViewModel.cs index 9f50cb387..dcd4b4a3f 100644 --- a/src/Artemis.UI/Screens/Scripting/ScriptsDialogViewModel.cs +++ b/src/Artemis.UI/Screens/Scripting/ScriptsDialogViewModel.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.ScriptingProviders; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.Scripting.Dialogs; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; diff --git a/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml b/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml index 2b0c9aee5..3f3571c93 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/AboutTabView.axaml @@ -191,6 +191,7 @@ Avalonia + DryIoc FluentAvalonia EmbedIO Furl.Http @@ -198,7 +199,6 @@ LiteDB McMaster.NETCore.Plugins Newtonsoft.Json - Ninject RGB.NET Serilog SkiaSharp @@ -208,6 +208,9 @@ https://avaloniaui.net/ + + https://github.com/dadhi/DryIoc + https://github.com/amwx/FluentAvalonia @@ -229,9 +232,6 @@ https://www.newtonsoft.com/json - - http://www.ninject.org/ - https://github.com/DarthAffe/RGB.NET diff --git a/src/Artemis.UI/Screens/Settings/Tabs/DevicesTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/DevicesTabViewModel.cs index 2d10b9ba5..620da173e 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/DevicesTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/DevicesTabViewModel.cs @@ -6,7 +6,7 @@ using System.Reactive.Linq; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.Device; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; diff --git a/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs index b0215e523..06d212fa1 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/GeneralTabViewModel.cs @@ -16,8 +16,8 @@ using Artemis.UI.Shared; using Artemis.UI.Shared.Providers; using Artemis.UI.Shared.Services; using Avalonia.Threading; +using DryIoc; using DynamicData; -using Ninject; using ReactiveUI; using Serilog.Events; @@ -33,7 +33,7 @@ public class GeneralTabViewModel : ActivatableViewModelBase private readonly IWindowService _windowService; private bool _startupWizardOpen; - public GeneralTabViewModel(IKernel kernel, + public GeneralTabViewModel(IContainer container, ISettingsService settingsService, IPluginManagementService pluginManagementService, IDebugService debugService, @@ -45,10 +45,10 @@ public class GeneralTabViewModel : ActivatableViewModelBase _debugService = debugService; _windowService = windowService; _updateService = updateService; - _autoRunProvider = kernel.TryGet(); + _autoRunProvider = container.Resolve(IfUnresolved.ReturnDefault); List layerBrushProviders = pluginManagementService.GetFeaturesOfType(); - List graphicsContextProviders = kernel.Get>(); + List graphicsContextProviders = container.Resolve>(); LayerBrushDescriptors = new ObservableCollection(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors)); GraphicsContexts = new ObservableCollection {"Software"}; GraphicsContexts.AddRange(graphicsContextProviders.Select(p => p.GraphicsContextName)); diff --git a/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabViewModel.cs index 388c7fbc4..b45ea27cb 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabViewModel.cs @@ -7,7 +7,7 @@ using System.Reactive.Linq; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.Plugins; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; diff --git a/src/Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditViewModel.cs b/src/Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditViewModel.cs index 66d186faf..5096cc2d3 100644 --- a/src/Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditViewModel.cs @@ -15,10 +15,10 @@ public class SidebarCategoryEditViewModel : ContentDialogViewModelBase private readonly IProfileService _profileService; private string? _categoryName; - public SidebarCategoryEditViewModel(IProfileService profileService, ProfileCategory? category) + public SidebarCategoryEditViewModel(IProfileService profileService, ProfileCategory category) { _profileService = profileService; - _category = category; + _category = category == ProfileCategory.Empty ? null : category; if (_category != null) _categoryName = _category.Name; diff --git a/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs b/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs index eaaf00480..a84d10ef7 100644 --- a/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Modules; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.VisualScripting; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; @@ -16,7 +16,6 @@ using Artemis.UI.Shared.Services.ProfileEditor; using Avalonia.Media.Imaging; using Avalonia.Threading; using Material.Icons; -using Newtonsoft.Json; using ReactiveUI; namespace Artemis.UI.Screens.Sidebar; @@ -43,7 +42,7 @@ public class ProfileConfigurationEditViewModel : DialogViewModelBase().First().ToString()); + + _profileConfiguration = profileConfiguration == ProfileConfiguration.Empty + ? profileService.CreateProfileConfiguration(profileCategory, "New profile", Enum.GetValues().First().ToString()) + : profileConfiguration; _profileName = _profileConfiguration.Name; _iconType = _profileConfiguration.Icon.IconType; _hotkeyMode = _profileConfiguration.HotkeyMode; @@ -64,11 +66,9 @@ public class ProfileConfigurationEditViewModel : DialogViewModelBase( - pluginManagementService.GetFeaturesOfType().Where(m => !m.IsAlwaysAvailable).Select(m => new ProfileModuleViewModel(m)) - ); + Modules = new ObservableCollection(pluginManagementService.GetFeaturesOfType().Where(m => !m.IsAlwaysAvailable).Select(m => new ProfileModuleViewModel(m))); Modules.Insert(0, null); _selectedModule = Modules.FirstOrDefault(m => m?.Module == _profileConfiguration.Module); @@ -258,7 +258,7 @@ public class ProfileConfigurationEditViewModel : DialogViewModelBase(("nodeScript", ProfileConfiguration.ActivationCondition)); + await _windowService.ShowDialogAsync(ProfileConfiguration.ActivationCondition); } #endregion diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs index 224bb4074..b19f2727c 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs @@ -9,7 +9,7 @@ using System.Reactive.Linq; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.Builders; @@ -146,7 +146,7 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase { await _windowService.CreateContentDialog() .WithTitle("Edit category") - .WithViewModel(out SidebarCategoryEditViewModel vm, ("category", ProfileCategory)) + .WithViewModel(out SidebarCategoryEditViewModel vm, ProfileCategory) .HavingPrimaryButton(b => b.WithText("Confirm").WithCommand(vm.Confirm)) .WithCloseButtonText("Cancel") .WithDefaultButton(ContentDialogButton.Primary) @@ -165,10 +165,7 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase private async Task ExecuteAddProfile() { - ProfileConfiguration? result = await _windowService.ShowDialogAsync( - ("profileCategory", ProfileCategory), - ("profileConfiguration", null) - ); + ProfileConfiguration? result = await _windowService.ShowDialogAsync(ProfileCategory, ProfileConfiguration.Empty); if (result != null) { SidebarProfileConfigurationViewModel viewModel = _vmFactory.SidebarProfileConfigurationViewModel(result); diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs index 8f21f7eca..91824fde6 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs @@ -57,10 +57,7 @@ public class SidebarProfileConfigurationViewModel : ActivatableViewModelBase private async Task ExecuteEditProfile() { - await _windowService.ShowDialogAsync( - ("profileCategory", ProfileConfiguration.Category), - ("profileConfiguration", ProfileConfiguration) - ); + await _windowService.ShowDialogAsync(ProfileConfiguration.Category, ProfileConfiguration); } private void ExecuteToggleSuspended() diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarScreenViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarScreenViewModel.cs index 95d1a643c..51986d0cb 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarScreenViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarScreenViewModel.cs @@ -1,8 +1,7 @@ using System; using Artemis.UI.Shared; +using DryIoc; using Material.Icons; -using Ninject; -using Ninject.Parameters; using ReactiveUI; namespace Artemis.UI.Screens.Sidebar; @@ -15,9 +14,9 @@ public class SidebarScreenViewModel : SidebarScreenViewModel where T : MainSc public override Type ScreenType => typeof(T); - public override MainScreenViewModel CreateInstance(IKernel kernel, IScreen screen) + public override MainScreenViewModel CreateInstance(IContainer container, IScreen screen) { - return kernel.Get(new ConstructorArgument("hostScreen", screen)); + return container.Resolve(new object[] { screen }); } } @@ -32,5 +31,5 @@ public abstract class SidebarScreenViewModel : ViewModelBase public MaterialIconKind Icon { get; } public abstract Type ScreenType { get; } - public abstract MainScreenViewModel CreateInstance(IKernel kernel, IScreen screen); + public abstract MainScreenViewModel CreateInstance(IContainer container, IScreen screen); } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs index 22ae73dec..4c3b971ad 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs @@ -7,7 +7,7 @@ using System.Reactive.Linq; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.Home; using Artemis.UI.Screens.ProfileEditor; using Artemis.UI.Screens.Settings; @@ -18,10 +18,10 @@ using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.Builders; using Artemis.UI.Shared.Services.ProfileEditor; using Avalonia.Threading; +using DryIoc; using DynamicData; using DynamicData.Binding; using Material.Icons; -using Ninject; using ReactiveUI; namespace Artemis.UI.Screens.Sidebar; @@ -29,7 +29,7 @@ namespace Artemis.UI.Screens.Sidebar; public class SidebarViewModel : ActivatableViewModelBase { private readonly IScreen _hostScreen; - private readonly IKernel _kernel; + private readonly IContainer _container; private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorVmFactory _profileEditorVmFactory; private readonly IWindowService _windowService; @@ -37,7 +37,7 @@ public class SidebarViewModel : ActivatableViewModelBase private ReadOnlyObservableCollection _sidebarCategories = new(new ObservableCollection()); public SidebarViewModel(IScreen hostScreen, - IKernel kernel, + IContainer container, IProfileService profileService, IWindowService windowService, IProfileEditorService profileEditorService, @@ -45,7 +45,7 @@ public class SidebarViewModel : ActivatableViewModelBase IProfileEditorVmFactory profileEditorVmFactory) { _hostScreen = hostScreen; - _kernel = kernel; + _container = container; _windowService = windowService; _profileEditorService = profileEditorService; _profileEditorVmFactory = profileEditorVmFactory; @@ -120,7 +120,7 @@ public class SidebarViewModel : ActivatableViewModelBase { await _windowService.CreateContentDialog() .WithTitle("Add new category") - .WithViewModel(out SidebarCategoryEditViewModel vm, ("category", null)) + .WithViewModel(out SidebarCategoryEditViewModel vm, ProfileCategory.Empty) .HavingPrimaryButton(b => b.WithText("Confirm").WithCommand(vm.Confirm)) .WithCloseButtonText("Cancel") .WithDefaultButton(ContentDialogButton.Primary) @@ -137,7 +137,7 @@ public class SidebarViewModel : ActivatableViewModelBase private void NavigateToScreen(SidebarScreenViewModel sidebarScreenViewModel) { - _hostScreen.Router.Navigate.Execute(sidebarScreenViewModel.CreateInstance(_kernel, _hostScreen)); + _hostScreen.Router.Navigate.Execute(sidebarScreenViewModel.CreateInstance(_container, _hostScreen)); _profileEditorService.ChangeCurrentProfileConfiguration(null); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/StartupWizard/StartupWizardViewModel.cs b/src/Artemis.UI/Screens/StartupWizard/StartupWizardViewModel.cs index 2c509c971..e2a3e516a 100644 --- a/src/Artemis.UI/Screens/StartupWizard/StartupWizardViewModel.cs +++ b/src/Artemis.UI/Screens/StartupWizard/StartupWizardViewModel.cs @@ -8,13 +8,13 @@ using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.DeviceProviders; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.Plugins; using Artemis.UI.Services.Interfaces; using Artemis.UI.Shared; using Artemis.UI.Shared.Providers; using Artemis.UI.Shared.Services; -using Ninject; +using DryIoc; using ReactiveUI; namespace Artemis.UI.Screens.StartupWizard; @@ -31,14 +31,14 @@ public class StartupWizardViewModel : DialogViewModelBase private bool _showFinish; private bool _showGoBack; - public StartupWizardViewModel(IKernel kernel, ISettingsService settingsService, IRgbService rgbService, IPluginManagementService pluginManagementService, IWindowService windowService, + public StartupWizardViewModel(IContainer container, ISettingsService settingsService, IRgbService rgbService, IPluginManagementService pluginManagementService, IWindowService windowService, IUpdateService updateService, ISettingsVmFactory settingsVmFactory) { _settingsService = settingsService; _rgbService = rgbService; _windowService = windowService; _updateService = updateService; - _autoRunProvider = kernel.TryGet(); + _autoRunProvider = container.Resolve(IfUnresolved.ReturnDefault); Continue = ReactiveCommand.Create(ExecuteContinue); GoBack = ReactiveCommand.Create(ExecuteGoBack); diff --git a/src/Artemis.UI/Screens/SurfaceEditor/ListDeviceViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/ListDeviceViewModel.cs index 2c68379eb..94071022e 100644 --- a/src/Artemis.UI/Screens/SurfaceEditor/ListDeviceViewModel.cs +++ b/src/Artemis.UI/Screens/SurfaceEditor/ListDeviceViewModel.cs @@ -57,7 +57,7 @@ public class ListDeviceViewModel : ViewModelBase await _windowService.CreateContentDialog() .WithTitle($"{Device.RgbDevice.DeviceInfo.DeviceName} - Detect input") - .WithViewModel(out DeviceDetectInputViewModel? viewModel, ("device", Device)) + .WithViewModel(out DeviceDetectInputViewModel viewModel, Device) .WithCloseButtonText("Cancel") .ShowAsync(); diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceDeviceViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceDeviceViewModel.cs index 51991e2a8..7596ce067 100644 --- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceDeviceViewModel.cs +++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceDeviceViewModel.cs @@ -115,7 +115,7 @@ public class SurfaceDeviceViewModel : ActivatableViewModelBase await _windowService.CreateContentDialog() .WithTitle($"{Device.RgbDevice.DeviceInfo.DeviceName} - Detect input") - .WithViewModel(out DeviceDetectInputViewModel? viewModel, ("device", Device)) + .WithViewModel(out DeviceDetectInputViewModel viewModel, Device) .WithCloseButtonText("Cancel") .ShowAsync(); diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs index dd0f738dd..0df1ca26c 100644 --- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs +++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs @@ -7,8 +7,8 @@ using System.Reactive.Disposables; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Extensions; -using Artemis.UI.Ninject.Factories; using Artemis.UI.Shared.Services; using Avalonia; using ReactiveUI; diff --git a/src/Artemis.UI/Screens/VisualScripting/CableView.axaml.cs b/src/Artemis.UI/Screens/VisualScripting/CableView.axaml.cs index 1cd822bf3..45e6b2042 100644 --- a/src/Artemis.UI/Screens/VisualScripting/CableView.axaml.cs +++ b/src/Artemis.UI/Screens/VisualScripting/CableView.axaml.cs @@ -8,7 +8,6 @@ using Avalonia.Input; using Avalonia.Markup.Xaml; using Avalonia.Media; using Avalonia.ReactiveUI; -using Avalonia.Rendering; using ReactiveUI; namespace Artemis.UI.Screens.VisualScripting; diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeScriptView.axaml.cs b/src/Artemis.UI/Screens/VisualScripting/NodeScriptView.axaml.cs index 92728f4d3..787f3fdca 100644 --- a/src/Artemis.UI/Screens/VisualScripting/NodeScriptView.axaml.cs +++ b/src/Artemis.UI/Screens/VisualScripting/NodeScriptView.axaml.cs @@ -14,7 +14,6 @@ using Avalonia.Markup.Xaml; using Avalonia.Media; using Avalonia.ReactiveUI; using Avalonia.Threading; -using Avalonia.VisualTree; using DynamicData.Binding; using ReactiveUI; diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeScriptViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/NodeScriptViewModel.cs index 00ab99900..5628da274 100644 --- a/src/Artemis.UI/Screens/VisualScripting/NodeScriptViewModel.cs +++ b/src/Artemis.UI/Screens/VisualScripting/NodeScriptViewModel.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics; using System.Linq; using System.Reactive; using System.Reactive.Linq; @@ -11,8 +10,8 @@ using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Events; using Artemis.Core.Services; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Models; -using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.VisualScripting.Pins; using Artemis.UI.Shared; using Artemis.UI.Shared.Services.NodeEditor; diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs index 0925e450c..7412f8d84 100644 --- a/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs +++ b/src/Artemis.UI/Screens/VisualScripting/NodeScriptWindowViewModel.cs @@ -7,7 +7,7 @@ using System.Reactive.Disposables; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.NodeEditor; using Artemis.UI.Shared.Services.NodeEditor.Commands; diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/NodeViewModel.cs index 97afc468f..17b73778e 100644 --- a/src/Artemis.UI/Screens/VisualScripting/NodeViewModel.cs +++ b/src/Artemis.UI/Screens/VisualScripting/NodeViewModel.cs @@ -5,7 +5,7 @@ using System.Reactive; using System.Reactive.Linq; using Artemis.Core; using Artemis.Core.Events; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Screens.VisualScripting.Pins; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; diff --git a/src/Artemis.UI/Screens/VisualScripting/Pins/InputPinCollectionViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/Pins/InputPinCollectionViewModel.cs index a889a8879..d5a7702eb 100644 --- a/src/Artemis.UI/Screens/VisualScripting/Pins/InputPinCollectionViewModel.cs +++ b/src/Artemis.UI/Screens/VisualScripting/Pins/InputPinCollectionViewModel.cs @@ -1,5 +1,5 @@ using Artemis.Core; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Shared.Services.NodeEditor; namespace Artemis.UI.Screens.VisualScripting.Pins; diff --git a/src/Artemis.UI/Screens/VisualScripting/Pins/OutputPinCollectionViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/Pins/OutputPinCollectionViewModel.cs index b842c9053..920f5f15c 100644 --- a/src/Artemis.UI/Screens/VisualScripting/Pins/OutputPinCollectionViewModel.cs +++ b/src/Artemis.UI/Screens/VisualScripting/Pins/OutputPinCollectionViewModel.cs @@ -1,5 +1,5 @@ using Artemis.Core; -using Artemis.UI.Ninject.Factories; +using Artemis.UI.DryIoc.Factories; using Artemis.UI.Shared.Services.NodeEditor; namespace Artemis.UI.Screens.VisualScripting.Pins; diff --git a/src/Artemis.UI/Services/RegistrationService.cs b/src/Artemis.UI/Services/RegistrationService.cs index 07e4660ca..e4d50ec9e 100644 --- a/src/Artemis.UI/Services/RegistrationService.cs +++ b/src/Artemis.UI/Services/RegistrationService.cs @@ -14,7 +14,7 @@ using Artemis.UI.Shared.Services.ProfileEditor; using Artemis.UI.Shared.Services.PropertyInput; using Artemis.VisualScripting.Nodes.Mathematics; using Avalonia; -using Ninject; +using DryIoc; using SkiaSharp; namespace Artemis.UI.Services; @@ -23,13 +23,13 @@ public class RegistrationService : IRegistrationService { private readonly IDataModelUIService _dataModelUIService; private readonly IInputService _inputService; - private readonly IKernel _kernel; + private readonly IContainer _container; private readonly INodeService _nodeService; private readonly IPropertyInputService _propertyInputService; private readonly IWebServerService _webServerService; private bool _registeredBuiltInPropertyEditors; - public RegistrationService(IKernel kernel, + public RegistrationService(IContainer container, IInputService inputService, IPropertyInputService propertyInputService, IProfileEditorService profileEditorService, @@ -39,7 +39,7 @@ public class RegistrationService : IRegistrationService IDeviceLayoutService deviceLayoutService // here to make sure it is instantiated ) { - _kernel = kernel; + _container = container; _inputService = inputService; _propertyInputService = propertyInputService; _nodeService = nodeService; @@ -53,7 +53,7 @@ public class RegistrationService : IRegistrationService private void CreateCursorResources() { - ICursorProvider? cursorProvider = _kernel.TryGet(); + ICursorProvider? cursorProvider = _container.Resolve(IfUnresolved.ReturnDefault); if (cursorProvider == null) return; diff --git a/src/Artemis.UI/Services/UpdateService.cs b/src/Artemis.UI/Services/UpdateService.cs index f4cada5f7..ab8e0e2ff 100644 --- a/src/Artemis.UI/Services/UpdateService.cs +++ b/src/Artemis.UI/Services/UpdateService.cs @@ -7,7 +7,7 @@ using Artemis.UI.Services.Interfaces; using Artemis.UI.Shared.Providers; using Artemis.UI.Shared.Services.MainWindow; using Avalonia.Threading; -using Ninject; +using DryIoc; using Serilog; namespace Artemis.UI.Services; @@ -22,13 +22,13 @@ public class UpdateService : IUpdateService private readonly IMainWindowService _mainWindowService; private readonly IUpdateProvider? _updateProvider; - public UpdateService(ILogger logger, IKernel kernel, ISettingsService settingsService, IMainWindowService mainWindowService) + public UpdateService(ILogger logger, IContainer container, ISettingsService settingsService, IMainWindowService mainWindowService) { _logger = logger; _mainWindowService = mainWindowService; if (!Constants.BuildInfo.IsLocalBuild) - _updateProvider = kernel.TryGet(); + _updateProvider = container.Resolve(IfUnresolved.ReturnDefault); _checkForUpdates = settingsService.GetSetting("UI.CheckForUpdates", true); _autoUpdate = settingsService.GetSetting("UI.AutoUpdate", false); diff --git a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj index ddfbc38c5..715ce5fe9 100644 --- a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj +++ b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Artemis.VisualScripting/DryIoc/NoStringNinjectModule.cs b/src/Artemis.VisualScripting/DryIoc/NoStringNinjectModule.cs new file mode 100644 index 000000000..8d3563615 --- /dev/null +++ b/src/Artemis.VisualScripting/DryIoc/NoStringNinjectModule.cs @@ -0,0 +1,35 @@ +using Artemis.Core.DryIoc; +using DryIoc; +using Microsoft.Extensions.ObjectPool; +using NoStringEvaluating; +using NoStringEvaluating.Contract; +using NoStringEvaluating.Models.Values; +using NoStringEvaluating.Services.Cache; +using NoStringEvaluating.Services.Checking; +using NoStringEvaluating.Services.Parsing; +using NoStringEvaluating.Services.Parsing.NodeReaders; + +namespace Artemis.VisualScripting.DryIoc; + +public class NoStringDryIocModule : IModule +{ + /// + public void Load(IRegistrator builder) + { + // Pooling + builder.RegisterInstance(ObjectPool.Create>()); + builder.RegisterInstance(ObjectPool.Create>()); + builder.RegisterInstance(ObjectPool.Create()); + + // Parser + builder.Register(Reuse.Singleton); + builder.Register(Reuse.Singleton); + builder.Register(Reuse.Singleton); + + // Checker + builder.Register(Reuse.Singleton); + + // Evaluator + builder.Register(Reuse.Singleton); + } +} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Ninject/NoStringNinjectModule.cs b/src/Artemis.VisualScripting/Ninject/NoStringNinjectModule.cs deleted file mode 100644 index 563b7f03d..000000000 --- a/src/Artemis.VisualScripting/Ninject/NoStringNinjectModule.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.Extensions.ObjectPool; -using Ninject.Modules; -using NoStringEvaluating; -using NoStringEvaluating.Contract; -using NoStringEvaluating.Models.Values; -using NoStringEvaluating.Services.Cache; -using NoStringEvaluating.Services.Checking; -using NoStringEvaluating.Services.Parsing; -using NoStringEvaluating.Services.Parsing.NodeReaders; - -namespace Artemis.VisualScripting.Ninject; - -public class NoStringNinjectModule : NinjectModule -{ - public override void Load() - { - // Pooling - Bind>>() - .ToConstant(ObjectPool.Create>()) - .InSingletonScope(); - - Bind>>() - .ToConstant(ObjectPool.Create>()) - .InSingletonScope(); - - Bind>() - .ToConstant(ObjectPool.Create()) - .InSingletonScope(); - - // Parser - Bind().To().InSingletonScope(); - Bind().To().InSingletonScope(); - Bind().To().InSingletonScope(); - - // Checker - Bind().To().InSingletonScope(); - - // Evaluator - Bind().To().InSingletonScope(); - } -} \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Nodes/Color/GradientBuilderNode.cs b/src/Artemis.VisualScripting/Nodes/Color/GradientBuilderNode.cs index e4d380196..26ff8067f 100644 --- a/src/Artemis.VisualScripting/Nodes/Color/GradientBuilderNode.cs +++ b/src/Artemis.VisualScripting/Nodes/Color/GradientBuilderNode.cs @@ -1,10 +1,5 @@ using Artemis.Core; using SkiaSharp; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Artemis.VisualScripting.Nodes.Color { diff --git a/src/Artemis.VisualScripting/Nodes/Color/SortedGradient.cs b/src/Artemis.VisualScripting/Nodes/Color/SortedGradient.cs index eea7329fe..f444c0cf0 100644 --- a/src/Artemis.VisualScripting/Nodes/Color/SortedGradient.cs +++ b/src/Artemis.VisualScripting/Nodes/Color/SortedGradient.cs @@ -1,11 +1,6 @@ using Artemis.Core; using Artemis.Core.ColorScience; using SkiaSharp; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Artemis.VisualScripting.Nodes.Color { diff --git a/src/Artemis.VisualScripting/Nodes/Input/Screens/PressedKeyPositionNodeCustomView.axaml.cs b/src/Artemis.VisualScripting/Nodes/Input/Screens/PressedKeyPositionNodeCustomView.axaml.cs index 0896825e0..767c68b4b 100644 --- a/src/Artemis.VisualScripting/Nodes/Input/Screens/PressedKeyPositionNodeCustomView.axaml.cs +++ b/src/Artemis.VisualScripting/Nodes/Input/Screens/PressedKeyPositionNodeCustomView.axaml.cs @@ -1,5 +1,3 @@ -using Avalonia; -using Avalonia.Controls; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; diff --git a/src/Artemis.VisualScripting/Nodes/List/Screens/ListOperatorNodeCustomView.axaml.cs b/src/Artemis.VisualScripting/Nodes/List/Screens/ListOperatorNodeCustomView.axaml.cs index 000d729e8..7ebdf311b 100644 --- a/src/Artemis.VisualScripting/Nodes/List/Screens/ListOperatorNodeCustomView.axaml.cs +++ b/src/Artemis.VisualScripting/Nodes/List/Screens/ListOperatorNodeCustomView.axaml.cs @@ -1,5 +1,3 @@ -using Avalonia; -using Avalonia.Controls; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; diff --git a/src/Artemis.VisualScripting/Nodes/List/Screens/ListOperatorPredicateNodeCustomView.axaml.cs b/src/Artemis.VisualScripting/Nodes/List/Screens/ListOperatorPredicateNodeCustomView.axaml.cs index ab950da39..c8a8b3d19 100644 --- a/src/Artemis.VisualScripting/Nodes/List/Screens/ListOperatorPredicateNodeCustomView.axaml.cs +++ b/src/Artemis.VisualScripting/Nodes/List/Screens/ListOperatorPredicateNodeCustomView.axaml.cs @@ -1,5 +1,3 @@ -using Avalonia; -using Avalonia.Controls; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; diff --git a/src/Artemis.VisualScripting/Nodes/List/Screens/ListOperatorPredicateNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/List/Screens/ListOperatorPredicateNodeCustomViewModel.cs index b840e0e8f..b1a922752 100644 --- a/src/Artemis.VisualScripting/Nodes/List/Screens/ListOperatorPredicateNodeCustomViewModel.cs +++ b/src/Artemis.VisualScripting/Nodes/List/Screens/ListOperatorPredicateNodeCustomViewModel.cs @@ -56,7 +56,7 @@ public class ListOperatorPredicateNodeCustomViewModel : CustomNodeViewModel if (_node.Script == null) return; - await _windowService.ShowDialogAsync(("nodeScript", _node.Script)); + await _windowService.ShowDialogAsync(_node.Script); _node.Script.Save(); _node.Storage ??= new ListOperatorEntity(); diff --git a/src/Artemis.VisualScripting/Nodes/Static/Screens/StaticBooleanValueNodeCustomView.axaml.cs b/src/Artemis.VisualScripting/Nodes/Static/Screens/StaticBooleanValueNodeCustomView.axaml.cs index a60961c46..6d619c059 100644 --- a/src/Artemis.VisualScripting/Nodes/Static/Screens/StaticBooleanValueNodeCustomView.axaml.cs +++ b/src/Artemis.VisualScripting/Nodes/Static/Screens/StaticBooleanValueNodeCustomView.axaml.cs @@ -1,5 +1,3 @@ -using Avalonia; -using Avalonia.Controls; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI;