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:
parent
6a12286783
commit
d4bd44b504
19
src/Artemis.Core/Events/Profiles/ProfileCategoryEventArgs.cs
Normal file
19
src/Artemis.Core/Events/Profiles/ProfileCategoryEventArgs.cs
Normal 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; }
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user