diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs
index 09e1dc62e..8bb05cb45 100644
--- a/src/Artemis.Core/Models/Profile/Profile.cs
+++ b/src/Artemis.Core/Models/Profile/Profile.cs
@@ -14,6 +14,7 @@ namespace Artemis.Core
{
private readonly object _lock = new();
private bool _isActivated;
+ private bool _isFreshImport;
internal Profile(ProfileModule module, string name) : base(null!)
{
@@ -57,6 +58,20 @@ namespace Artemis.Core
private set => SetAndNotify(ref _isActivated, value);
}
+ ///
+ /// Gets or sets a boolean indicating whether this profile is freshly imported i.e. no changes have been made to it
+ /// since import
+ ///
+ /// Note: As long as this is , profile adaption will be performed on load and any surface
+ /// changes
+ ///
+ ///
+ public bool IsFreshImport
+ {
+ get => _isFreshImport;
+ set => SetAndNotify(ref _isFreshImport, value);
+ }
+
///
/// Gets the profile entity this profile uses for persistent storage
///
@@ -134,6 +149,16 @@ namespace Artemis.Core
layer.PopulateLeds(devices);
}
+ ///
+ /// Occurs when the profile has been activated.
+ ///
+ public event EventHandler? Activated;
+
+ ///
+ /// Occurs when the profile is being deactivated.
+ ///
+ public event EventHandler? Deactivated;
+
///
protected override void Dispose(bool disposing)
{
@@ -156,6 +181,7 @@ namespace Artemis.Core
throw new ObjectDisposedException("Profile");
Name = ProfileEntity.Name;
+ IsFreshImport = ProfileEntity.IsFreshImport;
lock (ChildrenList)
{
@@ -171,9 +197,7 @@ namespace Artemis.Core
Folder _ = new(this, "Root folder");
}
else
- {
AddChild(new Folder(this, this, rootFolder));
- }
}
}
@@ -186,6 +210,7 @@ namespace Artemis.Core
ProfileEntity.ModuleId = Module.Id;
ProfileEntity.Name = Name;
ProfileEntity.IsActive = IsActivated;
+ ProfileEntity.IsFreshImport = IsFreshImport;
foreach (ProfileElement profileElement in Children)
profileElement.Save();
@@ -196,7 +221,7 @@ namespace Artemis.Core
ProfileEntity.Layers.Clear();
ProfileEntity.Layers.AddRange(GetAllLayers().Select(f => f.LayerEntity));
}
-
+
internal void Activate(IEnumerable devices)
{
lock (_lock)
@@ -212,18 +237,6 @@ namespace Artemis.Core
}
}
- #region Events
-
- ///
- /// Occurs when the profile has been activated.
- ///
- public event EventHandler? Activated;
-
- ///
- /// Occurs when the profile is being deactivated.
- ///
- public event EventHandler? Deactivated;
-
private void OnActivated()
{
Activated?.Invoke(this, EventArgs.Empty);
@@ -233,7 +246,5 @@ namespace Artemis.Core
{
Deactivated?.Invoke(this, EventArgs.Empty);
}
-
- #endregion
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/Profile/ProfileDescriptor.cs b/src/Artemis.Core/Models/Profile/ProfileDescriptor.cs
index 7171577fc..7e5d776e5 100644
--- a/src/Artemis.Core/Models/Profile/ProfileDescriptor.cs
+++ b/src/Artemis.Core/Models/Profile/ProfileDescriptor.cs
@@ -37,10 +37,5 @@ namespace Artemis.Core
/// Gets a boolean indicating whether this was the last active profile
///
public bool IsLastActiveProfile { get; }
-
- ///
- /// Gets or sets a boolean indicating whether the profile will be adapted the next time it is activated
- ///
- public bool NeedsAdaption { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Plugins/Modules/ProfileModule.cs b/src/Artemis.Core/Plugins/Modules/ProfileModule.cs
index 0e04cd3b6..cfbdc89e0 100644
--- a/src/Artemis.Core/Plugins/Modules/ProfileModule.cs
+++ b/src/Artemis.Core/Plugins/Modules/ProfileModule.cs
@@ -7,6 +7,7 @@ using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using Artemis.Core.DataModelExpansions;
+using Artemis.Core.Services;
using Artemis.Storage.Entities.Profile;
using Newtonsoft.Json;
using SkiaSharp;
@@ -94,7 +95,9 @@ namespace Artemis.Core.Modules
///
public abstract class ProfileModule : Module
{
- private readonly List _defaultProfiles;
+ private readonly List _defaultProfilePaths = new();
+ private readonly List _pendingDefaultProfilePaths = new();
+ private readonly List _defaultProfiles = new();
private readonly object _lock = new();
///
@@ -102,13 +105,13 @@ namespace Artemis.Core.Modules
///
protected internal readonly List HiddenPropertiesList = new();
+
///
/// Creates a new instance of the class
///
protected ProfileModule()
{
OpacityOverride = 1;
- _defaultProfiles = new List();
}
///
@@ -139,7 +142,7 @@ namespace Artemis.Core.Modules
///
/// Gets a list of default profiles, to add a new default profile use
///
- public ReadOnlyCollection DefaultProfiles => _defaultProfiles.AsReadOnly();
+ internal ReadOnlyCollection DefaultProfiles => _defaultProfiles.AsReadOnly();
///
/// Called after the profile has updated
@@ -167,22 +170,44 @@ namespace Artemis.Core.Modules
///
/// Adds a default profile by reading it from the file found at the provided path
///
- ///
- protected void AddDefaultProfile(string file)
+ /// A path pointing towards a profile file. May be relative to the plugin directory.
+ ///
+ /// if the default profile was added; if it was not because it is
+ /// already in the list.
+ ///
+ protected bool AddDefaultProfile(string file)
{
+ // It can be null if the plugin has not loaded yet...
+ if (Plugin == null!)
+ {
+ if (_pendingDefaultProfilePaths.Contains(file))
+ return false;
+ _pendingDefaultProfilePaths.Add(file);
+ return true;
+ }
+
+ if (!Path.IsPathRooted(file))
+ file = Plugin.ResolveRelativePath(file);
+
+ if (_defaultProfilePaths.Contains(file))
+ return false;
+ _defaultProfilePaths.Add(file);
+
// Ensure the file exists
if (!File.Exists(file))
throw new ArtemisPluginFeatureException(this, $"Could not find default profile at {file}.");
// Deserialize and make sure that succeeded
- ProfileEntity? profileEntity = JsonConvert.DeserializeObject(File.ReadAllText(file));
+ ProfileEntity? profileEntity = JsonConvert.DeserializeObject(File.ReadAllText(file), ProfileService.ExportSettings);
if (profileEntity == null)
throw new ArtemisPluginFeatureException(this, $"Failed to deserialize default profile at {file}.");
// Ensure the profile ID is unique
- ProfileDescriptor descriptor = new(this, profileEntity) {NeedsAdaption = true};
- if (_defaultProfiles.Any(d => d.Id == descriptor.Id))
- throw new ArtemisPluginFeatureException(this, $"Cannot add default profile from {file}, profile ID {descriptor.Id} already in use.");
+ if (_defaultProfiles.Any(d => d.Id == profileEntity.Id))
+ throw new ArtemisPluginFeatureException(this, $"Cannot add default profile from {file}, profile ID {profileEntity.Id} already in use.");
- _defaultProfiles.Add(descriptor);
+ profileEntity.IsFreshImport = true;
+ _defaultProfiles.Add(profileEntity);
+
+ return true;
}
///
@@ -193,6 +218,15 @@ namespace Artemis.Core.Modules
ActiveProfileChanged?.Invoke(this, EventArgs.Empty);
}
+ internal override void InternalEnable()
+ {
+ foreach (string pendingDefaultProfile in _pendingDefaultProfilePaths)
+ AddDefaultProfile(pendingDefaultProfile);
+ _pendingDefaultProfilePaths.Clear();
+
+ base.InternalEnable();
+ }
+
internal override void InternalUpdate(double deltaTime)
{
StartUpdateMeasure();
diff --git a/src/Artemis.Core/Services/ModuleService.cs b/src/Artemis.Core/Services/ModuleService.cs
index a6f85bcfd..22bc8299c 100644
--- a/src/Artemis.Core/Services/ModuleService.cs
+++ b/src/Artemis.Core/Services/ModuleService.cs
@@ -6,6 +6,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Artemis.Core.Modules;
+using Artemis.Storage.Entities.Profile;
using Artemis.Storage.Repositories.Interfaces;
using Serilog;
using Timer = System.Timers.Timer;
@@ -17,13 +18,15 @@ namespace Artemis.Core.Services
private static readonly SemaphoreSlim ActiveModuleSemaphore = new(1, 1);
private readonly ILogger _logger;
private readonly IModuleRepository _moduleRepository;
+ private readonly IProfileRepository _profileRepository;
private readonly IPluginManagementService _pluginManagementService;
private readonly IProfileService _profileService;
- public ModuleService(ILogger logger, IModuleRepository moduleRepository, IPluginManagementService pluginManagementService, IProfileService profileService)
+ public ModuleService(ILogger logger, IModuleRepository moduleRepository, IProfileRepository profileRepository, IPluginManagementService pluginManagementService, IProfileService profileService)
{
_logger = logger;
_moduleRepository = moduleRepository;
+ _profileRepository = profileRepository;
_pluginManagementService = pluginManagementService;
_profileService = profileService;
_pluginManagementService.PluginFeatureEnabled += OnPluginFeatureEnabled;
@@ -45,12 +48,24 @@ namespace Artemis.Core.Services
{
try
{
+ ProfileModule? profileModule = module as ProfileModule;
+
+ if (profileModule != null && profileModule.DefaultProfiles.Any())
+ {
+ List descriptors = _profileService.GetProfileDescriptors(profileModule);
+ foreach (ProfileEntity defaultProfile in profileModule.DefaultProfiles)
+ {
+ if (descriptors.All(d => d.Id != defaultProfile.Id))
+ _profileRepository.Add(defaultProfile);
+ }
+ }
+
module.Activate(false);
try
{
// If this is a profile module, activate the last active profile after module activation
- if (module is ProfileModule profileModule)
+ if (profileModule != null)
await _profileService.ActivateLastProfileAnimated(profileModule);
}
catch (Exception e)
diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs
index 380c9e563..61c5f147a 100644
--- a/src/Artemis.Core/Services/Storage/ProfileService.cs
+++ b/src/Artemis.Core/Services/Storage/ProfileService.cs
@@ -32,8 +32,8 @@ namespace Artemis.Core.Services
_rgbService.LedsChanged += RgbServiceOnLedsChanged;
}
- public JsonSerializerSettings MementoSettings { get; set; } = new() {TypeNameHandling = TypeNameHandling.All};
- public JsonSerializerSettings ExportSettings { get; set; } = new() {TypeNameHandling = TypeNameHandling.All, Formatting = Formatting.Indented};
+ public static JsonSerializerSettings MementoSettings { get; set; } = new() {TypeNameHandling = TypeNameHandling.All};
+ public static JsonSerializerSettings ExportSettings { get; set; } = new() {TypeNameHandling = TypeNameHandling.All, Formatting = Formatting.Indented};
public ProfileDescriptor? GetLastActiveProfile(ProfileModule module)
{
@@ -64,8 +64,16 @@ namespace Artemis.Core.Services
private void ActiveProfilesPopulateLeds()
{
List profileModules = _pluginManagementService.GetFeaturesOfType();
- foreach (ProfileModule profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList())
- profileModule.ActiveProfile?.PopulateLeds(_rgbService.EnabledDevices); // Avoid race condition
+ foreach (ProfileModule profileModule in profileModules)
+ {
+ // Avoid race condition, make the check here
+ if (profileModule.ActiveProfile != null)
+ {
+ profileModule.ActiveProfile.PopulateLeds(_rgbService.EnabledDevices);
+ _logger.Debug("Profile is a fresh import, adapting to surface - {profile}", profileModule.ActiveProfile);
+ AdaptProfile(profileModule.ActiveProfile);
+ }
+ }
}
public List GetProfileDescriptors(ProfileModule module)
@@ -107,13 +115,14 @@ namespace Artemis.Core.Services
Profile profile = new(profileDescriptor.ProfileModule, profileEntity);
InstantiateProfile(profile);
- if (profileDescriptor.NeedsAdaption)
- {
- AdaptProfile(profile);
- profileDescriptor.NeedsAdaption = false;
- }
profileDescriptor.ProfileModule.ChangeActiveProfile(profile, _rgbService.EnabledDevices);
+ if (profile.IsFreshImport)
+ {
+ _logger.Debug("Profile is a fresh import, adapting to surface - {profile}", profile);
+ AdaptProfile(profile);
+ }
+
SaveActiveProfile(profileDescriptor.ProfileModule);
return profile;
@@ -143,7 +152,7 @@ namespace Artemis.Core.Services
Profile profile = new(profileDescriptor.ProfileModule, profileEntity);
InstantiateProfile(profile);
-
+
void ActivatingRgbServiceOnLedsChanged(object? sender, EventArgs e)
{
profile.PopulateLeds(_rgbService.EnabledDevices);
@@ -161,6 +170,12 @@ namespace Artemis.Core.Services
_rgbService.LedsChanged += ActivatingRgbServiceOnLedsChanged;
await profileDescriptor.ProfileModule.ChangeActiveProfileAnimated(profile, _rgbService.EnabledDevices);
+ if (profile.IsFreshImport)
+ {
+ _logger.Debug("Profile is a fresh import, adapting to surface - {profile}", profile);
+ AdaptProfile(profile);
+ }
+
SaveActiveProfile(profileDescriptor.ProfileModule);
_pluginManagementService.PluginEnabled -= ActivatingProfilePluginToggle;
@@ -198,6 +213,8 @@ namespace Artemis.Core.Services
public void DeleteProfile(ProfileDescriptor profileDescriptor)
{
ProfileEntity profileEntity = _profileRepository.Get(profileDescriptor.Id);
+ if (profileEntity == null)
+ return;
_profileRepository.Remove(profileEntity);
}
@@ -208,6 +225,7 @@ namespace Artemis.Core.Services
profile.RedoStack.Clear();
profile.UndoStack.Push(memento);
+ profile.IsFreshImport = false;
profile.Save();
if (includeChildren)
{
@@ -294,8 +312,9 @@ namespace Artemis.Core.Services
profileEntity.UpdateGuid(Guid.NewGuid());
profileEntity.Name = $"{profileEntity.Name} - {nameAffix}";
+ profileEntity.IsFreshImport = true;
_profileRepository.Add(profileEntity);
- return new ProfileDescriptor(profileModule, profileEntity) {NeedsAdaption = true};
+ return new ProfileDescriptor(profileModule, profileEntity);
}
///
diff --git a/src/Artemis.Storage/Entities/Profile/ProfileEntity.cs b/src/Artemis.Storage/Entities/Profile/ProfileEntity.cs
index 177d8c00b..8fac49757 100644
--- a/src/Artemis.Storage/Entities/Profile/ProfileEntity.cs
+++ b/src/Artemis.Storage/Entities/Profile/ProfileEntity.cs
@@ -17,6 +17,7 @@ namespace Artemis.Storage.Entities.Profile
public string Name { get; set; }
public bool IsActive { get; set; }
+ public bool IsFreshImport { get; set; }
public List Folders { get; set; }
public List Layers { get; set; }
diff --git a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs
index 7f7b69743..7e9662b5e 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs
@@ -14,7 +14,6 @@ using Artemis.UI.Screens.ProfileEditor.LayerProperties;
using Artemis.UI.Screens.ProfileEditor.ProfileTree;
using Artemis.UI.Screens.ProfileEditor.Visualization;
using Artemis.UI.Shared.Services;
-using MaterialDesignThemes.Wpf;
using Stylet;
namespace Artemis.UI.Screens.ProfileEditor
@@ -59,7 +58,6 @@ namespace Artemis.UI.Screens.ProfileEditor
Module = module;
DialogService = dialogService;
- DefaultProfiles = new BindableCollection(module.DefaultProfiles);
Profiles = new BindableCollection();
// Populate the panels
@@ -100,9 +98,6 @@ namespace Artemis.UI.Screens.ProfileEditor
set => SetAndNotify(ref _profileViewModel, value);
}
- public BindableCollection DefaultProfiles { get; }
- public bool HasDefaultProfiles => DefaultProfiles.Any();
-
public BindableCollection Profiles
{
get => _profiles;
@@ -392,9 +387,7 @@ namespace Artemis.UI.Screens.ProfileEditor
{
// Get all profiles from the database
Profiles.Clear();
- Profiles.AddRange(_profileService.GetProfileDescriptors(Module));
- Profiles.AddRange(Module.DefaultProfiles.Where(d => Profiles.All(p => p.Id != d.Id)));
- Profiles.Sort(p => p.Name);
+ Profiles.AddRange(_profileService.GetProfileDescriptors(Module).OrderBy(p => p.Name));
}
}
}
\ No newline at end of file