mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Sidebar - Added category reordering
Sidebar - Fix disabled profiles not fading Sidebar - Fix module missing when editing existing profile configs Profile - Remove old undo/redo code
This commit is contained in:
parent
5873df250d
commit
b6e0c0fb66
@ -29,8 +29,6 @@ namespace Artemis.Core
|
|||||||
ProfileEntity = profileEntity;
|
ProfileEntity = profileEntity;
|
||||||
EntityId = profileEntity.Id;
|
EntityId = profileEntity.Id;
|
||||||
|
|
||||||
UndoStack = new MaxStack<string>(20);
|
|
||||||
RedoStack = new MaxStack<string>(20);
|
|
||||||
Exceptions = new List<Exception>();
|
Exceptions = new List<Exception>();
|
||||||
Scripts = new ReadOnlyObservableCollection<ProfileScript>(_scripts);
|
Scripts = new ReadOnlyObservableCollection<ProfileScript>(_scripts);
|
||||||
ScriptConfigurations = new ReadOnlyObservableCollection<ScriptConfiguration>(_scriptConfigurations);
|
ScriptConfigurations = new ReadOnlyObservableCollection<ScriptConfiguration>(_scriptConfigurations);
|
||||||
@ -81,8 +79,6 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ProfileEntity ProfileEntity { get; internal set; }
|
public ProfileEntity ProfileEntity { get; internal set; }
|
||||||
|
|
||||||
internal MaxStack<string> UndoStack { get; set; }
|
|
||||||
internal MaxStack<string> RedoStack { get; set; }
|
|
||||||
internal List<Exception> Exceptions { get; }
|
internal List<Exception> Exceptions { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@ -10,11 +10,6 @@ namespace Artemis.Core.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IProfileService : IArtemisService
|
public interface IProfileService : IArtemisService
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Gets the JSON serializer settings used to create profile mementos
|
|
||||||
/// </summary>
|
|
||||||
public static JsonSerializerSettings MementoSettings { get; } = new() {TypeNameHandling = TypeNameHandling.All};
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the JSON serializer settings used to import/export profiles
|
/// Gets the JSON serializer settings used to import/export profiles
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -109,18 +104,6 @@ namespace Artemis.Core.Services
|
|||||||
/// <param name="includeChildren"></param>
|
/// <param name="includeChildren"></param>
|
||||||
void SaveProfile(Profile profile, bool includeChildren);
|
void SaveProfile(Profile profile, bool includeChildren);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to restore the profile to the state it had before the last <see cref="SaveProfile" /> call.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="profile"></param>
|
|
||||||
bool UndoSaveProfile(Profile profile);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to restore the profile to the state it had before the last <see cref="UndoSaveProfile" /> call.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="profile"></param>
|
|
||||||
bool RedoSaveProfile(Profile profile);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// </summary>
|
||||||
|
|||||||
@ -445,7 +445,7 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
public void SaveProfile(Profile profile, bool includeChildren)
|
public void SaveProfile(Profile profile, bool includeChildren)
|
||||||
{
|
{
|
||||||
string memento = JsonConvert.SerializeObject(profile.ProfileEntity, IProfileService.MementoSettings);
|
_logger.Debug("Updating profile - Saving {Profile}", profile);
|
||||||
profile.Save();
|
profile.Save();
|
||||||
if (includeChildren)
|
if (includeChildren)
|
||||||
{
|
{
|
||||||
@ -453,18 +453,6 @@ namespace Artemis.Core.Services
|
|||||||
child.Save();
|
child.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are no changes, don't bother saving
|
|
||||||
string updatedMemento = JsonConvert.SerializeObject(profile.ProfileEntity, IProfileService.MementoSettings);
|
|
||||||
if (memento.Equals(updatedMemento))
|
|
||||||
{
|
|
||||||
_logger.Debug("Updating profile - Skipping save, no changes");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Debug("Updating profile - Saving " + profile);
|
|
||||||
profile.RedoStack.Clear();
|
|
||||||
profile.UndoStack.Push(memento);
|
|
||||||
|
|
||||||
// At this point the user made actual changes, save that
|
// At this point the user made actual changes, save that
|
||||||
profile.IsFreshImport = false;
|
profile.IsFreshImport = false;
|
||||||
profile.ProfileEntity.IsFreshImport = false;
|
profile.ProfileEntity.IsFreshImport = false;
|
||||||
@ -472,58 +460,6 @@ namespace Artemis.Core.Services
|
|||||||
_profileRepository.Save(profile.ProfileEntity);
|
_profileRepository.Save(profile.ProfileEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool UndoSaveProfile(Profile profile)
|
|
||||||
{
|
|
||||||
// Keep the profile from being rendered by locking it
|
|
||||||
lock (profile)
|
|
||||||
{
|
|
||||||
if (profile.UndoStack.Count == 0)
|
|
||||||
{
|
|
||||||
_logger.Debug("Undo profile update - Failed, undo stack empty");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
string top = profile.UndoStack.Pop();
|
|
||||||
string memento = JsonConvert.SerializeObject(profile.ProfileEntity, IProfileService.MementoSettings);
|
|
||||||
profile.RedoStack.Push(memento);
|
|
||||||
profile.ProfileEntity =
|
|
||||||
JsonConvert.DeserializeObject<ProfileEntity>(top, IProfileService.MementoSettings)
|
|
||||||
?? throw new InvalidOperationException("Failed to deserialize memento");
|
|
||||||
|
|
||||||
profile.Load();
|
|
||||||
profile.PopulateLeds(_rgbService.EnabledDevices);
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Debug("Undo profile update - Success");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool RedoSaveProfile(Profile profile)
|
|
||||||
{
|
|
||||||
// Keep the profile from being rendered by locking it
|
|
||||||
lock (profile)
|
|
||||||
{
|
|
||||||
if (profile.RedoStack.Count == 0)
|
|
||||||
{
|
|
||||||
_logger.Debug("Redo profile update - Failed, redo empty");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
string top = profile.RedoStack.Pop();
|
|
||||||
string memento = JsonConvert.SerializeObject(profile.ProfileEntity, IProfileService.MementoSettings);
|
|
||||||
profile.UndoStack.Push(memento);
|
|
||||||
profile.ProfileEntity =
|
|
||||||
JsonConvert.DeserializeObject<ProfileEntity>(top, IProfileService.MementoSettings)
|
|
||||||
?? throw new InvalidOperationException("Failed to deserialize memento");
|
|
||||||
|
|
||||||
profile.Load();
|
|
||||||
profile.PopulateLeds(_rgbService.EnabledDevices);
|
|
||||||
|
|
||||||
_logger.Debug("Redo profile update - Success");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProfileConfigurationExportModel ExportProfile(ProfileConfiguration profileConfiguration)
|
public ProfileConfigurationExportModel ExportProfile(ProfileConfiguration profileConfiguration)
|
||||||
{
|
{
|
||||||
// The profile may not be active and in that case lets activate it real quick
|
// The profile may not be active and in that case lets activate it real quick
|
||||||
@ -596,8 +532,6 @@ namespace Artemis.Core.Services
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void AdaptProfile(Profile profile)
|
public void AdaptProfile(Profile profile)
|
||||||
{
|
{
|
||||||
string memento = JsonConvert.SerializeObject(profile.ProfileEntity, IProfileService.MementoSettings);
|
|
||||||
|
|
||||||
List<ArtemisDevice> devices = _rgbService.EnabledDevices.ToList();
|
List<ArtemisDevice> devices = _rgbService.EnabledDevices.ToList();
|
||||||
foreach (Layer layer in profile.GetAllLayers())
|
foreach (Layer layer in profile.GetAllLayers())
|
||||||
layer.Adapter.Adapt(devices);
|
layer.Adapter.Adapt(devices);
|
||||||
@ -608,9 +542,6 @@ namespace Artemis.Core.Services
|
|||||||
renderProfileElement.Save();
|
renderProfileElement.Save();
|
||||||
|
|
||||||
_logger.Debug("Adapt profile - Saving " + profile);
|
_logger.Debug("Adapt profile - Saving " + profile);
|
||||||
profile.RedoStack.Clear();
|
|
||||||
profile.UndoStack.Push(memento);
|
|
||||||
|
|
||||||
_profileRepository.Save(profile.ProfileEntity);
|
_profileRepository.Save(profile.ProfileEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,118 +0,0 @@
|
|||||||
// Source: https://ntsblog.homedev.com.au/index.php/2010/05/06/c-stack-with-maximum-limit/
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Artemis.Core
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Generic stack implementation with a maximum limit
|
|
||||||
/// When something is pushed on the last item is removed from the list
|
|
||||||
/// </summary>
|
|
||||||
[Serializable]
|
|
||||||
internal class MaxStack<T>
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
|
|
||||||
private int _limit;
|
|
||||||
private LinkedList<T> _list;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
public MaxStack(int maxSize)
|
|
||||||
{
|
|
||||||
_limit = maxSize;
|
|
||||||
_list = new LinkedList<T>();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Public Stack Implementation
|
|
||||||
|
|
||||||
public void Push(T value)
|
|
||||||
{
|
|
||||||
if (_list.Count == _limit)
|
|
||||||
{
|
|
||||||
_list.RemoveLast();
|
|
||||||
}
|
|
||||||
_list.AddFirst(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Pop()
|
|
||||||
{
|
|
||||||
if (_list.Count > 0)
|
|
||||||
{
|
|
||||||
T value = _list.First!.Value;
|
|
||||||
_list.RemoveFirst();
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("The Stack is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Peek()
|
|
||||||
{
|
|
||||||
if (_list.Count > 0)
|
|
||||||
{
|
|
||||||
T value = _list.First!.Value;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("The Stack is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
_list.Clear();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get { return _list.Count; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the top object on the stack matches the value passed in
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool IsTop(T value)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
if (Count > 0)
|
|
||||||
{
|
|
||||||
result = Peek()!.Equals(value);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(T value)
|
|
||||||
{
|
|
||||||
bool result = false;
|
|
||||||
if (Count > 0)
|
|
||||||
{
|
|
||||||
result = _list.Contains(value);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return _list.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -68,6 +68,7 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
pluginManagementService.GetFeaturesOfType<Module>().Where(m => !m.IsAlwaysAvailable).Select(m => new ProfileModuleViewModel(m))
|
pluginManagementService.GetFeaturesOfType<Module>().Where(m => !m.IsAlwaysAvailable).Select(m => new ProfileModuleViewModel(m))
|
||||||
);
|
);
|
||||||
Modules.Insert(0, null);
|
Modules.Insert(0, null);
|
||||||
|
_selectedModule = Modules.FirstOrDefault(m => m?.Module == _profileConfiguration.Module);
|
||||||
|
|
||||||
VisualEditorViewModel = nodeVmFactory.NodeScriptViewModel(_profileConfiguration.ActivationCondition, true);
|
VisualEditorViewModel = nodeVmFactory.NodeScriptViewModel(_profileConfiguration.ActivationCondition, true);
|
||||||
|
|
||||||
|
|||||||
@ -89,7 +89,32 @@
|
|||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
<Grid x:Name="ContainerGrid" Margin="0 8 0 0" RowDefinitions="Auto,*">
|
<Grid x:Name="ContainerGrid" Margin="0 8 0 0" RowDefinitions="Auto,*" >
|
||||||
|
<Grid.ContextFlyout>
|
||||||
|
<MenuFlyout>
|
||||||
|
<MenuItem Header="View properties" Command="{CompiledBinding EditCategory}">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<avalonia:MaterialIcon Kind="Cog" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="Suspend" Command="{CompiledBinding ToggleSuspended}">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<avalonia:MaterialIcon Kind="Check" IsVisible="{CompiledBinding IsSuspended}" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="-" />
|
||||||
|
<MenuItem Header="Move up" Command="{CompiledBinding MoveUp}">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<avalonia:MaterialIcon Kind="ArrowUp" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="Move down" Command="{CompiledBinding MoveDown}">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<avalonia:MaterialIcon Kind="ArrowDown" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
</MenuFlyout>
|
||||||
|
</Grid.ContextFlyout>
|
||||||
<Grid Grid.Row="0" Background="Transparent" Margin="0 0 6 0" ColumnDefinitions="Auto,*,Auto,Auto,Auto,Auto">
|
<Grid Grid.Row="0" Background="Transparent" Margin="0 0 6 0" ColumnDefinitions="Auto,*,Auto,Auto,Auto,Auto">
|
||||||
<avalonia:MaterialIcon Classes.chevron-collapsed="{CompiledBinding !IsCollapsed}"
|
<avalonia:MaterialIcon Classes.chevron-collapsed="{CompiledBinding !IsCollapsed}"
|
||||||
Kind="ChevronUp"
|
Kind="ChevronUp"
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
@ -54,6 +55,8 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
ToggleSuspended = ReactiveCommand.Create(ExecuteToggleSuspended);
|
ToggleSuspended = ReactiveCommand.Create(ExecuteToggleSuspended);
|
||||||
AddProfile = ReactiveCommand.CreateFromTask(ExecuteAddProfile);
|
AddProfile = ReactiveCommand.CreateFromTask(ExecuteAddProfile);
|
||||||
EditCategory = ReactiveCommand.CreateFromTask(ExecuteEditCategory);
|
EditCategory = ReactiveCommand.CreateFromTask(ExecuteEditCategory);
|
||||||
|
MoveUp = ReactiveCommand.Create(ExecuteMoveUp);
|
||||||
|
MoveDown = ReactiveCommand.Create(ExecuteMoveDown);
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
@ -86,6 +89,9 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
public ReactiveCommand<Unit, Unit> ToggleSuspended { get; }
|
public ReactiveCommand<Unit, Unit> ToggleSuspended { get; }
|
||||||
public ReactiveCommand<Unit, Unit> AddProfile { get; }
|
public ReactiveCommand<Unit, Unit> AddProfile { get; }
|
||||||
public ReactiveCommand<Unit, Unit> EditCategory { get; }
|
public ReactiveCommand<Unit, Unit> EditCategory { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> MoveUp { get; }
|
||||||
|
public ReactiveCommand<Unit, Unit> MoveDown { get; }
|
||||||
|
|
||||||
public ProfileCategory ProfileCategory { get; }
|
public ProfileCategory ProfileCategory { get; }
|
||||||
public ReadOnlyObservableCollection<SidebarProfileConfigurationViewModel> ProfileConfigurations { get; }
|
public ReadOnlyObservableCollection<SidebarProfileConfigurationViewModel> ProfileConfigurations { get; }
|
||||||
|
|
||||||
@ -137,6 +143,36 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
_profileService.SaveProfileCategory(ProfileCategory);
|
_profileService.SaveProfileCategory(ProfileCategory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ExecuteMoveUp()
|
||||||
|
{
|
||||||
|
List<ProfileCategory> categories = _profileService.ProfileCategories.OrderBy(p => p.Order).ToList();
|
||||||
|
int index = categories.IndexOf(ProfileCategory);
|
||||||
|
if (index <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
categories[index - 1].Order++;
|
||||||
|
ProfileCategory.Order--;
|
||||||
|
_profileService.SaveProfileCategory(categories[index - 1]);
|
||||||
|
_profileService.SaveProfileCategory(ProfileCategory);
|
||||||
|
|
||||||
|
_sidebarViewModel.UpdateProfileCategories();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteMoveDown()
|
||||||
|
{
|
||||||
|
List<ProfileCategory> categories = _profileService.ProfileCategories.OrderBy(p => p.Order).ToList();
|
||||||
|
int index = categories.IndexOf(ProfileCategory);
|
||||||
|
if (index >= categories.Count - 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
categories[index + 1].Order--;
|
||||||
|
ProfileCategory.Order++;
|
||||||
|
_profileService.SaveProfileCategory(categories[index + 1]);
|
||||||
|
_profileService.SaveProfileCategory(ProfileCategory);
|
||||||
|
|
||||||
|
_sidebarViewModel.UpdateProfileCategories();
|
||||||
|
}
|
||||||
|
|
||||||
public void AddProfileConfiguration(ProfileConfiguration profileConfiguration, int? index)
|
public void AddProfileConfiguration(ProfileConfiguration profileConfiguration, int? index)
|
||||||
{
|
{
|
||||||
ProfileCategory oldCategory = profileConfiguration.Category;
|
ProfileCategory oldCategory = profileConfiguration.Category;
|
||||||
|
|||||||
@ -43,7 +43,8 @@ namespace Artemis.UI.Screens.Sidebar
|
|||||||
ExportProfile = ReactiveCommand.CreateFromTask(ExecuteExportProfile);
|
ExportProfile = ReactiveCommand.CreateFromTask(ExecuteExportProfile);
|
||||||
DuplicateProfile = ReactiveCommand.Create(ExecuteDuplicateProfile);
|
DuplicateProfile = ReactiveCommand.Create(ExecuteDuplicateProfile);
|
||||||
|
|
||||||
this.WhenActivated(d => _isDisabled = ProfileConfiguration.WhenAnyValue(c => c.IsSuspended, c => c.ActivationConditionMet, (suspended, met) => suspended || !met)
|
this.WhenActivated(d => _isDisabled = ProfileConfiguration.WhenAnyValue(c => c.Profile)
|
||||||
|
.Select(p => p == null)
|
||||||
.ToProperty(this, vm => vm.IsDisabled)
|
.ToProperty(this, vm => vm.IsDisabled)
|
||||||
.DisposeWith(d));
|
.DisposeWith(d));
|
||||||
_profileService.LoadProfileConfigurationIcon(ProfileConfiguration);
|
_profileService.LoadProfileConfigurationIcon(ProfileConfiguration);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user