From e8590abd610dc28ebc474e4fd9cc2149e88467d8 Mon Sep 17 00:00:00 2001 From: RobertBeekman Date: Tue, 9 Jan 2024 21:27:51 +0100 Subject: [PATCH] Devices - Reworking layout loading --- src/Artemis.Core/Constants.cs | 6 + .../DryIoc/ContainerExtensions.cs | 4 +- .../Models/Surface/ArtemisDevice.cs | 77 ++------- .../Models/Surface/Layout/ArtemisLayout.cs | 73 +++------ .../Models/Surface/LayoutSelection.cs | 28 ++++ .../Plugins/DeviceProviders/DeviceProvider.cs | 4 +- .../Providers/CustomPathLayoutProvider.cs | 28 ++++ .../Providers/DefaultLayoutProvider.cs | 31 ++++ .../Providers/Interfaces/ILayoutProvider.cs | 17 ++ .../Providers/NoneLayoutProvider.cs | 24 +++ src/Artemis.Core/Services/DeviceService.cs | 30 +++- .../Services/Interfaces/IDeviceService.cs | 5 +- .../Entities/Surface/DeviceEntity.cs | 6 +- .../Entities/Workshop/EntryEntity.cs | 5 +- src/Artemis.UI/Artemis.UI.csproj | 15 -- src/Artemis.UI/DryIoc/ContainerExtensions.cs | 2 + src/Artemis.UI/DryIoc/Factories/IVMFactory.cs | 150 ++++++++++-------- .../{ => General}/DeviceGeneralTabView.axaml | 5 +- .../DeviceGeneralTabView.axaml.cs | 3 +- .../DeviceGeneralTabViewModel.cs | 9 +- .../InputMappingsTabView.axaml | 5 +- .../InputMappingsTabView.axaml.cs | 3 +- .../InputMappingsTabViewModel.cs | 3 +- .../{ => Layout}/DeviceLayoutTabView.axaml | 55 ++++--- .../{ => Layout}/DeviceLayoutTabView.axaml.cs | 2 +- .../{ => Layout}/DeviceLayoutTabViewModel.cs | 74 ++------- .../DeviceLogicalLayoutDialogView.axaml | 5 +- .../DeviceLogicalLayoutDialogView.axaml.cs | 4 +- .../DeviceLogicalLayoutDialogViewModel.cs | 4 +- .../DevicePhysicalLayoutDialogView.axaml | 5 +- .../DevicePhysicalLayoutDialogView.axaml.cs | 5 +- .../DevicePhysicalLayoutDialogViewModel.cs | 2 +- .../LayoutProviders/CustomLayoutView.axaml | 25 +++ .../LayoutProviders/CustomLayoutView.axaml.cs | 13 ++ .../LayoutProviders/CustomLayoutViewModel.cs | 71 +++++++++ .../LayoutProviders/DefaultLayoutView.axaml | 10 ++ .../DefaultLayoutView.axaml.cs | 13 ++ .../LayoutProviders/DefaultLayoutViewModel.cs | 29 ++++ .../ILayoutProviderViewModel.cs | 14 ++ .../LayoutProviders/NoneLayoutView.axaml | 10 ++ .../LayoutProviders/NoneLayoutView.axaml.cs | 13 ++ .../LayoutProviders/NoneLayoutViewModel.cs | 29 ++++ .../LayoutProviders/WorkshopLayoutView.axaml | 11 ++ .../WorkshopLayoutView.axaml.cs | 13 ++ .../WorkshopLayoutViewModel.cs | 29 ++++ .../{ => Leds}/DeviceLedsTabLedViewModel.cs | 2 +- .../Tabs/{ => Leds}/DeviceLedsTabView.axaml | 5 +- .../{ => Leds}/DeviceLedsTabView.axaml.cs | 3 +- .../Tabs/{ => Leds}/DeviceLedsTabViewModel.cs | 2 +- .../Library/Tabs/InstalledTabItemViewModel.cs | 2 +- .../Layout/LayoutSelectionStepViewModel.cs | 2 +- .../Services/DeviceLayoutService.cs | 4 +- .../DryIoc/ContainerExtensions.cs | 3 + .../LayoutEntryInstallationHandler.cs | 56 +++++-- .../ProfileEntryInstallationHandler.cs | 10 +- .../Providers/WorkshopLayoutProvider.cs | 48 ++++++ .../Services/InstalledEntry.cs | 67 +++++++- 57 files changed, 824 insertions(+), 349 deletions(-) create mode 100644 src/Artemis.Core/Models/Surface/LayoutSelection.cs create mode 100644 src/Artemis.Core/Providers/CustomPathLayoutProvider.cs create mode 100644 src/Artemis.Core/Providers/DefaultLayoutProvider.cs create mode 100644 src/Artemis.Core/Providers/Interfaces/ILayoutProvider.cs create mode 100644 src/Artemis.Core/Providers/NoneLayoutProvider.cs rename src/Artemis.UI/Screens/Device/Tabs/{ => General}/DeviceGeneralTabView.axaml (98%) rename src/Artemis.UI/Screens/Device/Tabs/{ => General}/DeviceGeneralTabView.axaml.cs (76%) rename src/Artemis.UI/Screens/Device/Tabs/{ => General}/DeviceGeneralTabViewModel.cs (93%) rename src/Artemis.UI/Screens/Device/Tabs/{ => InputMappings}/InputMappingsTabView.axaml (94%) rename src/Artemis.UI/Screens/Device/Tabs/{ => InputMappings}/InputMappingsTabView.axaml.cs (75%) rename src/Artemis.UI/Screens/Device/Tabs/{ => InputMappings}/InputMappingsTabViewModel.cs (98%) rename src/Artemis.UI/Screens/Device/Tabs/{ => Layout}/DeviceLayoutTabView.axaml (64%) rename src/Artemis.UI/Screens/Device/Tabs/{ => Layout}/DeviceLayoutTabView.axaml.cs (95%) rename src/Artemis.UI/Screens/Device/Tabs/{ => Layout}/DeviceLayoutTabViewModel.cs (60%) rename src/Artemis.UI/Screens/Device/Tabs/{ => Layout}/DeviceLogicalLayoutDialogView.axaml (90%) rename src/Artemis.UI/Screens/Device/Tabs/{ => Layout}/DeviceLogicalLayoutDialogView.axaml.cs (92%) rename src/Artemis.UI/Screens/Device/Tabs/{ => Layout}/DeviceLogicalLayoutDialogViewModel.cs (93%) rename src/Artemis.UI/Screens/Device/Tabs/{ => Layout}/DevicePhysicalLayoutDialogView.axaml (95%) rename src/Artemis.UI/Screens/Device/Tabs/{ => Layout}/DevicePhysicalLayoutDialogView.axaml.cs (68%) rename src/Artemis.UI/Screens/Device/Tabs/{ => Layout}/DevicePhysicalLayoutDialogViewModel.cs (96%) create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/CustomLayoutView.axaml create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/CustomLayoutView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/CustomLayoutViewModel.cs create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/DefaultLayoutView.axaml create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/DefaultLayoutView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/DefaultLayoutViewModel.cs create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/ILayoutProviderViewModel.cs create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/NoneLayoutView.axaml create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/NoneLayoutView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/NoneLayoutViewModel.cs create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/WorkshopLayoutView.axaml create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/WorkshopLayoutView.axaml.cs create mode 100644 src/Artemis.UI/Screens/Device/Tabs/Layout/LayoutProviders/WorkshopLayoutViewModel.cs rename src/Artemis.UI/Screens/Device/Tabs/{ => Leds}/DeviceLedsTabLedViewModel.cs (96%) rename src/Artemis.UI/Screens/Device/Tabs/{ => Leds}/DeviceLedsTabView.axaml (93%) rename src/Artemis.UI/Screens/Device/Tabs/{ => Leds}/DeviceLedsTabView.axaml.cs (74%) rename src/Artemis.UI/Screens/Device/Tabs/{ => Leds}/DeviceLedsTabViewModel.cs (96%) create mode 100644 src/Artemis.WebClient.Workshop/Providers/WorkshopLayoutProvider.cs diff --git a/src/Artemis.Core/Constants.cs b/src/Artemis.Core/Constants.cs index 61381faf4..8386f5fcf 100644 --- a/src/Artemis.Core/Constants.cs +++ b/src/Artemis.Core/Constants.cs @@ -62,6 +62,11 @@ public static class Constants /// The full path to the Artemis user layouts folder /// public static readonly string LayoutsFolder = Path.Combine(DataFolder, "User Layouts"); + + /// + /// The full path to the Artemis user layouts folder + /// + public static readonly string WorkshopFolder = Path.Combine(DataFolder, "workshop"); /// /// The current API version for plugins @@ -155,4 +160,5 @@ public static class Constants /// Gets the graphics context to be used for rendering by SkiaSharp. /// public static IManagedGraphicsContext? ManagedGraphicsContext { get; internal set; } + } \ No newline at end of file diff --git a/src/Artemis.Core/DryIoc/ContainerExtensions.cs b/src/Artemis.Core/DryIoc/ContainerExtensions.cs index b9b768c78..44d377e8a 100644 --- a/src/Artemis.Core/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.Core/DryIoc/ContainerExtensions.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using System.Reflection; using Artemis.Core.DryIoc.Factories; +using Artemis.Core.Providers; using Artemis.Core.Services; using Artemis.Storage; using Artemis.Storage.Migrations.Interfaces; @@ -35,7 +36,8 @@ public static class ContainerExtensions // Bind migrations container.RegisterMany(storageAssembly, type => type.IsAssignableTo(), Reuse.Singleton, nonPublicServiceTypes: true); - + + container.RegisterMany(coreAssembly, type => type.IsAssignableTo(), Reuse.Singleton); container.Register(Reuse.Singleton); container.Register(Made.Of(_ => ServiceInfo.Of(), f => f.CreatePluginSettings(Arg.Index(0)), r => r.Parent.ImplementationType)); container.Register(Reuse.Singleton); diff --git a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs index d34a3cd7d..34a10d0fc 100644 --- a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs +++ b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; -using System.Diagnostics; using System.Linq; using Artemis.Core.DeviceProviders; +using Artemis.Core.Providers; using Artemis.Core.Services; using Artemis.Storage.Entities.Surface; using RGB.NET.Core; @@ -46,6 +46,7 @@ public class ArtemisDevice : CorePropertyChanged InputIdentifiers = new List(); InputMappings = new Dictionary(); Categories = new HashSet(); + LayoutSelection = new LayoutSelection {Type = DefaultLayoutProvider.LayoutType}; RgbDevice.ColorCorrections.Clear(); RgbDevice.ColorCorrections.Add(new ScaleColorCorrection(this)); @@ -74,6 +75,7 @@ public class ArtemisDevice : CorePropertyChanged InputIdentifiers = new List(); InputMappings = new Dictionary(); Categories = new HashSet(); + LayoutSelection = new LayoutSelection {Type = DefaultLayoutProvider.LayoutType}; foreach (DeviceInputIdentifierEntity identifierEntity in DeviceEntity.InputIdentifiers) InputIdentifiers.Add(new ArtemisDeviceInputIdentifier(identifierEntity.InputProvider, identifierEntity.Identifier)); @@ -153,6 +155,8 @@ public class ArtemisDevice : CorePropertyChanged /// public HashSet Categories { get; } + public LayoutSelection LayoutSelection { get; } + /// /// Gets or sets the X-position of the device /// @@ -293,19 +297,6 @@ public class ArtemisDevice : CorePropertyChanged } } - /// - /// Gets or sets a boolean indicating whether falling back to default layouts is enabled or not - /// - public bool DisableDefaultLayout - { - get => DeviceEntity.DisableDefaultLayout; - set - { - DeviceEntity.DisableDefaultLayout = value; - OnPropertyChanged(nameof(DisableDefaultLayout)); - } - } - /// /// Gets or sets the logical layout of the device e.g. DE, UK or US. /// Only applicable to keyboards @@ -320,20 +311,6 @@ public class ArtemisDevice : CorePropertyChanged } } - /// - /// Gets or sets the path of the custom layout to load when calling - /// for this device - /// - public string? CustomLayoutPath - { - get => DeviceEntity.CustomLayoutPath; - set - { - DeviceEntity.CustomLayoutPath = value; - OnPropertyChanged(nameof(CustomLayoutPath)); - } - } - /// /// Gets the layout of the device expanded with Artemis-specific data /// @@ -381,40 +358,6 @@ public class ArtemisDevice : CorePropertyChanged return artemisLed; } - /// - /// Returns the most preferred device layout for this device. - /// - /// The most preferred device layout for this device. - public ArtemisLayout? GetBestDeviceLayout() - { - ArtemisLayout? layout; - - // Configured layout path takes precedence over all other options - if (CustomLayoutPath != null) - { - layout = new ArtemisLayout(CustomLayoutPath, LayoutSource.Configured); - if (layout.IsValid) - return layout; - } - - // Look for a layout provided by the user - layout = DeviceProvider.LoadUserLayout(this); - if (layout.IsValid) - return layout; - - if (DisableDefaultLayout) - return null; - - // Look for a layout provided by the plugin - layout = DeviceProvider.LoadLayout(this); - if (layout.IsValid) - return layout; - - // Finally fall back to a default layout - layout = ArtemisLayout.GetDefaultLayout(this); - return layout; - } - /// /// Occurs when the underlying RGB.NET device was updated /// @@ -481,7 +424,7 @@ public class ArtemisDevice : CorePropertyChanged throw new ArtemisCoreException($"Cannot apply layout with {nameof(createMissingLeds)} set to true because the device provider does not support it"); if (layout != null && layout.IsValid && removeExcessiveLeds && !DeviceProvider.RemoveExcessiveLedsSupported) throw new ArtemisCoreException($"Cannot apply layout with {nameof(removeExcessiveLeds)} set to true because the device provider does not support it"); - + // Always clear the current layout ClearLayout(); @@ -534,6 +477,9 @@ public class ArtemisDevice : CorePropertyChanged DeviceEntity.Categories.Clear(); foreach (DeviceCategory deviceCategory in Categories) DeviceEntity.Categories.Add((int) deviceCategory); + + DeviceEntity.LayoutType = LayoutSelection.Type; + DeviceEntity.LayoutParameter = LayoutSelection.Parameter; } internal void Load() @@ -548,6 +494,9 @@ public class ArtemisDevice : CorePropertyChanged if (!Categories.Any()) ApplyDefaultCategories(); + LayoutSelection.Type = DeviceEntity.LayoutType; + LayoutSelection.Parameter = DeviceEntity.LayoutParameter; + LoadInputMappings(); } @@ -573,7 +522,7 @@ public class ArtemisDevice : CorePropertyChanged { Leds = RgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly(); LedIds = new ReadOnlyDictionary(Leds.ToDictionary(l => l.RgbLed.Id, l => l)); - + if (loadInputMappings) LoadInputMappings(); } diff --git a/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs b/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs index f44e3185d..5304f5e37 100644 --- a/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs +++ b/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs @@ -12,17 +12,18 @@ namespace Artemis.Core; /// public class ArtemisLayout { + private static readonly string DefaultLayoutPath = Path.Combine(Constants.ApplicationFolder, "DefaultLayouts", "Artemis"); + /// /// Creates a new instance of the class /// /// The path of the layout XML file - /// The source from where this layout is being loaded - public ArtemisLayout(string filePath, LayoutSource source) + public ArtemisLayout(string filePath) { FilePath = filePath; - Source = source; Leds = new List(); - + IsDefaultLayout = filePath.StartsWith(DefaultLayoutPath); + LoadLayout(); } @@ -31,11 +32,6 @@ public class ArtemisLayout /// public string FilePath { get; } - /// - /// Gets the source from where this layout was loaded - /// - public LayoutSource Source { get; } - /// /// Gets a boolean indicating whether a valid layout was loaded /// @@ -61,6 +57,8 @@ public class ArtemisLayout /// public LayoutCustomDeviceData LayoutCustomDeviceData { get; private set; } = null!; + public bool IsDefaultLayout { get; private set; } + /// /// Applies the layout to the provided device /// @@ -121,29 +119,28 @@ public class ArtemisLayout internal static ArtemisLayout? GetDefaultLayout(ArtemisDevice device) { - string layoutFolder = Path.Combine(Constants.ApplicationFolder, "DefaultLayouts", "Artemis"); if (device.DeviceType == RGBDeviceType.Keyboard) { // XL layout is defined by its programmable macro keys if (device.Leds.Any(l => l.RgbLed.Id >= LedId.Keyboard_Programmable1 && l.RgbLed.Id <= LedId.Keyboard_Programmable32)) { if (device.PhysicalLayout == KeyboardLayoutType.ANSI) - return new ArtemisLayout(Path.Combine(layoutFolder, "Keyboard", "Artemis XL keyboard-ANSI.xml"), LayoutSource.Default); - return new ArtemisLayout(Path.Combine(layoutFolder, "Keyboard", "Artemis XL keyboard-ISO.xml"), LayoutSource.Default); + return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Keyboard", "Artemis XL keyboard-ANSI.xml")); + return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Keyboard", "Artemis XL keyboard-ISO.xml")); } // L layout is defined by its numpad if (device.Leds.Any(l => l.RgbLed.Id >= LedId.Keyboard_NumLock && l.RgbLed.Id <= LedId.Keyboard_NumPeriodAndDelete)) { if (device.PhysicalLayout == KeyboardLayoutType.ANSI) - return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard", "Artemis L keyboard-ANSI.xml"), LayoutSource.Default); - return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard", "Artemis L keyboard-ISO.xml"), LayoutSource.Default); + return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Keyboard", "Artemis L keyboard-ANSI.xml")); + return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Keyboard", "Artemis L keyboard-ISO.xml")); } // No numpad will result in TKL if (device.PhysicalLayout == KeyboardLayoutType.ANSI) - return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard", "Artemis TKL keyboard-ANSI.xml"), LayoutSource.Default); - return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard", "Artemis TKL keyboard-ISO.xml"), LayoutSource.Default); + return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Keyboard", "Artemis TKL keyboard-ANSI.xml")); + return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Keyboard", "Artemis TKL keyboard-ISO.xml")); } // if (device.DeviceType == RGBDeviceType.Mouse) @@ -151,21 +148,21 @@ public class ArtemisLayout // if (device.Leds.Count == 1) // { // if (device.Leds.Any(l => l.RgbLed.Id == LedId.Logo)) - // return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "1 LED mouse logo.xml"), LayoutSource.Default); - // return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "1 LED mouse.xml"), LayoutSource.Default); + // return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Mouse", "1 LED mouse logo.xml"), LayoutSource.Default); + // return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Mouse", "1 LED mouse.xml"), LayoutSource.Default); // } // if (device.Leds.Any(l => l.RgbLed.Id == LedId.Logo)) - // return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "4 LED mouse logo.xml"), LayoutSource.Default); - // return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "4 LED mouse.xml"), LayoutSource.Default); + // return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Mouse", "4 LED mouse logo.xml"), LayoutSource.Default); + // return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Mouse", "4 LED mouse.xml"), LayoutSource.Default); // } if (device.DeviceType == RGBDeviceType.Headset) { if (device.Leds.Count == 1) - return new ArtemisLayout(Path.Combine(layoutFolder + "Headset", "Artemis 1 LED headset.xml"), LayoutSource.Default); + return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Headset", "Artemis 1 LED headset.xml")); if (device.Leds.Count == 2) - return new ArtemisLayout(Path.Combine(layoutFolder + "Headset", "Artemis 2 LED headset.xml"), LayoutSource.Default); - return new ArtemisLayout(Path.Combine(layoutFolder + "Headset", "Artemis 4 LED headset.xml"), LayoutSource.Default); + return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Headset", "Artemis 2 LED headset.xml")); + return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Headset", "Artemis 4 LED headset.xml")); } return null; @@ -206,30 +203,10 @@ public class ArtemisLayout else Image = null; } -} -/// -/// Represents a source from where a layout came -/// -public enum LayoutSource -{ - /// - /// A layout loaded from config - /// - Configured, - - /// - /// A layout loaded from the user layout folder - /// - User, - - /// - /// A layout loaded from the plugin folder - /// - Plugin, - - /// - /// A default layout loaded as a fallback option - /// - Default + /// + public override string ToString() + { + return FilePath; + } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Surface/LayoutSelection.cs b/src/Artemis.Core/Models/Surface/LayoutSelection.cs new file mode 100644 index 000000000..f64c54eb1 --- /dev/null +++ b/src/Artemis.Core/Models/Surface/LayoutSelection.cs @@ -0,0 +1,28 @@ +namespace Artemis.Core; + +/// +/// Represents a reference to a layout for a device. +/// +public class LayoutSelection : CorePropertyChanged +{ + private string? _type; + private string? _parameter; + + /// + /// Gets or sets what kind of layout reference this is. + /// + public string? Type + { + get => _type; + set => SetAndNotify(ref _type, value); + } + + /// + /// Gets or sets the parameter of the layout reference, such as a file path of workshop entry ID. + /// + public string? Parameter + { + get => _parameter; + set => SetAndNotify(ref _parameter, value); + } +} \ 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 843710370..ee9f256a9 100644 --- a/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs +++ b/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs @@ -62,7 +62,7 @@ public abstract class DeviceProvider : PluginFeature device.DeviceType.ToString(), GetDeviceLayoutName(device) ); - return new ArtemisLayout(filePath, LayoutSource.Plugin); + return new ArtemisLayout(filePath); } /// @@ -79,7 +79,7 @@ public abstract class DeviceProvider : PluginFeature device.DeviceType.ToString(), GetDeviceLayoutName(device) ); - return new ArtemisLayout(filePath, LayoutSource.User); + return new ArtemisLayout(filePath); } /// diff --git a/src/Artemis.Core/Providers/CustomPathLayoutProvider.cs b/src/Artemis.Core/Providers/CustomPathLayoutProvider.cs new file mode 100644 index 000000000..5b5e96e2c --- /dev/null +++ b/src/Artemis.Core/Providers/CustomPathLayoutProvider.cs @@ -0,0 +1,28 @@ +using RGB.NET.Layout; + +namespace Artemis.Core.Providers; + +public class CustomPathLayoutProvider : ILayoutProvider +{ + public static string LayoutType = "CustomPath"; + + /// + public ArtemisLayout? GetDeviceLayout(ArtemisDevice device) + { + if (device.LayoutSelection.Parameter == null) + return null; + return new ArtemisLayout(device.LayoutSelection.Parameter); + } + + /// + public void ApplyLayout(ArtemisDevice device, ArtemisLayout layout) + { + device.ApplyLayout(layout, device.DeviceProvider.CreateMissingLedsSupported, device.DeviceProvider.RemoveExcessiveLedsSupported); + } + + /// + public bool IsMatch(ArtemisDevice device) + { + return device.LayoutSelection.Type == LayoutType; + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Providers/DefaultLayoutProvider.cs b/src/Artemis.Core/Providers/DefaultLayoutProvider.cs new file mode 100644 index 000000000..2360ab11b --- /dev/null +++ b/src/Artemis.Core/Providers/DefaultLayoutProvider.cs @@ -0,0 +1,31 @@ +namespace Artemis.Core.Providers; + +public class DefaultLayoutProvider : ILayoutProvider +{ + public static string LayoutType = "Default"; + + /// + public ArtemisLayout? GetDeviceLayout(ArtemisDevice device) + { + // Look for a layout provided by the plugin + ArtemisLayout layout = device.DeviceProvider.LoadLayout(device); + + // Finally fall back to a default layout + return layout.IsValid ? layout : ArtemisLayout.GetDefaultLayout(device); + } + + /// + public void ApplyLayout(ArtemisDevice device, ArtemisLayout layout) + { + if (layout.IsDefaultLayout) + device.ApplyLayout(layout, false, false); + else + device.ApplyLayout(layout, device.DeviceProvider.CreateMissingLedsSupported, device.DeviceProvider.RemoveExcessiveLedsSupported); + } + + /// + public bool IsMatch(ArtemisDevice device) + { + return device.LayoutSelection.Type == LayoutType; + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Providers/Interfaces/ILayoutProvider.cs b/src/Artemis.Core/Providers/Interfaces/ILayoutProvider.cs new file mode 100644 index 000000000..fe8d421c2 --- /dev/null +++ b/src/Artemis.Core/Providers/Interfaces/ILayoutProvider.cs @@ -0,0 +1,17 @@ +namespace Artemis.Core.Providers; + +/// +/// Represents a class that can provide Artemis layouts for devices. +/// +public interface ILayoutProvider +{ + /// + /// If available, loads an Artemis layout for the provided device. + /// + /// The device to load the layout for. + /// The resulting layout if one was available; otherwise . + ArtemisLayout? GetDeviceLayout(ArtemisDevice device); + + void ApplyLayout(ArtemisDevice device, ArtemisLayout layout); + bool IsMatch(ArtemisDevice device); +} \ No newline at end of file diff --git a/src/Artemis.Core/Providers/NoneLayoutProvider.cs b/src/Artemis.Core/Providers/NoneLayoutProvider.cs new file mode 100644 index 000000000..c764b0ddb --- /dev/null +++ b/src/Artemis.Core/Providers/NoneLayoutProvider.cs @@ -0,0 +1,24 @@ +namespace Artemis.Core.Providers; + +public class NoneLayoutProvider : ILayoutProvider +{ + public static string LayoutType = "None"; + + /// + public ArtemisLayout? GetDeviceLayout(ArtemisDevice device) + { + return null; + } + + /// + public void ApplyLayout(ArtemisDevice device, ArtemisLayout layout) + { + device.ApplyLayout(null, false, false); + } + + /// + public bool IsMatch(ArtemisDevice device) + { + return device.LayoutSelection.Type == LayoutType; + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/DeviceService.cs b/src/Artemis.Core/Services/DeviceService.cs index ae43ab5ef..ea3e09533 100644 --- a/src/Artemis.Core/Services/DeviceService.cs +++ b/src/Artemis.Core/Services/DeviceService.cs @@ -4,6 +4,7 @@ using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using Artemis.Core.DeviceProviders; +using Artemis.Core.Providers; using Artemis.Core.Services.Models; using Artemis.Storage.Entities.Surface; using Artemis.Storage.Repositories.Interfaces; @@ -18,15 +19,21 @@ internal class DeviceService : IDeviceService private readonly IPluginManagementService _pluginManagementService; private readonly IDeviceRepository _deviceRepository; private readonly Lazy _renderService; + private readonly Func> _getLayoutProviders; private readonly List _enabledDevices = new(); private readonly List _devices = new(); - public DeviceService(ILogger logger, IPluginManagementService pluginManagementService, IDeviceRepository deviceRepository, Lazy renderService) + public DeviceService(ILogger logger, + IPluginManagementService pluginManagementService, + IDeviceRepository deviceRepository, + Lazy renderService, + Func> getLayoutProviders) { _logger = logger; _pluginManagementService = pluginManagementService; _deviceRepository = deviceRepository; _renderService = renderService; + _getLayoutProviders = getLayoutProviders; EnabledDevices = new ReadOnlyCollection(_enabledDevices); Devices = new ReadOnlyCollection(_devices); @@ -157,12 +164,23 @@ internal class DeviceService : IDeviceService } /// - public void ApplyDeviceLayout(ArtemisDevice device, ArtemisLayout? layout) + public void LoadDeviceLayout(ArtemisDevice device) { - if (layout == null || layout.Source == LayoutSource.Default) - device.ApplyLayout(layout, false, false); + ILayoutProvider? provider = _getLayoutProviders().FirstOrDefault(p => p.IsMatch(device)); + if (provider == null) + _logger.Warning("Could not find a layout provider for type {LayoutType} of device {Device}", device.LayoutSelection.Type, device); + + ArtemisLayout? layout = provider?.GetDeviceLayout(device); + if (layout != null && !layout.IsValid) + { + _logger.Warning("Got an invalid layout {Layout} from {LayoutProvider}", layout, provider!.GetType().FullName); + layout = null; + } + + if (layout == null) + device.ApplyLayout(null, false, false); else - device.ApplyLayout(layout, device.DeviceProvider.CreateMissingLedsSupported, device.DeviceProvider.RemoveExcessiveLedsSupported); + provider!.ApplyLayout(device, layout); UpdateLeds(); } @@ -230,7 +248,7 @@ internal class DeviceService : IDeviceService device = new ArtemisDevice(rgbDevice, deviceProvider); } - ApplyDeviceLayout(device, device.GetBestDeviceLayout()); + LoadDeviceLayout(device); return device; } diff --git a/src/Artemis.Core/Services/Interfaces/IDeviceService.cs b/src/Artemis.Core/Services/Interfaces/IDeviceService.cs index b66f14022..51b19d937 100644 --- a/src/Artemis.Core/Services/Interfaces/IDeviceService.cs +++ b/src/Artemis.Core/Services/Interfaces/IDeviceService.cs @@ -43,11 +43,10 @@ public interface IDeviceService : IArtemisService void AutoArrangeDevices(); /// - /// Apples the provided to the provided + /// Apples the best available to the provided /// /// - /// - void ApplyDeviceLayout(ArtemisDevice device, ArtemisLayout? layout); + void LoadDeviceLayout(ArtemisDevice device); /// /// Enables the provided device diff --git a/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs b/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs index 31dd8ac3d..b19e38c03 100644 --- a/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs +++ b/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs @@ -22,11 +22,11 @@ public class DeviceEntity public float GreenScale { get; set; } public float BlueScale { get; set; } public bool IsEnabled { get; set; } - - public bool DisableDefaultLayout { get; set; } + public int PhysicalLayout { get; set; } public string LogicalLayout { get; set; } - public string CustomLayoutPath { get; set; } + public string LayoutType { get; set; } + public string LayoutParameter { get; set; } public List InputIdentifiers { get; set; } public List InputMappings { get; set; } diff --git a/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs b/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs index 86bff6dcd..e2acf7922 100644 --- a/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs +++ b/src/Artemis.Storage/Entities/Workshop/EntryEntity.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace Artemis.Storage.Entities.Workshop; @@ -16,6 +17,6 @@ public class EntryEntity public long ReleaseId { get; set; } public string ReleaseVersion { get; set; } public DateTimeOffset InstalledAt { get; set; } - - public string LocalReference { get; set; } + + public Dictionary Metadata { get; set; } } \ No newline at end of file diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 71d09529d..e4a63012a 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -58,19 +58,4 @@ ..\..\..\RGB.NET\bin\net7.0\RGB.NET.Layout.dll - - - - EntryListInputView.axaml - Code - - - EntryListItemView.axaml - Code - - - EntrySpecificationsView.axaml - Code - - \ No newline at end of file diff --git a/src/Artemis.UI/DryIoc/ContainerExtensions.cs b/src/Artemis.UI/DryIoc/ContainerExtensions.cs index da3e9a188..2d7f58b22 100644 --- a/src/Artemis.UI/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.UI/DryIoc/ContainerExtensions.cs @@ -1,6 +1,7 @@ using System.Reflection; using Artemis.UI.DryIoc.Factories; using Artemis.UI.DryIoc.InstanceProviders; +using Artemis.UI.Screens.Device.Layout.LayoutProviders; using Artemis.UI.Screens.VisualScripting; using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Updating; @@ -26,6 +27,7 @@ public static class ContainerExtensions container.RegisterMany(thisAssembly, type => type.IsAssignableTo(), setup: Setup.With(preventDisposal: true)); container.RegisterMany(thisAssembly, type => type.IsAssignableTo() && type.IsInterface, setup: Setup.With(preventDisposal: true)); + container.RegisterMany(thisAssembly, type => type.IsAssignableTo() && type.IsInterface, setup: Setup.With(preventDisposal: true)); container.RegisterMany(thisAssembly, type => type.IsAssignableTo() && type != typeof(PropertyVmFactory)); container.Register(Reuse.Singleton); diff --git a/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs b/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs index b66691036..e95a8639c 100644 --- a/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs +++ b/src/Artemis.UI/DryIoc/Factories/IVMFactory.cs @@ -1,13 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; +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.Routing; using Artemis.UI.Screens.Device; +using Artemis.UI.Screens.Device.General; +using Artemis.UI.Screens.Device.InputMappings; +using Artemis.UI.Screens.Device.Layout; +using Artemis.UI.Screens.Device.Leds; using Artemis.UI.Screens.Plugins; using Artemis.UI.Screens.Plugins.Features; using Artemis.UI.Screens.Plugins.Prerequisites; @@ -27,12 +28,8 @@ using Artemis.UI.Screens.Sidebar; using Artemis.UI.Screens.SurfaceEditor; using Artemis.UI.Screens.VisualScripting; using Artemis.UI.Screens.VisualScripting.Pins; -using Artemis.UI.Shared; -using Artemis.UI.Shared.Routing; using Artemis.WebClient.Updating; using DryIoc; -using DynamicData; -using Material.Icons; using ReactiveUI; namespace Artemis.UI.DryIoc.Factories; @@ -51,48 +48,49 @@ public interface IDeviceVmFactory : IVmFactory InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection selectedLeds); DeviceGeneralTabViewModel DeviceGeneralTabViewModel(ArtemisDevice device); } + 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 }); + return _container.Resolve(new object[] {device}); } - + public DeviceSettingsViewModel DeviceSettingsViewModel(ArtemisDevice device, DevicesTabViewModel devicesTabViewModel) { - return _container.Resolve(new object[] { device, devicesTabViewModel }); + return _container.Resolve(new object[] {device, devicesTabViewModel}); } - + public DeviceDetectInputViewModel DeviceDetectInputViewModel(ArtemisDevice device) { - return _container.Resolve(new object[] { device }); + return _container.Resolve(new object[] {device}); } - + public DeviceLayoutTabViewModel DeviceLayoutTabViewModel(ArtemisDevice device) { - return _container.Resolve(new object[] { device }); + return _container.Resolve(new object[] {device}); } public DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device, ObservableCollection selectedLeds) { - return _container.Resolve(new object[] { device, selectedLeds }); + return _container.Resolve(new object[] {device, selectedLeds}); } - + public InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection selectedLeds) { - return _container.Resolve(new object[] { device, selectedLeds }); + return _container.Resolve(new object[] {device, selectedLeds}); } public DeviceGeneralTabViewModel DeviceGeneralTabViewModel(ArtemisDevice device) { - return _container.Resolve(new object[] { device }); + return _container.Resolve(new object[] {device}); } } @@ -102,28 +100,29 @@ public interface ISettingsVmFactory : IVmFactory 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 }); + return _container.Resolve(new object[] {plugin}); } - + public PluginViewModel PluginViewModel(Plugin plugin, ReactiveCommand? reload) { - return _container.Resolve(new object?[] { plugin, reload }); + return _container.Resolve(new object?[] {plugin, reload}); } - + public PluginFeatureViewModel PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo, bool showShield) { - return _container.Resolve(new object[] { pluginFeatureInfo, showShield }); + return _container.Resolve(new object[] {pluginFeatureInfo, showShield}); } } @@ -132,23 +131,24 @@ public interface ISidebarVmFactory : IVmFactory SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory); SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration); } + public class SidebarVmFactory : ISidebarVmFactory { private readonly IContainer _container; - + public SidebarVmFactory(IContainer container) { _container = container; } - + public SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory) { - return _container.Resolve(new object[] { profileCategory }); + return _container.Resolve(new object[] {profileCategory}); } - + public SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration) { - return _container.Resolve(new object[] { profileConfiguration }); + return _container.Resolve(new object[] {profileConfiguration}); } } @@ -157,6 +157,7 @@ public interface ISurfaceVmFactory : IVmFactory SurfaceDeviceViewModel SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel); ListDeviceViewModel ListDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel); } + public class SurfaceVmFactory : ISurfaceVmFactory { private readonly IContainer _container; @@ -168,12 +169,12 @@ public class SurfaceVmFactory : ISurfaceVmFactory public SurfaceDeviceViewModel SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel) { - return _container.Resolve(new object[] { device, surfaceEditorViewModel }); + return _container.Resolve(new object[] {device, surfaceEditorViewModel}); } public ListDeviceViewModel ListDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel) { - return _container.Resolve(new object[] { device, surfaceEditorViewModel }); + return _container.Resolve(new object[] {device, surfaceEditorViewModel}); } } @@ -181,6 +182,7 @@ public interface IPrerequisitesVmFactory : IVmFactory { PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall); } + public class PrerequisitesVmFactory : IPrerequisitesVmFactory { private readonly IContainer _container; @@ -192,7 +194,7 @@ public class PrerequisitesVmFactory : IPrerequisitesVmFactory public PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall) { - return _container.Resolve(new object[] { pluginPrerequisite, uninstall }); + return _container.Resolve(new object[] {pluginPrerequisite, uninstall}); } } @@ -204,6 +206,7 @@ public interface IProfileEditorVmFactory : IVmFactory LayerShapeVisualizerViewModel LayerShapeVisualizerViewModel(Layer layer); LayerVisualizerViewModel LayerVisualizerViewModel(Layer layer); } + public class ProfileEditorVmFactory : IProfileEditorVmFactory { private readonly IContainer _container; @@ -215,27 +218,27 @@ public class ProfileEditorVmFactory : IProfileEditorVmFactory public FolderTreeItemViewModel FolderTreeItemViewModel(TreeItemViewModel? parent, Folder folder) { - return _container.Resolve(new object?[] { parent, folder }); + return _container.Resolve(new object?[] {parent, folder}); } public LayerShapeVisualizerViewModel LayerShapeVisualizerViewModel(Layer layer) { - return _container.Resolve(new object[] { layer }); + return _container.Resolve(new object[] {layer}); } public LayerTreeItemViewModel LayerTreeItemViewModel(TreeItemViewModel? parent, Layer layer) { - return _container.Resolve(new object?[] { parent, layer }); + return _container.Resolve(new object?[] {parent, layer}); } public LayerVisualizerViewModel LayerVisualizerViewModel(Layer layer) { - return _container.Resolve(new object[] { layer }); + return _container.Resolve(new object[] {layer}); } public ProfileEditorViewModel ProfileEditorViewModel(IScreen hostScreen) { - return _container.Resolve(new object[] { hostScreen }); + return _container.Resolve(new object[] {hostScreen}); } } @@ -251,6 +254,7 @@ public interface ILayerPropertyVmFactory : IVmFactory TimelineViewModel TimelineViewModel(ObservableCollection propertyGroupViewModels); TimelineGroupViewModel TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel); } + public class LayerPropertyVmFactory : ILayerPropertyVmFactory { private readonly IContainer _container; @@ -262,37 +266,37 @@ public class LayerPropertyVmFactory : ILayerPropertyVmFactory public PropertyViewModel PropertyViewModel(ILayerProperty layerProperty) { - return _container.Resolve(new object[] { layerProperty }); + return _container.Resolve(new object[] {layerProperty}); } public PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup) { - return _container.Resolve(new object[] { layerPropertyGroup }); + return _container.Resolve(new object[] {layerPropertyGroup}); } public PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerBrush layerBrush) { - return _container.Resolve(new object[] { layerPropertyGroup, layerBrush }); + return _container.Resolve(new object[] {layerPropertyGroup, layerBrush}); } public PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerEffect layerEffect) { - return _container.Resolve(new object[] { layerPropertyGroup, layerEffect }); + return _container.Resolve(new object[] {layerPropertyGroup, layerEffect}); } public TreeGroupViewModel TreeGroupViewModel(PropertyGroupViewModel propertyGroupViewModel) { - return _container.Resolve(new object[] { propertyGroupViewModel }); + return _container.Resolve(new object[] {propertyGroupViewModel}); } public TimelineViewModel TimelineViewModel(ObservableCollection propertyGroupViewModels) { - return _container.Resolve(new object[] { propertyGroupViewModels }); + return _container.Resolve(new object[] {propertyGroupViewModels}); } public TimelineGroupViewModel TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel) { - return _container.Resolve(new object[] { propertyGroupViewModel }); + return _container.Resolve(new object[] {propertyGroupViewModel}); } } @@ -300,6 +304,7 @@ public interface IDataBindingVmFactory : IVmFactory { DataBindingViewModel DataBindingViewModel(); } + public class DataBindingVmFactory : IDataBindingVmFactory { private readonly IContainer _container; @@ -333,6 +338,7 @@ public interface INodeVmFactory : IVmFactory InputPinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel); OutputPinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel); } + public class NodeVmFactory : INodeVmFactory { private readonly IContainer _container; @@ -344,47 +350,47 @@ public class NodeVmFactory : INodeVmFactory public NodeScriptViewModel NodeScriptViewModel(NodeScript nodeScript, bool isPreview) { - return _container.Resolve(new object[] { nodeScript, isPreview }); + return _container.Resolve(new object[] {nodeScript, isPreview}); } public NodePickerViewModel NodePickerViewModel(NodeScript nodeScript) { - return _container.Resolve(new object[] { nodeScript }); + return _container.Resolve(new object[] {nodeScript}); } public NodeViewModel NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node) { - return _container.Resolve(new object[] { nodeScriptViewModel, 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 }); + return _container.Resolve(new object[] {nodeScriptViewModel, from, to}); } public DragCableViewModel DragCableViewModel(PinViewModel pinViewModel) { - return _container.Resolve(new object[] { pinViewModel }); + return _container.Resolve(new object[] {pinViewModel}); } public InputPinViewModel InputPinViewModel(IPin inputPin, NodeScriptViewModel nodeScriptViewModel) { - return _container.Resolve(new object[] { inputPin, nodeScriptViewModel }); + return _container.Resolve(new object[] {inputPin, nodeScriptViewModel}); } public OutputPinViewModel OutputPinViewModel(IPin outputPin, NodeScriptViewModel nodeScriptViewModel) { - return _container.Resolve(new object[] { outputPin, nodeScriptViewModel }); + return _container.Resolve(new object[] {outputPin, nodeScriptViewModel}); } public InputPinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel) { - return _container.Resolve(new object[] { inputPinCollection, nodeScriptViewModel }); + return _container.Resolve(new object[] {inputPinCollection, nodeScriptViewModel}); } public OutputPinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel) { - return _container.Resolve(new object[] { outputPinCollection, nodeScriptViewModel }); + return _container.Resolve(new object[] {outputPinCollection, nodeScriptViewModel}); } } @@ -395,6 +401,7 @@ public interface IConditionVmFactory : IVmFactory StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition); EventConditionViewModel EventConditionViewModel(EventCondition eventCondition); } + public class ConditionVmFactory : IConditionVmFactory { private readonly IContainer _container; @@ -406,22 +413,22 @@ public class ConditionVmFactory : IConditionVmFactory public AlwaysOnConditionViewModel AlwaysOnConditionViewModel(AlwaysOnCondition alwaysOnCondition) { - return _container.Resolve(new object[] { alwaysOnCondition }); + return _container.Resolve(new object[] {alwaysOnCondition}); } public PlayOnceConditionViewModel PlayOnceConditionViewModel(PlayOnceCondition playOnceCondition) { - return _container.Resolve(new object[] { playOnceCondition }); + return _container.Resolve(new object[] {playOnceCondition}); } public StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition) { - return _container.Resolve(new object[] { staticCondition }); + return _container.Resolve(new object[] {staticCondition}); } public EventConditionViewModel EventConditionViewModel(EventCondition eventCondition) { - return _container.Resolve(new object[] { eventCondition }); + return _container.Resolve(new object[] {eventCondition}); } } @@ -432,6 +439,7 @@ public interface ILayerHintVmFactory : IVmFactory KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(Layer layer, KeyboardSectionAdaptionHint adaptionHint); SingleLedAdaptionHintViewModel SingleLedAdaptionHintViewModel(Layer layer, SingleLedAdaptionHint adaptionHint); } + public class LayerHintVmFactory : ILayerHintVmFactory { private readonly IContainer _container; @@ -443,22 +451,22 @@ public class LayerHintVmFactory : ILayerHintVmFactory public CategoryAdaptionHintViewModel CategoryAdaptionHintViewModel(Layer layer, CategoryAdaptionHint adaptionHint) { - return _container.Resolve(new object[] { layer, adaptionHint }); + return _container.Resolve(new object[] {layer, adaptionHint}); } public DeviceAdaptionHintViewModel DeviceAdaptionHintViewModel(Layer layer, DeviceAdaptionHint adaptionHint) { - return _container.Resolve(new object[] { layer, adaptionHint }); + return _container.Resolve(new object[] {layer, adaptionHint}); } public KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(Layer layer, KeyboardSectionAdaptionHint adaptionHint) { - return _container.Resolve(new object[] { layer, adaptionHint }); + return _container.Resolve(new object[] {layer, adaptionHint}); } - + public SingleLedAdaptionHintViewModel SingleLedAdaptionHintViewModel(Layer layer, SingleLedAdaptionHint adaptionHint) { - return _container.Resolve(new object[] { layer, adaptionHint }); + return _container.Resolve(new object[] {layer, adaptionHint}); } } @@ -467,6 +475,7 @@ public interface IScriptVmFactory : IVmFactory ScriptConfigurationViewModel ScriptConfigurationViewModel(ScriptConfiguration scriptConfiguration); ScriptConfigurationViewModel ScriptConfigurationViewModel(Profile profile, ScriptConfiguration scriptConfiguration); } + public class ScriptVmFactory : IScriptVmFactory { private readonly IContainer _container; @@ -478,12 +487,12 @@ public class ScriptVmFactory : IScriptVmFactory public ScriptConfigurationViewModel ScriptConfigurationViewModel(ScriptConfiguration scriptConfiguration) { - return _container.Resolve(new object[] { scriptConfiguration }); + return _container.Resolve(new object[] {scriptConfiguration}); } public ScriptConfigurationViewModel ScriptConfigurationViewModel(Profile profile, ScriptConfiguration scriptConfiguration) { - return _container.Resolve(new object[] { profile, scriptConfiguration }); + return _container.Resolve(new object[] {profile, scriptConfiguration}); } } @@ -491,6 +500,7 @@ public interface IReleaseVmFactory : IVmFactory { ReleaseViewModel ReleaseListViewModel(IGetReleases_PublishedReleases_Nodes release); } + public class ReleaseVmFactory : IReleaseVmFactory { private readonly IContainer _container; @@ -499,9 +509,9 @@ public class ReleaseVmFactory : IReleaseVmFactory { _container = container; } - + public ReleaseViewModel ReleaseListViewModel(IGetReleases_PublishedReleases_Nodes release) { - return _container.Resolve(new object[] { release }); + return _container.Resolve(new object[] {release}); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml b/src/Artemis.UI/Screens/Device/Tabs/General/DeviceGeneralTabView.axaml similarity index 98% rename from src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml rename to src/Artemis.UI/Screens/Device/Tabs/General/DeviceGeneralTabView.axaml index 5512743c0..c6d42e2b5 100644 --- a/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml +++ b/src/Artemis.UI/Screens/Device/Tabs/General/DeviceGeneralTabView.axaml @@ -5,9 +5,10 @@ xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared" xmlns:device="clr-namespace:Artemis.UI.Screens.Device" + xmlns:general="clr-namespace:Artemis.UI.Screens.Device.General" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="650" - x:Class="Artemis.UI.Screens.Device.DeviceGeneralTabView" - x:DataType="device:DeviceGeneralTabViewModel"> + x:Class="Artemis.UI.Screens.Device.General.DeviceGeneralTabView" + x:DataType="general:DeviceGeneralTabViewModel"> diff --git a/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml.cs b/src/Artemis.UI/Screens/Device/Tabs/General/DeviceGeneralTabView.axaml.cs similarity index 76% rename from src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml.cs rename to src/Artemis.UI/Screens/Device/Tabs/General/DeviceGeneralTabView.axaml.cs index 8c4dff8b0..6a0d32d75 100644 --- a/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml.cs +++ b/src/Artemis.UI/Screens/Device/Tabs/General/DeviceGeneralTabView.axaml.cs @@ -1,7 +1,6 @@ -using Avalonia.Controls; using Avalonia.ReactiveUI; -namespace Artemis.UI.Screens.Device; +namespace Artemis.UI.Screens.Device.General; public partial class DeviceGeneralTabView : ReactiveUserControl { public DeviceGeneralTabView() diff --git a/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabViewModel.cs b/src/Artemis.UI/Screens/Device/Tabs/General/DeviceGeneralTabViewModel.cs similarity index 93% rename from src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabViewModel.cs rename to src/Artemis.UI/Screens/Device/Tabs/General/DeviceGeneralTabViewModel.cs index 12275f57a..19bd02b61 100644 --- a/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabViewModel.cs +++ b/src/Artemis.UI/Screens/Device/Tabs/General/DeviceGeneralTabViewModel.cs @@ -4,6 +4,7 @@ using System.Reactive.Disposables; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; +using Artemis.UI.Screens.Device.Layout; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using PropertyChanged.SourceGenerator; @@ -11,7 +12,7 @@ using ReactiveUI; using RGB.NET.Core; using SkiaSharp; -namespace Artemis.UI.Screens.Device; +namespace Artemis.UI.Screens.Device.General; public partial class DeviceGeneralTabViewModel : ActivatableViewModelBase { @@ -56,7 +57,7 @@ public partial class DeviceGeneralTabViewModel : ActivatableViewModelBase _initialGreenScale = Device.GreenScale; _initialBlueScale = Device.BlueScale; - this.WhenAnyValue(x => x.RedScale, x => x.GreenScale, x => x.BlueScale).Subscribe(_ => ApplyScaling()); + this.WhenAnyValue(x => x.RedScale, x => x.GreenScale, x => x.BlueScale).Subscribe(_ => ApplyScaling()); this.WhenActivated(d => { @@ -127,12 +128,12 @@ public partial class DeviceGeneralTabViewModel : ActivatableViewModelBase return; if (!Device.DeviceProvider.CanDetectPhysicalLayout && !await DevicePhysicalLayoutDialogViewModel.SelectPhysicalLayout(_windowService, Device)) return; - if (!Device.DeviceProvider.CanDetectLogicalLayout && !await DeviceLogicalLayoutDialogViewModel.SelectLogicalLayout(_windowService, Device)) + if (!Device.DeviceProvider.CanDetectLogicalLayout && !await Layout.DeviceLogicalLayoutDialogViewModel.SelectLogicalLayout(_windowService, Device)) return; await Task.Delay(400); _deviceService.SaveDevice(Device); - _deviceService.ApplyDeviceLayout(Device, Device.GetBestDeviceLayout()); + _deviceService.LoadDeviceLayout(Device); } private void Apply() diff --git a/src/Artemis.UI/Screens/Device/Tabs/InputMappingsTabView.axaml b/src/Artemis.UI/Screens/Device/Tabs/InputMappings/InputMappingsTabView.axaml similarity index 94% rename from src/Artemis.UI/Screens/Device/Tabs/InputMappingsTabView.axaml rename to src/Artemis.UI/Screens/Device/Tabs/InputMappings/InputMappingsTabView.axaml index e7c3bb42d..f76881aed 100644 --- a/src/Artemis.UI/Screens/Device/Tabs/InputMappingsTabView.axaml +++ b/src/Artemis.UI/Screens/Device/Tabs/InputMappings/InputMappingsTabView.axaml @@ -4,9 +4,10 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:device="clr-namespace:Artemis.UI.Screens.Device" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" + xmlns:inputMappings="clr-namespace:Artemis.UI.Screens.Device.InputMappings" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Artemis.UI.Screens.Device.InputMappingsTabView" - x:DataType="device:InputMappingsTabViewModel"> + x:Class="Artemis.UI.Screens.Device.InputMappings.InputMappingsTabView" + x:DataType="inputMappings:InputMappingsTabViewModel"> diff --git a/src/Artemis.UI/Screens/Device/Tabs/InputMappingsTabView.axaml.cs b/src/Artemis.UI/Screens/Device/Tabs/InputMappings/InputMappingsTabView.axaml.cs similarity index 75% rename from src/Artemis.UI/Screens/Device/Tabs/InputMappingsTabView.axaml.cs rename to src/Artemis.UI/Screens/Device/Tabs/InputMappings/InputMappingsTabView.axaml.cs index c5a533ade..36dea6bb0 100644 --- a/src/Artemis.UI/Screens/Device/Tabs/InputMappingsTabView.axaml.cs +++ b/src/Artemis.UI/Screens/Device/Tabs/InputMappings/InputMappingsTabView.axaml.cs @@ -1,7 +1,6 @@ -using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; -namespace Artemis.UI.Screens.Device; +namespace Artemis.UI.Screens.Device.InputMappings; public partial class InputMappingsTabView : ReactiveUserControl { diff --git a/src/Artemis.UI/Screens/Device/Tabs/InputMappingsTabViewModel.cs b/src/Artemis.UI/Screens/Device/Tabs/InputMappings/InputMappingsTabViewModel.cs similarity index 98% rename from src/Artemis.UI/Screens/Device/Tabs/InputMappingsTabViewModel.cs rename to src/Artemis.UI/Screens/Device/Tabs/InputMappings/InputMappingsTabViewModel.cs index 122029a67..9a116cd92 100644 --- a/src/Artemis.UI/Screens/Device/Tabs/InputMappingsTabViewModel.cs +++ b/src/Artemis.UI/Screens/Device/Tabs/InputMappings/InputMappingsTabViewModel.cs @@ -6,13 +6,12 @@ using Artemis.Core; using Artemis.Core.Services; using Artemis.UI.Exceptions; using Artemis.UI.Shared; -using HidSharp.Reports.Units; using PropertyChanged.SourceGenerator; using ReactiveUI; using RGB.NET.Core; using Unit = System.Reactive.Unit; -namespace Artemis.UI.Screens.Device; +namespace Artemis.UI.Screens.Device.InputMappings; public partial class InputMappingsTabViewModel : ActivatableViewModelBase { diff --git a/src/Artemis.UI/Screens/Device/Tabs/DeviceLayoutTabView.axaml b/src/Artemis.UI/Screens/Device/Tabs/Layout/DeviceLayoutTabView.axaml similarity index 64% rename from src/Artemis.UI/Screens/Device/Tabs/DeviceLayoutTabView.axaml rename to src/Artemis.UI/Screens/Device/Tabs/Layout/DeviceLayoutTabView.axaml index 5075c6e5d..b154411cf 100644 --- a/src/Artemis.UI/Screens/Device/Tabs/DeviceLayoutTabView.axaml +++ b/src/Artemis.UI/Screens/Device/Tabs/Layout/DeviceLayoutTabView.axaml @@ -5,9 +5,12 @@ xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:device="clr-namespace:Artemis.UI.Screens.Device" + xmlns:providers="clr-namespace:Artemis.Core.Providers;assembly=Artemis.Core" + xmlns:layout="clr-namespace:Artemis.UI.Screens.Device.Layout" + xmlns:layoutProviders="clr-namespace:Artemis.UI.Screens.Device.Layout.LayoutProviders" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="800" - x:Class="Artemis.UI.Screens.Device.DeviceLayoutTabView" - x:DataType="device:DeviceLayoutTabViewModel"> + x:Class="Artemis.UI.Screens.Device.Layout.DeviceLayoutTabView" + x:DataType="layout:DeviceLayoutTabViewModel"> @@ -28,6 +31,7 @@ + @@ -45,28 +49,43 @@ + - + - - + + - - - - - - - - - - -