diff --git a/src/.idea/.idea.Artemis/.idea/avalonia.xml b/src/.idea/.idea.Artemis/.idea/avalonia.xml index 07f14ce84..8021c13f5 100644 --- a/src/.idea/.idea.Artemis/.idea/avalonia.xml +++ b/src/.idea/.idea.Artemis/.idea/avalonia.xml @@ -14,6 +14,7 @@ + @@ -27,7 +28,12 @@ + + + + + @@ -40,6 +46,7 @@ + @@ -47,6 +54,7 @@ + diff --git a/src/Artemis.Core/Events/Profiles/LayerAdapterHintEventArgs.cs b/src/Artemis.Core/Events/Profiles/LayerAdapterHintEventArgs.cs new file mode 100644 index 000000000..5d3600ba4 --- /dev/null +++ b/src/Artemis.Core/Events/Profiles/LayerAdapterHintEventArgs.cs @@ -0,0 +1,19 @@ +using System; + +namespace Artemis.Core; + +/// +/// Provides data for layer adapter hint events. +/// +public class LayerAdapterHintEventArgs : EventArgs +{ + internal LayerAdapterHintEventArgs(IAdaptionHint adaptionHint) + { + AdaptionHint = adaptionHint; + } + + /// + /// Gets the layer adaption hint this event is related to + /// + public IAdaptionHint AdaptionHint { get; } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/AdaptionHints/CategoryAdaptionHint.cs b/src/Artemis.Core/Models/Profile/AdaptionHints/CategoryAdaptionHint.cs index 824b27963..18e87f574 100644 --- a/src/Artemis.Core/Models/Profile/AdaptionHints/CategoryAdaptionHint.cs +++ b/src/Artemis.Core/Models/Profile/AdaptionHints/CategoryAdaptionHint.cs @@ -7,8 +7,13 @@ namespace Artemis.Core /// /// Represents a hint that adapts layers to a certain category of devices /// - public class CategoryAdaptionHint : IAdaptionHint + public class CategoryAdaptionHint : CorePropertyChanged, IAdaptionHint { + private DeviceCategory _category; + private int _skip; + private bool _limitAmount; + private int _amount; + /// /// Creates a new instance of the class /// @@ -27,22 +32,38 @@ namespace Artemis.Core /// /// Gets or sets the category of devices LEDs will be applied to /// - public DeviceCategory Category { get; set; } + public DeviceCategory Category + { + get => _category; + set => SetAndNotify(ref _category, value); + } /// /// Gets or sets the amount of devices to skip /// - public int Skip { get; set; } + public int Skip + { + get => _skip; + set => SetAndNotify(ref _skip, value); + } /// /// Gets or sets a boolean indicating whether a limited amount of devices should be used /// - public bool LimitAmount { get; set; } + public bool LimitAmount + { + get => _limitAmount; + set => SetAndNotify(ref _limitAmount, value); + } /// /// Gets or sets the amount of devices to limit to if is /// - public int Amount { get; set; } + public int Amount + { + get => _amount; + set => SetAndNotify(ref _amount, value); + } /// public override string ToString() diff --git a/src/Artemis.Core/Models/Profile/AdaptionHints/DeviceAdaptionHint.cs b/src/Artemis.Core/Models/Profile/AdaptionHints/DeviceAdaptionHint.cs index 28058f641..62ed05b85 100644 --- a/src/Artemis.Core/Models/Profile/AdaptionHints/DeviceAdaptionHint.cs +++ b/src/Artemis.Core/Models/Profile/AdaptionHints/DeviceAdaptionHint.cs @@ -8,8 +8,13 @@ namespace Artemis.Core /// /// Represents a hint that adapts layers to a certain type of devices /// - public class DeviceAdaptionHint : IAdaptionHint + public class DeviceAdaptionHint : CorePropertyChanged, IAdaptionHint { + private RGBDeviceType _deviceType; + private int _skip; + private bool _limitAmount; + private int _amount; + /// /// Creates a new instance of the class /// @@ -28,22 +33,38 @@ namespace Artemis.Core /// /// Gets or sets the type of devices LEDs will be applied to /// - public RGBDeviceType DeviceType { get; set; } + public RGBDeviceType DeviceType + { + get => _deviceType; + set => SetAndNotify(ref _deviceType, value); + } /// /// Gets or sets the amount of devices to skip /// - public int Skip { get; set; } + public int Skip + { + get => _skip; + set => SetAndNotify(ref _skip, value); + } /// /// Gets or sets a boolean indicating whether a limited amount of devices should be used /// - public bool LimitAmount { get; set; } + public bool LimitAmount + { + get => _limitAmount; + set => SetAndNotify(ref _limitAmount, value); + } /// /// Gets or sets the amount of devices to limit to if is /// - public int Amount { get; set; } + public int Amount + { + get => _amount; + set => SetAndNotify(ref _amount, value); + } #region Implementation of IAdaptionHint diff --git a/src/Artemis.Core/Models/Profile/AdaptionHints/KeyboardSectionAdaptionHint.cs b/src/Artemis.Core/Models/Profile/AdaptionHints/KeyboardSectionAdaptionHint.cs index 0177a8938..cf61108c4 100644 --- a/src/Artemis.Core/Models/Profile/AdaptionHints/KeyboardSectionAdaptionHint.cs +++ b/src/Artemis.Core/Models/Profile/AdaptionHints/KeyboardSectionAdaptionHint.cs @@ -9,7 +9,7 @@ namespace Artemis.Core /// /// Represents a hint that adapts layers to a certain region of keyboards /// - public class KeyboardSectionAdaptionHint : IAdaptionHint + public class KeyboardSectionAdaptionHint : CorePropertyChanged, IAdaptionHint { private static readonly Dictionary> RegionLedIds = new() { @@ -18,6 +18,8 @@ namespace Artemis.Core {KeyboardSection.Extra, Enum.GetValues().Where(l => l >= LedId.Keyboard_Custom1 && l <= LedId.Keyboard_Custom64).ToList()} }; + private KeyboardSection _section; + /// /// Creates a new instance of the class /// @@ -33,7 +35,11 @@ namespace Artemis.Core /// /// Gets or sets the section this hint will apply LEDs to /// - public KeyboardSection Section { get; set; } + public KeyboardSection Section + { + get => _section; + set => SetAndNotify(ref _section, value); + } #region Implementation of IAdaptionHint diff --git a/src/Artemis.Core/Models/Profile/LayerAdapter.cs b/src/Artemis.Core/Models/Profile/LayerAdapter.cs index b60d901f9..aa8ceeb5c 100644 --- a/src/Artemis.Core/Models/Profile/LayerAdapter.cs +++ b/src/Artemis.Core/Models/Profile/LayerAdapter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using Artemis.Storage.Entities.Profile; using Artemis.Storage.Entities.Profile.AdaptionHints; @@ -12,10 +13,13 @@ namespace Artemis.Core /// public class LayerAdapter : IStorageModel { + private readonly List _adaptionHints; + internal LayerAdapter(Layer layer) { + _adaptionHints = new List(); Layer = layer; - AdaptionHints = new List(); + AdaptionHints = new ReadOnlyCollection(_adaptionHints); } /// @@ -26,7 +30,7 @@ namespace Artemis.Core /// /// Gets or sets a list containing the adaption hints used by this adapter /// - public List AdaptionHints { get; set; } + public ReadOnlyCollection AdaptionHints { get; set; } /// /// Modifies the layer, adapting it to the provided @@ -73,7 +77,7 @@ namespace Artemis.Core if (devices.All(DoesLayerCoverDevice)) { DeviceAdaptionHint hint = new() {DeviceType = RGBDeviceType.All}; - AdaptionHints.Add(hint); + Add(hint); newHints.Add(hint); } else @@ -88,7 +92,7 @@ namespace Artemis.Core if (DoesLayerCoverDevice(device)) { DeviceAdaptionHint hint = new() {DeviceType = device.DeviceType}; - AdaptionHints.Add(hint); + Add(hint); newHints.Add(hint); } } @@ -103,7 +107,7 @@ namespace Artemis.Core if (categoryDevices.Any() && categoryDevices.All(DoesLayerCoverDevice)) { CategoryAdaptionHint hint = new() {Category = deviceCategory}; - AdaptionHints.Add(hint); + Add(hint); newHints.Add(hint); } } @@ -117,25 +121,57 @@ namespace Artemis.Core return device.Leds.All(l => Layer.Leds.Contains(l)); } + /// + /// Adds an adaption hint to the adapter. + /// + /// The adaption hint to add. + public void Add(IAdaptionHint adaptionHint) + { + if (_adaptionHints.Contains(adaptionHint)) + return; + + _adaptionHints.Add(adaptionHint); + AdapterHintAdded?.Invoke(this, new LayerAdapterHintEventArgs(adaptionHint)); + } + + /// + /// Removes the first occurrence of a specific adaption hint from the adapter. + /// + /// The adaption hint to remove. + public void Remove(IAdaptionHint adaptionHint) + { + if (_adaptionHints.Remove(adaptionHint)) + AdapterHintRemoved?.Invoke(this, new LayerAdapterHintEventArgs(adaptionHint)); + } + + /// + /// Removes all adaption hints from the adapter. + /// + public void Clear() + { + while (_adaptionHints.Any()) + Remove(_adaptionHints.First()); + } + #region Implementation of IStorageModel /// public void Load() { - AdaptionHints.Clear(); + _adaptionHints.Clear(); // Kind of meh. // This leaves the adapter responsible for finding the right hint for the right entity, but it's gotta be done somewhere.. foreach (IAdaptionHintEntity hintEntity in Layer.LayerEntity.AdaptionHints) switch (hintEntity) { case DeviceAdaptionHintEntity entity: - AdaptionHints.Add(new DeviceAdaptionHint(entity)); + Add(new DeviceAdaptionHint(entity)); break; case CategoryAdaptionHintEntity entity: - AdaptionHints.Add(new CategoryAdaptionHint(entity)); + Add(new CategoryAdaptionHint(entity)); break; case KeyboardSectionAdaptionHintEntity entity: - AdaptionHints.Add(new KeyboardSectionAdaptionHint(entity)); + Add(new KeyboardSectionAdaptionHint(entity)); break; } } @@ -149,5 +185,15 @@ namespace Artemis.Core } #endregion + + /// + /// Occurs whenever a new adapter hint is added to the adapter. + /// + public event EventHandler? AdapterHintAdded; + + /// + /// Occurs whenever an adapter hint is removed from the adapter. + /// + public event EventHandler? AdapterHintRemoved; } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Controls/EnumComboBox.axaml b/src/Artemis.UI.Shared/Controls/EnumComboBox.axaml index 36ada5068..59195d73a 100644 --- a/src/Artemis.UI.Shared/Controls/EnumComboBox.axaml +++ b/src/Artemis.UI.Shared/Controls/EnumComboBox.axaml @@ -7,7 +7,7 @@ - + diff --git a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs index d96befb87..05e6d08e2 100644 --- a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs +++ b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs @@ -7,6 +7,7 @@ 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; @@ -114,4 +115,11 @@ public interface IConditionVmFactory : IVmFactory PlayOnceConditionViewModel PlayOnceConditionViewModel(PlayOnceCondition playOnceCondition); StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition); EventConditionViewModel EventConditionViewModel(EventCondition eventCondition); +} + +public interface ILayerHintVmFactory : IVmFactory +{ + CategoryAdaptionHintViewModel CategoryAdaptionHintViewModel(CategoryAdaptionHint adaptionHint); + DeviceAdaptionHintViewModel DeviceAdaptionHintViewModel(DeviceAdaptionHint adaptionHint); + KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(KeyboardSectionAdaptionHint adaptionHint); } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/AdaptionHintViewModelBase.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/AdaptionHintViewModelBase.cs new file mode 100644 index 000000000..96495d5c8 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/AdaptionHintViewModelBase.cs @@ -0,0 +1,22 @@ +using System.Reactive; +using Artemis.Core; +using Artemis.UI.Shared; +using ReactiveUI; + +namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints; + +public abstract class AdaptionHintViewModelBase : ViewModelBase +{ + protected AdaptionHintViewModelBase(IAdaptionHint adaptionHint) + { + AdaptionHint = adaptionHint; + Remove = ReactiveCommand.Create(ExecuteRemove); + } + + public ReactiveCommand Remove { get; } + public IAdaptionHint AdaptionHint { get; } + + private void ExecuteRemove() + { + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/CategoryAdaptionHintView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/CategoryAdaptionHintView.axaml new file mode 100644 index 000000000..6fc3e55ba --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/CategoryAdaptionHintView.axaml @@ -0,0 +1,52 @@ + + + + Category hint + Applies the layer to devices of a certain category + + + + + + + + Skip + + device(s) + + Take + + device(s) + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/CategoryAdaptionHintView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/CategoryAdaptionHintView.axaml.cs new file mode 100644 index 000000000..41b29c88a --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/CategoryAdaptionHintView.axaml.cs @@ -0,0 +1,18 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints; + +public partial class CategoryAdaptionHintView : UserControl +{ + public CategoryAdaptionHintView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/CategoryAdaptionHintViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/CategoryAdaptionHintViewModel.cs new file mode 100644 index 000000000..7d6c3cc11 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/CategoryAdaptionHintViewModel.cs @@ -0,0 +1,13 @@ +using Artemis.Core; + +namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints; + +public class CategoryAdaptionHintViewModel : AdaptionHintViewModelBase +{ + public CategoryAdaptionHintViewModel(CategoryAdaptionHint adaptionHint) : base(adaptionHint) + { + CategoryAdaptionHint = adaptionHint; + } + + public CategoryAdaptionHint CategoryAdaptionHint { get; } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/DeviceAdaptionHintView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/DeviceAdaptionHintView.axaml new file mode 100644 index 000000000..0a21cc216 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/DeviceAdaptionHintView.axaml @@ -0,0 +1,52 @@ + + + + Device type hint + Applies the layer to devices of a certain type + + + + + + + + Skip + + device(s) + + Take + + device(s) + + + + + diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/DeviceAdaptionHintView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/DeviceAdaptionHintView.axaml.cs new file mode 100644 index 000000000..af6f2ef81 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/DeviceAdaptionHintView.axaml.cs @@ -0,0 +1,18 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints; + +public partial class DeviceAdaptionHintView : UserControl +{ + public DeviceAdaptionHintView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/DeviceAdaptionHintViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/DeviceAdaptionHintViewModel.cs new file mode 100644 index 000000000..723554871 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/DeviceAdaptionHintViewModel.cs @@ -0,0 +1,13 @@ +using Artemis.Core; + +namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints; + +public class DeviceAdaptionHintViewModel : AdaptionHintViewModelBase +{ + public DeviceAdaptionHintViewModel(DeviceAdaptionHint adaptionHint) : base(adaptionHint) + { + DeviceAdaptionHint = adaptionHint; + } + + public DeviceAdaptionHint DeviceAdaptionHint { get; } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/KeyboardSectionAdaptionHintView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/KeyboardSectionAdaptionHintView.axaml new file mode 100644 index 000000000..aeb3353dc --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/KeyboardSectionAdaptionHintView.axaml @@ -0,0 +1,32 @@ + + + + Keyboard section hint + Applies the layer to a section of all keyboards + + + + + + + + + diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/KeyboardSectionAdaptionHintView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/KeyboardSectionAdaptionHintView.axaml.cs new file mode 100644 index 000000000..7acec3936 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/KeyboardSectionAdaptionHintView.axaml.cs @@ -0,0 +1,18 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints; + +public partial class KeyboardSectionAdaptionHintView : UserControl +{ + public KeyboardSectionAdaptionHintView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/KeyboardSectionAdaptionHintViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/KeyboardSectionAdaptionHintViewModel.cs new file mode 100644 index 000000000..3d4449deb --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/KeyboardSectionAdaptionHintViewModel.cs @@ -0,0 +1,13 @@ +using Artemis.Core; + +namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints; + +public class KeyboardSectionAdaptionHintViewModel : AdaptionHintViewModelBase +{ + public KeyboardSectionAdaptionHintViewModel(KeyboardSectionAdaptionHint adaptionHint) : base(adaptionHint) + { + KeyboardSectionAdaptionHint = adaptionHint; + } + + public KeyboardSectionAdaptionHint KeyboardSectionAdaptionHint { get; } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogView.axaml new file mode 100644 index 000000000..75b799e45 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogView.axaml @@ -0,0 +1,81 @@ + + + + + + + + + + + Learn more about adaption hints + + + + Add hints below to help decide where to place this layer when the profile is imported. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Add hint + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogView.axaml.cs new file mode 100644 index 000000000..2a4585ba1 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogView.axaml.cs @@ -0,0 +1,22 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using FluentAvalonia.UI.Controls; + +namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs; + +public partial class LayerHintsDialogView : ReactiveCoreWindow +{ + public LayerHintsDialogView() + { + InitializeComponent(); +#if DEBUG + this.AttachDevTools(); +#endif + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogViewModel.cs new file mode 100644 index 000000000..ae4786351 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogViewModel.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive.Linq; +using Artemis.Core; +using Artemis.Core.Services; +using Artemis.UI.Ninject.Factories; +using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints; +using Artemis.UI.Shared; +using Avalonia.Controls.Mixins; +using DynamicData; +using ReactiveUI; + +namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs; + +public class LayerHintsDialogViewModel : DialogViewModelBase +{ + private readonly IRgbService _rgbService; + private readonly ILayerHintVmFactory _vmFactory; + + public LayerHintsDialogViewModel(Layer layer, IRgbService rgbService, ILayerHintVmFactory vmFactory) + { + _rgbService = rgbService; + _vmFactory = vmFactory; + + Layer = layer; + AdaptionHints = new ObservableCollection(); + + this.WhenActivated(d => + { + Observable.FromEventPattern(x => layer.Adapter.AdapterHintAdded += x, x => layer.Adapter.AdapterHintAdded -= x) + .Subscribe(c => AdaptionHints.Add(CreateHintViewModel(c.EventArgs.AdaptionHint))) + .DisposeWith(d); + Observable.FromEventPattern(x => layer.Adapter.AdapterHintRemoved += x, x => layer.Adapter.AdapterHintRemoved -= x) + .Subscribe(c => AdaptionHints.Remove(AdaptionHints.FirstOrDefault(h => h.AdaptionHint == c.EventArgs.AdaptionHint)!)) + .DisposeWith(d); + + AdaptionHints.AddRange(Layer.Adapter.AdaptionHints.Select(CreateHintViewModel)); + }); + } + + public Layer Layer { get; } + public ObservableCollection AdaptionHints { get; } + + public void Finish() + { + Close(true); + } + + public void AutoDetermineHints() + { + Layer.Adapter.DetermineHints(_rgbService.EnabledDevices); + } + + public void AddCategoryHint() + { + Layer.Adapter.Add(new CategoryAdaptionHint()); + } + + public void AddDeviceHint() + { + Layer.Adapter.Add(new DeviceAdaptionHint()); + } + + public void AddKeyboardSectionHint() + { + Layer.Adapter.Add(new KeyboardSectionAdaptionHint()); + } + + public void RemoveAdaptionHint(IAdaptionHint hint) + { + Layer.Adapter.Remove(hint); + } + + private AdaptionHintViewModelBase CreateHintViewModel(IAdaptionHint hint) + { + return hint switch + { + CategoryAdaptionHint categoryAdaptionHint => _vmFactory.CategoryAdaptionHintViewModel(categoryAdaptionHint), + DeviceAdaptionHint deviceAdaptionHint => _vmFactory.DeviceAdaptionHintViewModel(deviceAdaptionHint), + KeyboardSectionAdaptionHint keyboardSectionAdaptionHint => _vmFactory.KeyboardSectionAdaptionHintViewModel(keyboardSectionAdaptionHint), + _ => throw new ArgumentOutOfRangeException(nameof(hint)) + }; + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml index 22cff3a34..45e2d9141 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml @@ -112,6 +112,11 @@ + + + + + diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs index fe2315ced..7f9e55f14 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Artemis.Core; 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; using Artemis.UI.Shared.Services.ProfileEditor; @@ -46,6 +47,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase AddLayer = ReactiveCommand.Create(ExecuteAddLayer); AddFolder = ReactiveCommand.Create(ExecuteAddFolder); + OpenAdaptionHints = ReactiveCommand.CreateFromTask(ExecuteOpenAdaptionHints, this.WhenAnyValue(vm => vm.ProfileElement).Select(p => p is Layer)); Rename = ReactiveCommand.Create(ExecuteRename); Delete = ReactiveCommand.Create(ExecuteDelete); Duplicate = ReactiveCommand.CreateFromTask(ExecuteDuplicate); @@ -97,6 +99,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase public ReactiveCommand AddLayer { get; } public ReactiveCommand AddFolder { get; } + public ReactiveCommand OpenAdaptionHints { get; } public ReactiveCommand Rename { get; } public ReactiveCommand Duplicate { get; } public ReactiveCommand Copy { get; } @@ -247,6 +250,14 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase if (ProfileElement != null) ProfileEditorService.CreateAndAddLayer(ProfileElement); } + + private async Task ExecuteOpenAdaptionHints() + { + if (ProfileElement is not Layer layer) + return; + + await _windowService.ShowDialogAsync(("layer", layer)); + } private async void UpdateCanPaste(bool isFlyoutOpen) {