diff --git a/src/Artemis.Core/Events/Profiles/ProfileCategoryEventArgs.cs b/src/Artemis.Core/Events/Profiles/ProfileCategoryEventArgs.cs
new file mode 100644
index 000000000..bc7e6652f
--- /dev/null
+++ b/src/Artemis.Core/Events/Profiles/ProfileCategoryEventArgs.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Artemis.Core;
+
+///
+/// Provides data for profile configuration events.
+///
+public class ProfileCategoryEventArgs : EventArgs
+{
+ internal ProfileCategoryEventArgs(ProfileCategory profileCategory)
+ {
+ ProfileCategory = profileCategory;
+ }
+
+ ///
+ /// Gets the profile category this event is related to
+ ///
+ public ProfileCategory ProfileCategory { get; }
+}
\ 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 3c3358fd7..603bfdf08 100644
--- a/src/Artemis.Core/Models/Profile/ProfileCategory.cs
+++ b/src/Artemis.Core/Models/Profile/ProfileCategory.cs
@@ -20,9 +20,11 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel
/// Creates a new instance of the class
///
/// The name of the category
- internal ProfileCategory(string name)
+ /// The order of the category
+ internal ProfileCategory(string name, int order)
{
_name = name;
+ _order = order;
Entity = new ProfileCategoryEntity();
ProfileConfigurations = new ReadOnlyCollection(_profileConfigurations);
}
diff --git a/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs b/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs
index 7c5e786d5..98e0bc322 100644
--- a/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs
+++ b/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs
@@ -6,135 +6,135 @@ using SkiaSharp;
namespace Artemis.Core.Services;
///
-/// Provides access to profile storage and is responsible for activating default profiles
+/// Provides access to profile storage and is responsible for activating default profiles.
///
public interface IProfileService : IArtemisService
{
///
- /// Gets the JSON serializer settings used to import/export profiles
+ /// Gets the JSON serializer settings used to import/export profiles.
///
public static JsonSerializerSettings ExportSettings { get; } = new() {TypeNameHandling = TypeNameHandling.All, Formatting = Formatting.Indented};
///
- /// Gets a read only collection containing all the profile categories
+ /// Gets a read only collection containing all the profile categories.
///
ReadOnlyCollection ProfileCategories { get; }
///
- /// Gets a read only collection containing all the profile configurations
+ /// Gets a read only collection containing all the profile configurations.
///
ReadOnlyCollection ProfileConfigurations { get; }
///
- /// Gets or sets a boolean indicating whether hotkeys are enabled
+ /// Gets or sets a boolean indicating whether hotkeys are enabled.
///
bool HotkeysEnabled { get; set; }
///
- /// Gets or sets a boolean indicating whether rendering should only be done for profiles being edited
+ /// Gets or sets a boolean indicating whether rendering should only be done for profiles being edited.
///
bool RenderForEditor { get; set; }
///
- /// Gets or sets the profile element to focus on while rendering for the editor
+ /// Gets or sets the profile element to focus on while rendering for the editor.
///
ProfileElement? EditorFocus { get; set; }
///
- /// Activates the profile of the given with the currently active surface
+ /// Activates the profile of the given with the currently active surface.
///
- /// The profile configuration of the profile to activate
+ /// The profile configuration of the profile to activate.
Profile ActivateProfile(ProfileConfiguration profileConfiguration);
///
- /// Deactivates the profile of the given with the currently active surface
+ /// Deactivates the profile of the given with the currently active surface.
///
- /// The profile configuration of the profile to activate
+ /// The profile configuration of the profile to activate.
void DeactivateProfile(ProfileConfiguration profileConfiguration);
///
- /// Permanently deletes the profile of the given
+ /// Permanently deletes the profile of the given .
///
- /// The profile configuration of the profile to delete
+ /// The profile configuration of the profile to delete.
void DeleteProfile(ProfileConfiguration profileConfiguration);
///
/// Saves the provided and it's s but not the
- /// s themselves
+ /// s themselves.
///
- /// The profile category to update
+ /// The profile category to update.
void SaveProfileCategory(ProfileCategory profileCategory);
///
- /// Creates a new profile category and saves it to persistent storage
+ /// Creates a new profile category and saves it to persistent storage.
///
- /// The name of the new profile category, must be unique
- /// The newly created profile category
+ /// The name of the new profile category, must be unique.
+ /// The newly created profile category.
ProfileCategory CreateProfileCategory(string name);
///
- /// Permanently deletes the provided profile category
+ /// Permanently deletes the provided profile category.
///
void DeleteProfileCategory(ProfileCategory profileCategory);
///
- /// Creates a new profile configuration and adds it to the provided
+ /// Creates a new profile configuration and adds it to the provided .
///
- /// The profile category to add the profile to
- /// The name of the new profile configuration
- /// The icon of the new profile configuration
- /// The newly created profile configuration
+ /// The profile category to add the profile to.
+ /// The name of the new profile configuration.
+ /// The icon of the new profile configuration.
+ /// The newly created profile configuration.
ProfileConfiguration CreateProfileConfiguration(ProfileCategory category, string name, string icon);
///
- /// Removes the provided profile configuration from the
+ /// Removes the provided profile configuration from the .
///
///
void RemoveProfileConfiguration(ProfileConfiguration profileConfiguration);
///
- /// Loads the icon of this profile configuration if needed and puts it into ProfileConfiguration.Icon.FileIcon
+ /// Loads the icon of this profile configuration if needed and puts it into ProfileConfiguration.Icon.FileIcon.
///
void LoadProfileConfigurationIcon(ProfileConfiguration profileConfiguration);
///
- /// Saves the current icon of this profile
+ /// Saves the current icon of this profile.
///
void SaveProfileConfigurationIcon(ProfileConfiguration profileConfiguration);
///
- /// Writes the profile to persistent storage
+ /// Writes the profile to persistent storage.
///
///
///
void SaveProfile(Profile profile, bool includeChildren);
///
- /// Exports the profile described in the given into an export model
+ /// Exports the profile described in the given into an export model.
///
- /// The profile configuration of the profile to export
- /// The resulting export model
+ /// The profile configuration of the profile to export.
+ /// The resulting export model.
ProfileConfigurationExportModel ExportProfile(ProfileConfiguration profileConfiguration);
///
- /// Imports the provided base64 encoded GZIPed JSON as a profile configuration
+ /// Imports the provided base64 encoded GZIPed JSON as a profile configuration.
///
- /// The in which to import the profile
- /// The model containing the profile to import
- /// Whether or not to give the profile a new GUID, making it unique
+ /// The in which to import the profile.
+ /// The model containing the profile to import.
+ /// Whether or not to give the profile a new GUID, making it unique.
///
/// Whether or not to mark the profile as a fresh import, causing it to be adapted until
- /// any changes are made to it
+ /// any changes are made to it.
///
- /// Text to add after the name of the profile (separated by a dash)
- /// The resulting profile configuration
+ /// Text to add after the name of the profile (separated by a dash).
+ /// The resulting profile configuration.
ProfileConfiguration ImportProfile(ProfileCategory category, ProfileConfigurationExportModel exportModel, bool makeUnique = true, bool markAsFreshImport = true,
string? nameAffix = "imported");
///
- /// Adapts a given profile to the currently active devices
+ /// Adapts a given profile to the currently active devices.
///
- /// The profile to adapt
+ /// The profile to adapt.
void AdaptProfile(Profile profile);
///
@@ -143,18 +143,28 @@ public interface IProfileService : IArtemisService
void UpdateProfiles(double deltaTime);
///
- /// Renders all currently active profiles
+ /// Renders all currently active profiles.
///
///
void RenderProfiles(SKCanvas canvas);
///
- /// Occurs whenever a profile has been activated
+ /// Occurs whenever a profile has been activated.
///
public event EventHandler? ProfileActivated;
///
- /// Occurs whenever a profile has been deactivated
+ /// Occurs whenever a profile has been deactivated.
///
public event EventHandler? ProfileDeactivated;
+
+ ///
+ /// Occurs whenever a profile category is added.
+ ///
+ public event EventHandler? ProfileCategoryAdded;
+
+ ///
+ /// Occurs whenever a profile category is removed.
+ ///
+ public event EventHandler? ProfileCategoryRemoved;
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs
index 16a2e0341..d5adc7d87 100644
--- a/src/Artemis.Core/Services/Storage/ProfileService.cs
+++ b/src/Artemis.Core/Services/Storage/ProfileService.cs
@@ -53,16 +53,6 @@ internal class ProfileService : IProfileService
UpdateModules();
}
- protected virtual void OnProfileActivated(ProfileConfigurationEventArgs e)
- {
- ProfileActivated?.Invoke(this, e);
- }
-
- protected virtual void OnProfileDeactivated(ProfileConfigurationEventArgs e)
- {
- ProfileDeactivated?.Invoke(this, e);
- }
-
private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e)
{
if (!HotkeysEnabled)
@@ -386,13 +376,16 @@ internal class ProfileService : IProfileService
public ProfileCategory CreateProfileCategory(string name)
{
+ ProfileCategory profileCategory;
lock (_profileRepository)
{
- ProfileCategory profileCategory = new(name);
+ profileCategory = new ProfileCategory(name, _profileCategories.Count + 1);
_profileCategories.Add(profileCategory);
SaveProfileCategory(profileCategory);
- return profileCategory;
}
+
+ OnProfileCategoryAdded(new ProfileCategoryEventArgs(profileCategory));
+ return profileCategory;
}
public void DeleteProfileCategory(ProfileCategory profileCategory)
@@ -406,6 +399,8 @@ internal class ProfileService : IProfileService
_profileCategories.Remove(profileCategory);
_profileCategoryRepository.Remove(profileCategory.Entity);
}
+
+ OnProfileCategoryRemoved(new ProfileCategoryEventArgs(profileCategory));
}
public ProfileConfiguration CreateProfileConfiguration(ProfileCategory category, string name, string icon)
@@ -543,6 +538,32 @@ internal class ProfileService : IProfileService
_profileRepository.Save(profile.ProfileEntity);
}
+ #region Events
+
public event EventHandler? ProfileActivated;
public event EventHandler? ProfileDeactivated;
+ public event EventHandler? ProfileCategoryAdded;
+ public event EventHandler? ProfileCategoryRemoved;
+
+ protected virtual void OnProfileActivated(ProfileConfigurationEventArgs e)
+ {
+ ProfileActivated?.Invoke(this, e);
+ }
+
+ protected virtual void OnProfileDeactivated(ProfileConfigurationEventArgs e)
+ {
+ ProfileDeactivated?.Invoke(this, e);
+ }
+
+ protected virtual void OnProfileCategoryAdded(ProfileCategoryEventArgs e)
+ {
+ ProfileCategoryAdded?.Invoke(this, e);
+ }
+
+ protected virtual void OnProfileCategoryRemoved(ProfileCategoryEventArgs e)
+ {
+ ProfileCategoryRemoved?.Invoke(this, e);
+ }
+
+ #endregion
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs
index da4b16196..06d0b3dfa 100644
--- a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs
+++ b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs
@@ -50,8 +50,8 @@ public interface ISettingsVmFactory : IVmFactory
public interface ISidebarVmFactory : IVmFactory
{
SidebarViewModel? SidebarViewModel(IScreen hostScreen);
- SidebarCategoryViewModel SidebarCategoryViewModel(SidebarViewModel sidebarViewModel, ProfileCategory profileCategory);
- SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(SidebarViewModel sidebarViewModel, ProfileConfiguration profileConfiguration);
+ SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory);
+ SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration);
}
public interface ISurfaceVmFactory : IVmFactory
diff --git a/src/Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditViewModel.cs b/src/Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditViewModel.cs
index f08a25c5e..66d186faf 100644
--- a/src/Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditViewModel.cs
+++ b/src/Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditViewModel.cs
@@ -1,4 +1,5 @@
-using System.Reactive;
+using System.Linq;
+using System.Reactive;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Shared;
@@ -23,7 +24,8 @@ public class SidebarCategoryEditViewModel : ContentDialogViewModelBase
_categoryName = _category.Name;
Confirm = ReactiveCommand.Create(ExecuteConfirm, ValidationContext.Valid);
- this.ValidationRule(vm => vm.CategoryName, categoryName => !string.IsNullOrWhiteSpace(categoryName), "You must specify a valid name");
+ this.ValidationRule(vm => vm.CategoryName, categoryName => !string.IsNullOrWhiteSpace(categoryName?.Trim()), "You must specify a valid name");
+ this.ValidationRule(vm => vm.CategoryName, categoryName => profileService.ProfileCategories.All(c => c.Name != categoryName?.Trim()), "You must specify a unique name");
}
public string? CategoryName
@@ -38,12 +40,12 @@ public class SidebarCategoryEditViewModel : ContentDialogViewModelBase
{
if (_category != null)
{
- _category.Name = CategoryName!;
+ _category.Name = CategoryName!.Trim();
_profileService.SaveProfileCategory(_category);
}
else
{
- _profileService.CreateProfileCategory(CategoryName!);
+ _profileService.CreateProfileCategory(CategoryName!.Trim());
}
ContentDialog?.Hide(ContentDialogResult.Primary);
diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs
index 101ed0908..8da48b281 100644
--- a/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs
+++ b/src/Artemis.UI/Screens/Sidebar/SidebarCategoryViewModel.cs
@@ -24,17 +24,18 @@ namespace Artemis.UI.Screens.Sidebar;
public class SidebarCategoryViewModel : ActivatableViewModelBase
{
private readonly IProfileService _profileService;
- private readonly SidebarViewModel _sidebarViewModel;
private readonly ISidebarVmFactory _vmFactory;
private readonly IWindowService _windowService;
private ObservableAsPropertyHelper? _isCollapsed;
private ObservableAsPropertyHelper? _isSuspended;
private SidebarProfileConfigurationViewModel? _selectedProfileConfiguration;
- public SidebarCategoryViewModel(SidebarViewModel sidebarViewModel, ProfileCategory profileCategory, IProfileService profileService, IWindowService windowService,
- IProfileEditorService profileEditorService, ISidebarVmFactory vmFactory)
+ public SidebarCategoryViewModel(ProfileCategory profileCategory,
+ IProfileService profileService,
+ IWindowService windowService,
+ IProfileEditorService profileEditorService,
+ ISidebarVmFactory vmFactory)
{
- _sidebarViewModel = sidebarViewModel;
_profileService = profileService;
_windowService = windowService;
_vmFactory = vmFactory;
@@ -47,7 +48,7 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase
profileConfigurations.Connect()
.Filter(profileConfigurationsFilter)
.Sort(SortExpressionComparer.Ascending(c => c.Order))
- .Transform(c => _vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, c))
+ .Transform(c => _vmFactory.SidebarProfileConfigurationViewModel(c))
.Bind(out ReadOnlyObservableCollection profileConfigurationViewModels)
.Subscribe();
ProfileConfigurations = profileConfigurationViewModels;
@@ -93,7 +94,7 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase
_windowService.ShowExceptionDialog(s.ProfileConfiguration.BrokenState, s.ProfileConfiguration.BrokenStateException);
else
_windowService.ShowExceptionDialog(e.Message, e);
-
+
profileEditorService.ChangeCurrentProfileConfiguration(null);
SelectedProfileConfiguration = null;
}
@@ -148,8 +149,6 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase
.WithCloseButtonText("Cancel")
.WithDefaultButton(ContentDialogButton.Primary)
.ShowAsync();
-
- _sidebarViewModel.UpdateProfileCategories();
}
private async Task ExecuteDeleteCategory()
@@ -166,7 +165,7 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase
);
if (result != null)
{
- SidebarProfileConfigurationViewModel viewModel = _vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, result);
+ SidebarProfileConfigurationViewModel viewModel = _vmFactory.SidebarProfileConfigurationViewModel(result);
SelectedProfileConfiguration = viewModel;
}
}
@@ -230,8 +229,6 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase
ProfileCategory.Order--;
_profileService.SaveProfileCategory(categories[index - 1]);
_profileService.SaveProfileCategory(ProfileCategory);
-
- _sidebarViewModel.UpdateProfileCategories();
}
private void ExecuteMoveDown()
@@ -245,7 +242,5 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase
ProfileCategory.Order++;
_profileService.SaveProfileCategory(categories[index + 1]);
_profileService.SaveProfileCategory(ProfileCategory);
-
- _sidebarViewModel.UpdateProfileCategories();
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs
index 57c743f1d..8f21f7eca 100644
--- a/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs
+++ b/src/Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationViewModel.cs
@@ -19,17 +19,11 @@ public class SidebarProfileConfigurationViewModel : ActivatableViewModelBase
{
private readonly IProfileEditorService _profileEditorService;
private readonly IProfileService _profileService;
- private readonly SidebarViewModel _sidebarViewModel;
private readonly IWindowService _windowService;
private ObservableAsPropertyHelper? _isDisabled;
- public SidebarProfileConfigurationViewModel(SidebarViewModel sidebarViewModel,
- ProfileConfiguration profileConfiguration,
- IProfileService profileService,
- IProfileEditorService profileEditorService,
- IWindowService windowService)
+ public SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration, IProfileService profileService, IProfileEditorService profileEditorService, IWindowService windowService)
{
- _sidebarViewModel = sidebarViewModel;
_profileService = profileService;
_profileEditorService = profileEditorService;
_windowService = windowService;
@@ -63,13 +57,10 @@ public class SidebarProfileConfigurationViewModel : ActivatableViewModelBase
private async Task ExecuteEditProfile()
{
- ProfileConfiguration? edited = await _windowService.ShowDialogAsync(
+ await _windowService.ShowDialogAsync(
("profileCategory", ProfileConfiguration.Category),
("profileConfiguration", ProfileConfiguration)
);
-
- if (edited != null)
- _sidebarViewModel.UpdateProfileCategories();
}
private void ExecuteToggleSuspended()
diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarView.axaml b/src/Artemis.UI/Screens/Sidebar/SidebarView.axaml
index 5c617be53..d20036165 100644
--- a/src/Artemis.UI/Screens/Sidebar/SidebarView.axaml
+++ b/src/Artemis.UI/Screens/Sidebar/SidebarView.axaml
@@ -4,8 +4,10 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+ xmlns:sidebar="clr-namespace:Artemis.UI.Screens.Sidebar"
mc:Ignorable="d" d:DesignWidth="240" d:DesignHeight="450"
- x:Class="Artemis.UI.Screens.Sidebar.SidebarView">
+ x:Class="Artemis.UI.Screens.Sidebar.SidebarView"
+ x:DataType="sidebar:SidebarViewModel">
@@ -24,18 +26,18 @@
+ Items="{CompiledBinding SidebarScreens}"
+ SelectedItem="{CompiledBinding SelectedSidebarScreen}" />
-
+
+ Command="{CompiledBinding AddCategory}" />
diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs
index 8a2b7852d..22ae73dec 100644
--- a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs
+++ b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs
@@ -1,7 +1,9 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Reactive;
using System.Reactive.Disposables;
+using System.Reactive.Linq;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
@@ -15,35 +17,38 @@ using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Builders;
using Artemis.UI.Shared.Services.ProfileEditor;
+using Avalonia.Threading;
+using DynamicData;
+using DynamicData.Binding;
using Material.Icons;
using Ninject;
using ReactiveUI;
-using RGB.NET.Core;
namespace Artemis.UI.Screens.Sidebar;
public class SidebarViewModel : ActivatableViewModelBase
{
private readonly IScreen _hostScreen;
+ private readonly IKernel _kernel;
private readonly IProfileEditorService _profileEditorService;
- private readonly IProfileService _profileService;
- private readonly IRgbService _rgbService;
- private readonly ISidebarVmFactory _sidebarVmFactory;
+ private readonly IProfileEditorVmFactory _profileEditorVmFactory;
private readonly IWindowService _windowService;
- private ArtemisDevice? _headerDevice;
-
private SidebarScreenViewModel? _selectedSidebarScreen;
+ private ReadOnlyObservableCollection _sidebarCategories = new(new ObservableCollection());
-
- public SidebarViewModel(IScreen hostScreen, IKernel kernel, IProfileService profileService, IRgbService rgbService, IWindowService windowService,
- IProfileEditorService profileEditorService, ISidebarVmFactory sidebarVmFactory, IProfileEditorVmFactory profileEditorVmFactory)
+ public SidebarViewModel(IScreen hostScreen,
+ IKernel kernel,
+ IProfileService profileService,
+ IWindowService windowService,
+ IProfileEditorService profileEditorService,
+ ISidebarVmFactory sidebarVmFactory,
+ IProfileEditorVmFactory profileEditorVmFactory)
{
_hostScreen = hostScreen;
- _profileService = profileService;
- _rgbService = rgbService;
+ _kernel = kernel;
_windowService = windowService;
_profileEditorService = profileEditorService;
- _sidebarVmFactory = sidebarVmFactory;
+ _profileEditorVmFactory = profileEditorVmFactory;
SidebarScreens = new ObservableCollection
{
@@ -55,45 +60,52 @@ public class SidebarViewModel : ActivatableViewModelBase
new SidebarScreenViewModel(MaterialIconKind.Cog, "Settings")
};
- UpdateProfileCategories();
- UpdateHeaderDevice();
+ AddCategory = ReactiveCommand.CreateFromTask(ExecuteAddCategory);
- this.WhenActivated(disposables =>
+ SourceList profileCategories = new();
+
+ this.WhenActivated(d =>
{
- this.WhenAnyObservable(vm => vm._hostScreen.Router.CurrentViewModel)
- .WhereNotNull()
+ this.WhenAnyObservable(vm => vm._hostScreen.Router.CurrentViewModel).WhereNotNull()
.Subscribe(c => SelectedSidebarScreen = SidebarScreens.FirstOrDefault(s => s.ScreenType == c.GetType()))
- .DisposeWith(disposables);
+ .DisposeWith(d);
- this.WhenAnyValue(vm => vm.SelectedSidebarScreen)
- .WhereNotNull()
- .Subscribe(s =>
- {
- _hostScreen.Router.Navigate.Execute(s.CreateInstance(kernel, _hostScreen));
- profileEditorService.ChangeCurrentProfileConfiguration(null);
- });
+ this.WhenAnyValue(vm => vm.SelectedSidebarScreen).WhereNotNull().Subscribe(NavigateToScreen);
+ this.WhenAnyObservable(vm => vm._profileEditorService.ProfileConfiguration).Subscribe(NavigateToProfile).DisposeWith(d);
- this.WhenAnyObservable(vm => vm._profileEditorService.ProfileConfiguration)
- .Subscribe(profile =>
- {
- if (profile == null && _hostScreen.Router.GetCurrentViewModel() is ProfileEditorViewModel)
- SelectedSidebarScreen = SidebarScreens.FirstOrDefault();
- else if (profile != null && _hostScreen.Router.GetCurrentViewModel() is not ProfileEditorViewModel)
- _hostScreen.Router.Navigate.Execute(profileEditorVmFactory.ProfileEditorViewModel(_hostScreen));
- })
- .DisposeWith(disposables);
+ Observable.FromEventPattern(x => profileService.ProfileCategoryAdded += x, x => profileService.ProfileCategoryAdded -= x)
+ .Subscribe(e => profileCategories.Add(e.EventArgs.ProfileCategory))
+ .DisposeWith(d);
+ Observable.FromEventPattern(x => profileService.ProfileCategoryRemoved += x, x => profileService.ProfileCategoryRemoved -= x)
+ .Subscribe(e => profileCategories.Remove(e.EventArgs.ProfileCategory))
+ .DisposeWith(d);
+ profileCategories.Edit(c =>
+ {
+ c.Clear();
+ c.AddRange(profileService.ProfileCategories);
+ });
+
+ profileCategories.Connect()
+ .AutoRefresh(p => p.Order)
+ .Sort(SortExpressionComparer.Ascending(p => p.Order))
+ .Transform(sidebarVmFactory.SidebarCategoryViewModel)
+ .ObserveOn(AvaloniaScheduler.Instance)
+ .Bind(out ReadOnlyObservableCollection categoryViewModels)
+ .Subscribe()
+ .DisposeWith(d);
+
+ SidebarCategories = categoryViewModels;
SelectedSidebarScreen = SidebarScreens.First();
});
}
public ObservableCollection SidebarScreens { get; }
- public ObservableCollection SidebarCategories { get; } = new();
- public ArtemisDevice? HeaderDevice
+ public ReadOnlyObservableCollection SidebarCategories
{
- get => _headerDevice;
- set => RaiseAndSetIfChanged(ref _headerDevice, value);
+ get => _sidebarCategories;
+ set => RaiseAndSetIfChanged(ref _sidebarCategories, value);
}
public SidebarScreenViewModel? SelectedSidebarScreen
@@ -102,14 +114,9 @@ public class SidebarViewModel : ActivatableViewModelBase
set => RaiseAndSetIfChanged(ref _selectedSidebarScreen, value);
}
- public SidebarCategoryViewModel AddProfileCategoryViewModel(ProfileCategory profileCategory)
- {
- SidebarCategoryViewModel viewModel = _sidebarVmFactory.SidebarCategoryViewModel(this, profileCategory);
- SidebarCategories.Add(viewModel);
- return viewModel;
- }
+ public ReactiveCommand AddCategory { get; }
- public async Task AddCategory()
+ private async Task ExecuteAddCategory()
{
await _windowService.CreateContentDialog()
.WithTitle("Add new category")
@@ -118,19 +125,19 @@ public class SidebarViewModel : ActivatableViewModelBase
.WithCloseButtonText("Cancel")
.WithDefaultButton(ContentDialogButton.Primary)
.ShowAsync();
-
- UpdateProfileCategories();
}
- public void UpdateProfileCategories()
+ private void NavigateToProfile(ProfileConfiguration? profile)
{
- SidebarCategories.Clear();
- foreach (ProfileCategory profileCategory in _profileService.ProfileCategories.OrderBy(p => p.Order))
- AddProfileCategoryViewModel(profileCategory);
+ if (profile == null && _hostScreen.Router.GetCurrentViewModel() is ProfileEditorViewModel)
+ SelectedSidebarScreen = SidebarScreens.FirstOrDefault();
+ else if (profile != null && _hostScreen.Router.GetCurrentViewModel() is not ProfileEditorViewModel)
+ _hostScreen.Router.Navigate.Execute(_profileEditorVmFactory.ProfileEditorViewModel(_hostScreen));
}
- private void UpdateHeaderDevice()
+ private void NavigateToScreen(SidebarScreenViewModel sidebarScreenViewModel)
{
- HeaderDevice = _rgbService.Devices.FirstOrDefault(d => d.DeviceType == RGBDeviceType.Keyboard && d.Layout is {IsValid: true});
+ _hostScreen.Router.Navigate.Execute(sidebarScreenViewModel.CreateInstance(_kernel, _hostScreen));
+ _profileEditorService.ChangeCurrentProfileConfiguration(null);
}
}
\ No newline at end of file