1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Sidebar - Fixed removed categories not dissapearing

Sidebar - Fixed exception when creating a category with an already in use name
This commit is contained in:
Robert 2022-10-12 21:20:39 +02:00
parent 6a12286783
commit d4bd44b504
10 changed files with 193 additions and 144 deletions

View File

@ -0,0 +1,19 @@
using System;
namespace Artemis.Core;
/// <summary>
/// Provides data for profile configuration events.
/// </summary>
public class ProfileCategoryEventArgs : EventArgs
{
internal ProfileCategoryEventArgs(ProfileCategory profileCategory)
{
ProfileCategory = profileCategory;
}
/// <summary>
/// Gets the profile category this event is related to
/// </summary>
public ProfileCategory ProfileCategory { get; }
}

View File

@ -20,9 +20,11 @@ public class ProfileCategory : CorePropertyChanged, IStorageModel
/// Creates a new instance of the <see cref="ProfileCategory" /> class
/// </summary>
/// <param name="name">The name of the category</param>
internal ProfileCategory(string name)
/// <param name="order">The order of the category</param>
internal ProfileCategory(string name, int order)
{
_name = name;
_order = order;
Entity = new ProfileCategoryEntity();
ProfileConfigurations = new ReadOnlyCollection<ProfileConfiguration>(_profileConfigurations);
}

View File

@ -6,135 +6,135 @@ using SkiaSharp;
namespace Artemis.Core.Services;
/// <summary>
/// Provides access to profile storage and is responsible for activating default profiles
/// Provides access to profile storage and is responsible for activating default profiles.
/// </summary>
public interface IProfileService : IArtemisService
{
/// <summary>
/// Gets the JSON serializer settings used to import/export profiles
/// Gets the JSON serializer settings used to import/export profiles.
/// </summary>
public static JsonSerializerSettings ExportSettings { get; } = new() {TypeNameHandling = TypeNameHandling.All, Formatting = Formatting.Indented};
/// <summary>
/// Gets a read only collection containing all the profile categories
/// Gets a read only collection containing all the profile categories.
/// </summary>
ReadOnlyCollection<ProfileCategory> ProfileCategories { get; }
/// <summary>
/// Gets a read only collection containing all the profile configurations
/// Gets a read only collection containing all the profile configurations.
/// </summary>
ReadOnlyCollection<ProfileConfiguration> ProfileConfigurations { get; }
/// <summary>
/// Gets or sets a boolean indicating whether hotkeys are enabled
/// Gets or sets a boolean indicating whether hotkeys are enabled.
/// </summary>
bool HotkeysEnabled { get; set; }
/// <summary>
/// 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.
/// </summary>
bool RenderForEditor { get; set; }
/// <summary>
/// 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.
/// </summary>
ProfileElement? EditorFocus { get; set; }
/// <summary>
/// Activates the profile of the given <see cref="ProfileConfiguration" /> with the currently active surface
/// Activates the profile of the given <see cref="ProfileConfiguration" /> with the currently active surface.
/// </summary>
/// <param name="profileConfiguration">The profile configuration of the profile to activate</param>
/// <param name="profileConfiguration">The profile configuration of the profile to activate.</param>
Profile ActivateProfile(ProfileConfiguration profileConfiguration);
/// <summary>
/// Deactivates the profile of the given <see cref="ProfileConfiguration" /> with the currently active surface
/// Deactivates the profile of the given <see cref="ProfileConfiguration" /> with the currently active surface.
/// </summary>
/// <param name="profileConfiguration">The profile configuration of the profile to activate</param>
/// <param name="profileConfiguration">The profile configuration of the profile to activate.</param>
void DeactivateProfile(ProfileConfiguration profileConfiguration);
/// <summary>
/// Permanently deletes the profile of the given <see cref="ProfileConfiguration" />
/// Permanently deletes the profile of the given <see cref="ProfileConfiguration" />.
/// </summary>
/// <param name="profileConfiguration">The profile configuration of the profile to delete</param>
/// <param name="profileConfiguration">The profile configuration of the profile to delete.</param>
void DeleteProfile(ProfileConfiguration profileConfiguration);
/// <summary>
/// Saves the provided <see cref="ProfileCategory" /> and it's <see cref="ProfileConfiguration" />s but not the
/// <see cref="Profile" />s themselves
/// <see cref="Profile" />s themselves.
/// </summary>
/// <param name="profileCategory">The profile category to update</param>
/// <param name="profileCategory">The profile category to update.</param>
void SaveProfileCategory(ProfileCategory profileCategory);
/// <summary>
/// Creates a new profile category and saves it to persistent storage
/// Creates a new profile category and saves it to persistent storage.
/// </summary>
/// <param name="name">The name of the new profile category, must be unique</param>
/// <returns>The newly created profile category</returns>
/// <param name="name">The name of the new profile category, must be unique.</param>
/// <returns>The newly created profile category.</returns>
ProfileCategory CreateProfileCategory(string name);
/// <summary>
/// Permanently deletes the provided profile category
/// Permanently deletes the provided profile category.
/// </summary>
void DeleteProfileCategory(ProfileCategory profileCategory);
/// <summary>
/// Creates a new profile configuration and adds it to the provided <see cref="ProfileCategory" />
/// Creates a new profile configuration and adds it to the provided <see cref="ProfileCategory" />.
/// </summary>
/// <param name="category">The profile category to add the profile to</param>
/// <param name="name">The name of the new profile configuration</param>
/// <param name="icon">The icon of the new profile configuration</param>
/// <returns>The newly created profile configuration</returns>
/// <param name="category">The profile category to add the profile to.</param>
/// <param name="name">The name of the new profile configuration.</param>
/// <param name="icon">The icon of the new profile configuration.</param>
/// <returns>The newly created profile configuration.</returns>
ProfileConfiguration CreateProfileConfiguration(ProfileCategory category, string name, string icon);
/// <summary>
/// Removes the provided profile configuration from the <see cref="ProfileCategory" />
/// Removes the provided profile configuration from the <see cref="ProfileCategory" />.
/// </summary>
/// <param name="profileConfiguration"></param>
void RemoveProfileConfiguration(ProfileConfiguration profileConfiguration);
/// <summary>
/// Loads the icon of this profile configuration if needed and puts it into <c>ProfileConfiguration.Icon.FileIcon</c>
/// Loads the icon of this profile configuration if needed and puts it into <c>ProfileConfiguration.Icon.FileIcon</c>.
/// </summary>
void LoadProfileConfigurationIcon(ProfileConfiguration profileConfiguration);
/// <summary>
/// Saves the current icon of this profile
/// Saves the current icon of this profile.
/// </summary>
void SaveProfileConfigurationIcon(ProfileConfiguration profileConfiguration);
/// <summary>
/// Writes the profile to persistent storage
/// Writes the profile to persistent storage.
/// </summary>
/// <param name="profile"></param>
/// <param name="includeChildren"></param>
void SaveProfile(Profile profile, bool includeChildren);
/// <summary>
/// Exports the profile described in the given <see cref="ProfileConfiguration" /> into an export model
/// Exports the profile described in the given <see cref="ProfileConfiguration" /> into an export model.
/// </summary>
/// <param name="profileConfiguration">The profile configuration of the profile to export</param>
/// <returns>The resulting export model</returns>
/// <param name="profileConfiguration">The profile configuration of the profile to export.</param>
/// <returns>The resulting export model.</returns>
ProfileConfigurationExportModel ExportProfile(ProfileConfiguration profileConfiguration);
/// <summary>
/// Imports the provided base64 encoded GZIPed JSON as a profile configuration
/// Imports the provided base64 encoded GZIPed JSON as a profile configuration.
/// </summary>
/// <param name="category">The <see cref="ProfileCategory" /> in which to import the profile</param>
/// <param name="exportModel">The model containing the profile to import</param>
/// <param name="makeUnique">Whether or not to give the profile a new GUID, making it unique</param>
/// <param name="category">The <see cref="ProfileCategory" /> in which to import the profile.</param>
/// <param name="exportModel">The model containing the profile to import.</param>
/// <param name="makeUnique">Whether or not to give the profile a new GUID, making it unique.</param>
/// <param name="markAsFreshImport">
/// 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.
/// </param>
/// <param name="nameAffix">Text to add after the name of the profile (separated by a dash)</param>
/// <returns>The resulting profile configuration</returns>
/// <param name="nameAffix">Text to add after the name of the profile (separated by a dash).</param>
/// <returns>The resulting profile configuration.</returns>
ProfileConfiguration ImportProfile(ProfileCategory category, ProfileConfigurationExportModel exportModel, bool makeUnique = true, bool markAsFreshImport = true,
string? nameAffix = "imported");
/// <summary>
/// Adapts a given profile to the currently active devices
/// Adapts a given profile to the currently active devices.
/// </summary>
/// <param name="profile">The profile to adapt</param>
/// <param name="profile">The profile to adapt.</param>
void AdaptProfile(Profile profile);
/// <summary>
@ -143,18 +143,28 @@ public interface IProfileService : IArtemisService
void UpdateProfiles(double deltaTime);
/// <summary>
/// Renders all currently active profiles
/// Renders all currently active profiles.
/// </summary>
/// <param name="canvas"></param>
void RenderProfiles(SKCanvas canvas);
/// <summary>
/// Occurs whenever a profile has been activated
/// Occurs whenever a profile has been activated.
/// </summary>
public event EventHandler<ProfileConfigurationEventArgs>? ProfileActivated;
/// <summary>
/// Occurs whenever a profile has been deactivated
/// Occurs whenever a profile has been deactivated.
/// </summary>
public event EventHandler<ProfileConfigurationEventArgs>? ProfileDeactivated;
/// <summary>
/// Occurs whenever a profile category is added.
/// </summary>
public event EventHandler<ProfileCategoryEventArgs>? ProfileCategoryAdded;
/// <summary>
/// Occurs whenever a profile category is removed.
/// </summary>
public event EventHandler<ProfileCategoryEventArgs>? ProfileCategoryRemoved;
}

View File

@ -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<ProfileConfigurationEventArgs>? ProfileActivated;
public event EventHandler<ProfileConfigurationEventArgs>? ProfileDeactivated;
public event EventHandler<ProfileCategoryEventArgs>? ProfileCategoryAdded;
public event EventHandler<ProfileCategoryEventArgs>? 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
}

View File

@ -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

View File

@ -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);

View File

@ -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<bool>? _isCollapsed;
private ObservableAsPropertyHelper<bool>? _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<ProfileConfiguration>.Ascending(c => c.Order))
.Transform(c => _vmFactory.SidebarProfileConfigurationViewModel(_sidebarViewModel, c))
.Transform(c => _vmFactory.SidebarProfileConfigurationViewModel(c))
.Bind(out ReadOnlyObservableCollection<SidebarProfileConfigurationViewModel> 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();
}
}

View File

@ -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<bool>? _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<ProfileConfigurationEditViewModel, ProfileConfiguration?>(
await _windowService.ShowDialogAsync<ProfileConfigurationEditViewModel, ProfileConfiguration?>(
("profileCategory", ProfileConfiguration.Category),
("profileConfiguration", ProfileConfiguration)
);
if (edited != null)
_sidebarViewModel.UpdateProfileCategories();
}
private void ExecuteToggleSuspended()

View File

@ -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">
<UserControl.Styles>
<StyleInclude Source="avares://Avalonia.Xaml.Interactions/Draggable/Styles.axaml" />
</UserControl.Styles>
@ -24,18 +26,18 @@
<ListBox Classes="sidebar-listbox"
Grid.Row="1"
Margin="10 2"
Items="{Binding SidebarScreens}"
SelectedItem="{Binding SelectedSidebarScreen}" />
Items="{CompiledBinding SidebarScreens}"
SelectedItem="{CompiledBinding SelectedSidebarScreen}" />
<Separator Grid.Row="2" Margin="8" Height="1" Background="#FF6c6c6c" />
<!-- Categories -->
<ScrollViewer Grid.Row="3" VerticalScrollBarVisibility="Auto">
<StackPanel>
<ItemsControl Margin="10 2" Items="{Binding SidebarCategories}" Classes="profile-categories" />
<ItemsControl Margin="10 2" Items="{CompiledBinding SidebarCategories}" Classes="profile-categories" />
<Button Content="Add new category"
Margin="10"
HorizontalAlignment="Stretch"
Command="{Binding AddCategory}" />
Command="{CompiledBinding AddCategory}" />
</StackPanel>
</ScrollViewer>

View File

@ -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<SidebarCategoryViewModel> _sidebarCategories = new(new ObservableCollection<SidebarCategoryViewModel>());
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<SidebarScreenViewModel>
{
@ -55,45 +60,52 @@ public class SidebarViewModel : ActivatableViewModelBase
new SidebarScreenViewModel<SettingsViewModel>(MaterialIconKind.Cog, "Settings")
};
UpdateProfileCategories();
UpdateHeaderDevice();
AddCategory = ReactiveCommand.CreateFromTask(ExecuteAddCategory);
this.WhenActivated(disposables =>
SourceList<ProfileCategory> 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<ProfileCategoryEventArgs>(x => profileService.ProfileCategoryAdded += x, x => profileService.ProfileCategoryAdded -= x)
.Subscribe(e => profileCategories.Add(e.EventArgs.ProfileCategory))
.DisposeWith(d);
Observable.FromEventPattern<ProfileCategoryEventArgs>(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<ProfileCategory>.Ascending(p => p.Order))
.Transform(sidebarVmFactory.SidebarCategoryViewModel)
.ObserveOn(AvaloniaScheduler.Instance)
.Bind(out ReadOnlyObservableCollection<SidebarCategoryViewModel> categoryViewModels)
.Subscribe()
.DisposeWith(d);
SidebarCategories = categoryViewModels;
SelectedSidebarScreen = SidebarScreens.First();
});
}
public ObservableCollection<SidebarScreenViewModel> SidebarScreens { get; }
public ObservableCollection<SidebarCategoryViewModel> SidebarCategories { get; } = new();
public ArtemisDevice? HeaderDevice
public ReadOnlyObservableCollection<SidebarCategoryViewModel> 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<Unit, Unit> 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);
}
}