diff --git a/src/Artemis.Core/Plugins/Modules/ActivationRequirements/ProcessActivationRequirement.cs b/src/Artemis.Core/Plugins/Modules/ActivationRequirements/ProcessActivationRequirement.cs
index dda84aa6d..e18212b6d 100644
--- a/src/Artemis.Core/Plugins/Modules/ActivationRequirements/ProcessActivationRequirement.cs
+++ b/src/Artemis.Core/Plugins/Modules/ActivationRequirements/ProcessActivationRequirement.cs
@@ -1,4 +1,5 @@
-using System.Diagnostics;
+using System;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using Artemis.Core.Extensions;
@@ -39,7 +40,7 @@ namespace Artemis.Core.Plugins.Modules.ActivationRequirements
var processes = ProcessName != null ? Process.GetProcessesByName(ProcessName).Where(p => !p.HasExited) : Process.GetProcesses().Where(p => !p.HasExited);
return Location != null
- ? processes.Any(p => Path.GetDirectoryName(p.GetProcessFilename()) == Location)
+ ? processes.Any(p => string.Equals(Path.GetDirectoryName(p.GetProcessFilename()), Location, StringComparison.CurrentCultureIgnoreCase))
: processes.Any();
}
}
diff --git a/src/Artemis.Core/Plugins/Modules/Module.cs b/src/Artemis.Core/Plugins/Modules/Module.cs
index eb71dbec3..7f77ca5f8 100644
--- a/src/Artemis.Core/Plugins/Modules/Module.cs
+++ b/src/Artemis.Core/Plugins/Modules/Module.cs
@@ -79,6 +79,12 @@ namespace Artemis.Core.Plugins.Modules
///
public string DisplayIcon { get; set; }
+ ///
+ /// A path to an image to use as the modules display icon that's shown in the menu.
+ /// If set, takes precedence over
+ ///
+ public string DisplayIconPath { get; set; }
+
///
/// Gets whether this module is activated. A module can only be active while its
/// are met
@@ -138,14 +144,22 @@ namespace Artemis.Core.Plugins.Modules
public abstract void Render(double deltaTime, ArtemisSurface surface, SKCanvas canvas, SKImageInfo canvasInfo);
///
- /// Called when the are met
+ /// Called when the are met or during an override
///
- public abstract void ModuleActivated();
+ ///
+ /// If true, the activation was due to an override. This usually means the module was activated
+ /// by the profile editor
+ ///
+ public abstract void ModuleActivated(bool isOverride);
///
- /// Called when the are no longer met
+ /// Called when the are no longer met or during an override
///
- public abstract void ModuleDeactivated();
+ ///
+ /// If true, the deactivation was due to an override. This usually means the module was deactivated
+ /// by the profile editor
+ ///
+ public abstract void ModuleDeactivated(bool isOverride);
///
/// Evaluates the activation requirements following the and returns the result
@@ -163,22 +177,22 @@ namespace Artemis.Core.Plugins.Modules
return false;
}
- internal virtual void Activate()
+ internal virtual void Activate(bool isOverride)
{
if (IsActivated)
return;
- ModuleActivated();
+ ModuleActivated(isOverride);
IsActivated = true;
}
- internal virtual void Deactivate()
+ internal virtual void Deactivate(bool isOverride)
{
if (!IsActivated)
return;
IsActivated = false;
- ModuleDeactivated();
+ ModuleDeactivated(isOverride);
}
internal void ApplyToEntity()
diff --git a/src/Artemis.Core/Plugins/Modules/ProfileModule.cs b/src/Artemis.Core/Plugins/Modules/ProfileModule.cs
index 894757b42..ad3b7c179 100644
--- a/src/Artemis.Core/Plugins/Modules/ProfileModule.cs
+++ b/src/Artemis.Core/Plugins/Modules/ProfileModule.cs
@@ -193,9 +193,9 @@ namespace Artemis.Core.Plugins.Modules
///
public bool AnimatingProfileChange { get; private set; }
- internal override void Deactivate()
+ internal override void Deactivate(bool isOverride)
{
- base.Deactivate();
+ base.Deactivate(isOverride);
var profile = ActiveProfile;
ActiveProfile = null;
diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs
index c4a223ec8..e6201f936 100644
--- a/src/Artemis.Core/Services/CoreService.cs
+++ b/src/Artemis.Core/Services/CoreService.cs
@@ -175,8 +175,8 @@ namespace Artemis.Core.Services
lock (_modules)
{
modules = _modules.Where(m => m.IsActivated || m.InternalExpandsMainDataModel)
- .OrderByDescending(m => m.PriorityCategory)
- .ThenByDescending(m => m.Priority)
+ .OrderBy(m => m.PriorityCategory)
+ .ThenBy(m => m.Priority)
.ToList();
}
diff --git a/src/Artemis.Core/Services/Interfaces/IModuleService.cs b/src/Artemis.Core/Services/Interfaces/IModuleService.cs
new file mode 100644
index 000000000..509c5048a
--- /dev/null
+++ b/src/Artemis.Core/Services/Interfaces/IModuleService.cs
@@ -0,0 +1,41 @@
+using System.Threading.Tasks;
+using Artemis.Core.Plugins.Modules;
+
+namespace Artemis.Core.Services.Interfaces
+{
+ ///
+ /// A service providing module activation functionality
+ ///
+ public interface IModuleService : IArtemisService
+ {
+ ///
+ /// Gets whether an override is currently being applied
+ ///
+ bool ApplyingOverride { get; }
+
+ ///
+ /// Gets the current active module override. If set, all other modules are deactivated and only the
+ /// is active.
+ ///
+ Module ActiveModuleOverride { get; }
+
+ ///
+ /// Changes the current and deactivates all other modules
+ ///
+ ///
+ Task SetActiveModuleOverride(Module overrideModule);
+
+ ///
+ /// Evaluates every enabled module's activation requirements and activates/deactivates modules accordingly
+ ///
+ Task UpdateModuleActivation();
+
+ ///
+ /// Updates the priority and priority category of the given module
+ ///
+ /// The module to update
+ /// The new priority category of the module
+ /// The new priority of the module
+ void UpdateModulePriority(Module module, ModulePriorityCategory category, int priority);
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Interfaces/IPluginService.cs b/src/Artemis.Core/Services/Interfaces/IPluginService.cs
index f806b5d37..76af14982 100644
--- a/src/Artemis.Core/Services/Interfaces/IPluginService.cs
+++ b/src/Artemis.Core/Services/Interfaces/IPluginService.cs
@@ -7,6 +7,9 @@ using RGB.NET.Core;
namespace Artemis.Core.Services.Interfaces
{
+ ///
+ /// A service providing plugin management
+ ///
public interface IPluginService : IArtemisService, IDisposable
{
///
diff --git a/src/Artemis.Core/Services/ModuleService.cs b/src/Artemis.Core/Services/ModuleService.cs
index e037fbf5d..f3f5eef53 100644
--- a/src/Artemis.Core/Services/ModuleService.cs
+++ b/src/Artemis.Core/Services/ModuleService.cs
@@ -1,5 +1,9 @@
-using System.Diagnostics;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
using System.Timers;
using Artemis.Core.Events;
using Artemis.Core.Plugins.Modules;
@@ -7,6 +11,7 @@ using Artemis.Core.Services.Interfaces;
using Artemis.Core.Services.Storage.Interfaces;
using Artemis.Storage.Repositories.Interfaces;
using Serilog;
+using Timer = System.Timers.Timer;
namespace Artemis.Core.Services
{
@@ -26,58 +31,85 @@ namespace Artemis.Core.Services
_pluginService.PluginEnabled += PluginServiceOnPluginEnabled;
var activationUpdateTimer = new Timer(2000);
- activationUpdateTimer.Elapsed += ActivationUpdateTimerOnElapsed;
activationUpdateTimer.Start();
+ activationUpdateTimer.Elapsed += ActivationUpdateTimerOnElapsed;
+
PopulatePriorities();
}
- private void ActivationUpdateTimerOnElapsed(object sender, ElapsedEventArgs e)
+ public bool ApplyingOverride { get; private set; }
+ public Module ActiveModuleOverride { get; private set; }
+
+ public async Task SetActiveModuleOverride(Module overrideModule)
{
- UpdateModuleActivation();
+ if (ActiveModuleOverride == overrideModule)
+ return;
+
+ try
+ {
+ // Not the cleanest way but locks don't work async and I cba with a mutex
+ while (ApplyingOverride)
+ await Task.Delay(50);
+
+ ApplyingOverride = true;
+ ActiveModuleOverride = overrideModule;
+
+ // If set to null, resume regular activation
+ if (ActiveModuleOverride == null)
+ {
+ await UpdateModuleActivation();
+ _logger.Information("Cleared active module override");
+ return;
+ }
+
+ // If a module was provided, activate it and deactivate everything else
+ var modules = _pluginService.GetPluginsOfType().ToList();
+ var deactivationTasks = new List();
+ foreach (var module in modules)
+ {
+ if (module != ActiveModuleOverride)
+ deactivationTasks.Add(DeactivateModule(module, true));
+ }
+
+ await Task.WhenAll(deactivationTasks);
+
+ if (!ActiveModuleOverride.IsActivated)
+ await ActivateModule(ActiveModuleOverride, true);
+
+ _logger.Information($"Set active module override to {ActiveModuleOverride.DisplayName}");
+ }
+ finally
+ {
+ ApplyingOverride = false;
+ }
}
- public void UpdateModuleActivation()
+ public async Task UpdateModuleActivation()
{
+ if (ActiveModuleOverride != null)
+ return;
+
var stopwatch = new Stopwatch();
stopwatch.Start();
var modules = _pluginService.GetPluginsOfType().ToList();
+ var tasks = new List();
foreach (var module in modules)
{
var shouldBeActivated = module.EvaluateActivationRequirements();
if (shouldBeActivated && !module.IsActivated)
- {
- module.Activate();
- // If this is a profile module, activate the last active profile after module activation
- if (module is ProfileModule profileModule)
- _profileService.ActivateLastProfile(profileModule);
- }
+ tasks.Add(ActivateModule(module, false));
else if (!shouldBeActivated && module.IsActivated)
- module.Deactivate();
+ tasks.Add(DeactivateModule(module, false));
}
+ await Task.WhenAll(tasks);
+
stopwatch.Stop();
if (stopwatch.ElapsedMilliseconds > 100)
_logger.Warning("Activation requirements evaluation took too long: {moduleCount} module(s) in {elapsed}", modules.Count, stopwatch.Elapsed);
}
- public void PopulatePriorities()
- {
- var modules = _pluginService.GetPluginsOfType().ToList();
- var moduleEntities = _moduleRepository.GetAll();
-
- foreach (var module in modules)
- {
- var entity = moduleEntities.FirstOrDefault(e => e.PluginGuid == module.PluginInfo.Guid);
- if (entity != null)
- {
- module.Entity = entity;
- module.PriorityCategory = (ModulePriorityCategory) entity.PriorityCategory;
- module.Priority = entity.Priority;
- }
- }
- }
-
public void UpdateModulePriority(Module module, ModulePriorityCategory category, int priority)
{
var modules = _pluginService.GetPluginsOfType().Where(m => m.PriorityCategory == category).OrderBy(m => m.Priority).ToList();
@@ -105,6 +137,46 @@ namespace Artemis.Core.Services
}
}
+ private async void ActivationUpdateTimerOnElapsed(object sender, ElapsedEventArgs e)
+ {
+ await UpdateModuleActivation();
+ }
+
+ private async Task ActivateModule(Module module, bool isOverride)
+ {
+ module.Activate(isOverride);
+
+ // If this is a profile module, activate the last active profile after module activation
+ if (module is ProfileModule profileModule)
+ await _profileService.ActivateLastProfileAnimated(profileModule);
+ }
+
+ private async Task DeactivateModule(Module module, bool isOverride)
+ {
+ // If this is a profile module, activate the last active profile after module activation
+ if (module.IsActivated && module is ProfileModule profileModule)
+ await profileModule.ChangeActiveProfileAnimated(null, null);
+
+ module.Deactivate(isOverride);
+ }
+
+ private void PopulatePriorities()
+ {
+ var modules = _pluginService.GetPluginsOfType().ToList();
+ var moduleEntities = _moduleRepository.GetAll();
+
+ foreach (var module in modules)
+ {
+ var entity = moduleEntities.FirstOrDefault(e => e.PluginGuid == module.PluginInfo.Guid);
+ if (entity != null)
+ {
+ module.Entity = entity;
+ module.PriorityCategory = (ModulePriorityCategory) entity.PriorityCategory;
+ module.Priority = entity.Priority;
+ }
+ }
+ }
+
private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e)
{
if (e.PluginInfo.Instance is Module module)
@@ -124,8 +196,4 @@ namespace Artemis.Core.Services
UpdateModulePriority(module, module.DefaultPriorityCategory, 1);
}
}
-
- public interface IModuleService : IArtemisService
- {
- }
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs b/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs
index 5fea023cb..00e0ddfed 100644
--- a/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs
+++ b/src/Artemis.Core/Services/Storage/Interfaces/IProfileService.cs
@@ -51,6 +51,14 @@ namespace Artemis.Core.Services.Storage.Interfaces
///
void ActivateLastProfile(ProfileModule profileModule);
+ ///
+ /// Asynchronously activates the last profile of the given profile module using a fade animation
+ ///
+ ///
+ ///
+
+ Task ActivateLastProfileAnimated(ProfileModule profileModule);
+
///
/// Activates the profile described in the given with the currently active surface
///
diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs
index 964eb9266..88d6c5a12 100644
--- a/src/Artemis.Core/Services/Storage/ProfileService.cs
+++ b/src/Artemis.Core/Services/Storage/ProfileService.cs
@@ -64,6 +64,13 @@ namespace Artemis.Core.Services.Storage
ActivateProfile(activeProfile);
}
+ public async Task ActivateLastProfileAnimated(ProfileModule profileModule)
+ {
+ var activeProfile = GetLastActiveProfile(profileModule);
+ if (activeProfile != null)
+ await ActivateProfileAnimated(activeProfile);
+ }
+
public Profile ActivateProfile(ProfileDescriptor profileDescriptor)
{
if (profileDescriptor.ProfileModule.ActiveProfile?.EntityId == profileDescriptor.Id)
@@ -94,12 +101,25 @@ namespace Artemis.Core.Services.Storage
var profile = new Profile(profileDescriptor.ProfileModule, profileEntity);
InstantiateProfile(profile);
+ void ActivatingProfileSurfaceUpdate(object sender, SurfaceConfigurationEventArgs e) => profile.PopulateLeds(e.Surface);
+ void ActivatingProfilePluginToggle(object sender, PluginEventArgs e) => InstantiateProfile(profile);
+
+ // This could happen during activation so subscribe to it
+ _pluginService.PluginEnabled += ActivatingProfilePluginToggle;
+ _pluginService.PluginDisabled += ActivatingProfilePluginToggle;
+ _surfaceService.SurfaceConfigurationUpdated += ActivatingProfileSurfaceUpdate;
+
await profileDescriptor.ProfileModule.ChangeActiveProfileAnimated(profile, _surfaceService.ActiveSurface);
SaveActiveProfile(profileDescriptor.ProfileModule);
+ _pluginService.PluginEnabled -= ActivatingProfilePluginToggle;
+ _pluginService.PluginDisabled -= ActivatingProfilePluginToggle;
+ _surfaceService.SurfaceConfigurationUpdated -= ActivatingProfileSurfaceUpdate;
+
return profile;
}
+
public void ClearActiveProfile(ProfileModule module)
{
module.ChangeActiveProfile(null, _surfaceService.ActiveSurface);
@@ -234,6 +254,9 @@ namespace Artemis.Core.Services.Storage
private void SaveActiveProfile(ProfileModule module)
{
+ if (module.ActiveProfile == null)
+ return;
+
var profileEntities = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
foreach (var profileEntity in profileEntities)
{
diff --git a/src/Artemis.Core/Utilities/IntroAnimation.cs b/src/Artemis.Core/Utilities/IntroAnimation.cs
index 06a6ba79c..02a5c59a6 100644
--- a/src/Artemis.Core/Utilities/IntroAnimation.cs
+++ b/src/Artemis.Core/Utilities/IntroAnimation.cs
@@ -79,12 +79,12 @@ namespace Artemis.Core.Utilities
throw new NotImplementedException();
}
- public override void ModuleActivated()
+ public override void ModuleActivated(bool isOverride)
{
throw new NotImplementedException();
}
- public override void ModuleDeactivated()
+ public override void ModuleDeactivated(bool isOverride)
{
throw new NotImplementedException();
}
diff --git a/src/Artemis.Plugins.Modules.Overlay/Artemis - Backup.Plugins.Modules.Overlay.csproj b/src/Artemis.Plugins.Modules.Overlay/Artemis - Backup.Plugins.Modules.Overlay.csproj
new file mode 100644
index 000000000..358044031
--- /dev/null
+++ b/src/Artemis.Plugins.Modules.Overlay/Artemis - Backup.Plugins.Modules.Overlay.csproj
@@ -0,0 +1,46 @@
+
+
+ netcoreapp3.1
+
+ Artemis.Plugins.Modules.Overlay
+ Artemis.Plugins.Modules.Overlay
+ x64
+
+
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Artemis.Plugins.Modules.Overlay/Artemis.Plugins.Modules.Overlay.csproj b/src/Artemis.Plugins.Modules.Overlay/Artemis.Plugins.Modules.Overlay.csproj
new file mode 100644
index 000000000..2b5876ee1
--- /dev/null
+++ b/src/Artemis.Plugins.Modules.Overlay/Artemis.Plugins.Modules.Overlay.csproj
@@ -0,0 +1,35 @@
+
+
+ netcoreapp3.1
+
+ Artemis.Plugins.Modules.Overlay
+ Artemis.Plugins.Modules.Overlay
+ x64
+
+
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Artemis.Plugins.Modules.Overlay/OverlayModule.cs b/src/Artemis.Plugins.Modules.Overlay/OverlayModule.cs
new file mode 100644
index 000000000..d079c1626
--- /dev/null
+++ b/src/Artemis.Plugins.Modules.Overlay/OverlayModule.cs
@@ -0,0 +1,35 @@
+using Artemis.Core.Plugins.Modules;
+using Artemis.Core.Plugins.Modules.ActivationRequirements;
+
+namespace Artemis.Plugins.Modules.Overlay
+{
+ // The core of your module. Hover over the method names to see a description.
+ public class OverlayModule : ProfileModule
+ {
+ // This is the beginning of your plugin life cycle. Use this instead of a constructor.
+ public override void EnablePlugin()
+ {
+ DisplayName = "Overlay";
+ DisplayIcon = "ArrangeBringToFront";
+ DefaultPriorityCategory = ModulePriorityCategory.Overlay;
+
+ ActivationRequirements.Add(new ProcessActivationRequirement("taskmgr"));
+ }
+
+ // This is the end of your plugin life cycle.
+ public override void DisablePlugin()
+ {
+ // Make sure to clean up resources where needed (dispose IDisposables etc.)
+ }
+
+ public override void ModuleActivated(bool isOverride)
+ {
+ // When this gets called your activation requirements have been met and the module will start displaying
+ }
+
+ public override void ModuleDeactivated(bool isOverride)
+ {
+ // When this gets called your activation requirements are no longer met and your module will stop displaying
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Plugins.Modules.Overlay/plugin.json b/src/Artemis.Plugins.Modules.Overlay/plugin.json
new file mode 100644
index 000000000..bbb0b9206
--- /dev/null
+++ b/src/Artemis.Plugins.Modules.Overlay/plugin.json
@@ -0,0 +1,7 @@
+{
+ "Guid": "29e3ff97-83a5-44fc-a2dc-04f446b54146",
+ "Name": "Overlay module",
+ "Description": "A general profile-enabled overlay module for every-day use",
+ "Version": "1.0.0.0",
+ "Main": "Artemis.Plugins.Modules.Overlay.dll"
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Module/ModuleRootViewModel.cs b/src/Artemis.UI/Screens/Module/ModuleRootViewModel.cs
index 0ac585fe6..7851a2982 100644
--- a/src/Artemis.UI/Screens/Module/ModuleRootViewModel.cs
+++ b/src/Artemis.UI/Screens/Module/ModuleRootViewModel.cs
@@ -2,6 +2,8 @@
using System.Linq;
using System.Threading.Tasks;
using Artemis.Core.Plugins.Modules;
+using Artemis.Core.Services;
+using Artemis.Core.Services.Interfaces;
using Artemis.UI.Ninject.Factories;
using Ninject;
using Ninject.Parameters;
@@ -11,22 +13,41 @@ namespace Artemis.UI.Screens.Module
{
public class ModuleRootViewModel : Conductor.Collection.OneActive
{
+ private readonly IModuleService _moduleService;
private readonly IProfileEditorVmFactory _profileEditorVmFactory;
private readonly IKernel _kernel;
- public ModuleRootViewModel(Core.Plugins.Modules.Module module, IProfileEditorVmFactory profileEditorVmFactory, IKernel kernel)
+ public ModuleRootViewModel(Core.Plugins.Modules.Module module, IModuleService moduleService, IProfileEditorVmFactory profileEditorVmFactory, IKernel kernel)
{
DisplayName = module?.DisplayName;
Module = module;
+ _moduleService = moduleService;
_profileEditorVmFactory = profileEditorVmFactory;
_kernel = kernel;
-
- Task.Run(AddTabsAsync);
}
public Core.Plugins.Modules.Module Module { get; }
+ protected override void OnActivate()
+ {
+ Task.Run(async () =>
+ {
+ await _moduleService.SetActiveModuleOverride(Module);
+ await AddTabsAsync();
+ });
+ base.OnActivate();
+ }
+
+ protected override void OnDeactivate()
+ {
+ Task.Run(async () =>
+ {
+ await _moduleService.SetActiveModuleOverride(null);
+ });
+ base.OnDeactivate();
+ }
+
private async Task AddTabsAsync()
{
// Give the screen a moment to active without freezing the UI thread
diff --git a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs
index a4d803ee7..c304aba1e 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs
@@ -228,14 +228,14 @@ namespace Artemis.UI.Screens.ProfileEditor
_snackbarMessageQueue.Enqueue("Redid profile update", "UNDO", Undo);
}
- protected override void OnInitialActivate()
+ protected override void OnActivate()
{
LoadWorkspaceSettings();
Module.IsProfileUpdatingDisabled = true;
Module.ActiveProfileChanged += ModuleOnActiveProfileChanged;
Execute.PostToUIThread(LoadProfiles);
- base.OnInitialActivate();
+ base.OnActivate();
}
protected override void OnClose()
@@ -243,6 +243,8 @@ namespace Artemis.UI.Screens.ProfileEditor
SaveWorkspaceSettings();
Module.IsProfileUpdatingDisabled = false;
Module.ActiveProfileChanged -= ModuleOnActiveProfileChanged;
+
+ _profileEditorService.ChangeSelectedProfile(null);
base.OnClose();
}
diff --git a/src/Artemis.UI/Screens/RootViewModel.cs b/src/Artemis.UI/Screens/RootViewModel.cs
index 830237a8a..c6c29a490 100644
--- a/src/Artemis.UI/Screens/RootViewModel.cs
+++ b/src/Artemis.UI/Screens/RootViewModel.cs
@@ -137,7 +137,7 @@ namespace Artemis.UI.Screens
private void SidebarViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
- if (e.PropertyName == nameof(SidebarViewModel.SelectedItem))
+ if (e.PropertyName == nameof(SidebarViewModel.SelectedItem) && ActiveItem != SidebarViewModel.SelectedItem)
{
SidebarViewModel.IsSidebarOpen = false;
ActiveItemReady = false;
diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs
index 8bc5fff76..87d6e5779 100644
--- a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs
+++ b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;
+using System.Windows.Media.Imaging;
using Artemis.Core.Events;
using Artemis.Core.Services.Interfaces;
using Artemis.UI.Events;
@@ -22,15 +24,15 @@ namespace Artemis.UI.Screens.Sidebar
{
public class SidebarViewModel : PropertyChangedBase, IHandle, IDisposable
{
+ private readonly Timer _activeModulesUpdateTimer;
private readonly IKernel _kernel;
private readonly IModuleVmFactory _moduleVmFactory;
private readonly IPluginService _pluginService;
+ private string _activeModules;
+ private bool _isSidebarOpen;
+ private IScreen _selectedItem;
private BindableCollection _sidebarItems;
private Dictionary _sidebarModules;
- private IScreen _selectedItem;
- private bool _isSidebarOpen;
- private readonly Timer _activeModulesUpdateTimer;
- private string _activeModules;
public SidebarViewModel(IKernel kernel, IEventAggregator eventAggregator, IModuleVmFactory moduleVmFactory, IPluginService pluginService)
{
@@ -52,15 +54,6 @@ namespace Artemis.UI.Screens.Sidebar
eventAggregator.Subscribe(this);
}
- private void ActiveModulesUpdateTimerOnElapsed(object sender, EventArgs e)
- {
- if (!IsSidebarOpen)
- return;
-
- var activeModules = SidebarModules.Count(m => m.Value.IsActivated);
- ActiveModules = activeModules == 1 ? "1 active module" : $"{activeModules} active modules";
- }
-
public BindableCollection SidebarItems
{
get => _sidebarItems;
@@ -96,6 +89,18 @@ namespace Artemis.UI.Screens.Sidebar
}
}
+ public void Dispose()
+ {
+ SelectedItem?.Deactivate();
+ SelectedItem = null;
+
+ _pluginService.PluginEnabled -= PluginServiceOnPluginEnabled;
+ _pluginService.PluginDisabled -= PluginServiceOnPluginDisabled;
+
+ _activeModulesUpdateTimer.Stop();
+ _activeModulesUpdateTimer.Elapsed -= ActiveModulesUpdateTimerOnElapsed;
+ }
+
public void SetupSidebar()
{
SidebarItems.Clear();
@@ -120,7 +125,7 @@ namespace Artemis.UI.Screens.Sidebar
}
// ReSharper disable once UnusedMember.Global - Called by view
- public async Task SelectItem(WillSelectNavigationItemEventArgs args)
+ public void SelectItem(WillSelectNavigationItemEventArgs args)
{
if (args.NavigationItemToSelect == null)
{
@@ -128,7 +133,7 @@ namespace Artemis.UI.Screens.Sidebar
return;
}
- await SelectSidebarItem(args.NavigationItemToSelect);
+ SelectSidebarItem(args.NavigationItemToSelect);
}
public void AddModule(Core.Plugins.Modules.Module module)
@@ -137,11 +142,19 @@ namespace Artemis.UI.Screens.Sidebar
if (SidebarModules.Any(io => io.Value == module))
return;
- // Icon is provided as string to avoid having to reference MaterialDesignThemes
- var parsedIcon = Enum.TryParse(module.DisplayIcon, true, out var iconEnum);
- if (parsedIcon == false)
- iconEnum = PackIconKind.QuestionMarkCircle;
- var sidebarItem = new FirstLevelNavigationItem {Icon = iconEnum, Label = module.DisplayName};
+ object icon;
+ if (module.DisplayIconPath != null && File.Exists(Path.Combine(module.PluginInfo.Directory.FullName, module.DisplayIconPath)))
+ icon = new BitmapImage(new Uri(Path.Combine(module.PluginInfo.Directory.FullName, module.DisplayIconPath)));
+ else
+ {
+ // Icon is provided as string to avoid having to reference MaterialDesignThemes
+ var parsedIcon = Enum.TryParse(module.DisplayIcon, true, out var iconEnum);
+ if (parsedIcon == false)
+ iconEnum = PackIconKind.QuestionMarkCircle;
+ icon = iconEnum;
+ }
+
+ var sidebarItem = new FirstLevelNavigationItem {Icon = icon, Label = module.DisplayName};
SidebarItems.Add(sidebarItem);
SidebarModules.Add(sidebarItem, module);
}
@@ -157,54 +170,48 @@ namespace Artemis.UI.Screens.Sidebar
SidebarModules.Remove(existing.Key);
}
- private async Task SelectSidebarItem(INavigationItem sidebarItem)
+ private void ActiveModulesUpdateTimerOnElapsed(object sender, EventArgs e)
+ {
+ if (!IsSidebarOpen)
+ return;
+
+ var activeModules = SidebarModules.Count(m => m.Value.IsActivated);
+ ActiveModules = activeModules == 1 ? "1 active module" : $"{activeModules} active modules";
+ }
+
+ private void SelectSidebarItem(INavigationItem sidebarItem)
{
// A module was selected if the dictionary contains the selected item
if (SidebarModules.ContainsKey(sidebarItem))
- await ActivateModule(sidebarItem);
+ ActivateModule(sidebarItem);
else if (sidebarItem is FirstLevelNavigationItem navigationItem)
- await ActivateViewModel(navigationItem.Label);
- else if (await CloseCurrentItem())
+ ActivateViewModel(navigationItem.Label);
+ else
SelectedItem = null;
}
- private async Task CloseCurrentItem()
- {
- if (SelectedItem == null)
- return true;
-
- var canClose = await SelectedItem.CanCloseAsync();
- if (!canClose)
- return false;
-
- SelectedItem.Close();
- return true;
- }
-
- private async Task ActivateViewModel(string label)
+ private void ActivateViewModel(string label)
{
if (label == "Home")
- await ActivateViewModel();
+ ActivateViewModel();
else if (label == "News")
- await ActivateViewModel();
+ ActivateViewModel();
else if (label == "Workshop")
- await ActivateViewModel();
+ ActivateViewModel();
else if (label == "Surface Editor")
- await ActivateViewModel();
+ ActivateViewModel();
else if (label == "Settings")
- await ActivateViewModel();
+ ActivateViewModel();
}
- private async Task ActivateViewModel()
+ private void ActivateViewModel()
{
- if (await CloseCurrentItem())
- SelectedItem = (IScreen) _kernel.Get();
+ SelectedItem = (IScreen) _kernel.Get();
}
- private async Task ActivateModule(INavigationItem sidebarItem)
+ private void ActivateModule(INavigationItem sidebarItem)
{
- if (await CloseCurrentItem())
- SelectedItem = SidebarModules.ContainsKey(sidebarItem) ? _moduleVmFactory.Create(SidebarModules[sidebarItem]) : null;
+ SelectedItem = SidebarModules.ContainsKey(sidebarItem) ? _moduleVmFactory.Create(SidebarModules[sidebarItem]) : null;
}
#region Event handlers
@@ -223,21 +230,9 @@ namespace Artemis.UI.Screens.Sidebar
public void Handle(RequestSelectSidebarItemEvent message)
{
- Execute.OnUIThread(async () => await ActivateViewModel(message.Label));
+ ActivateViewModel(message.Label);
}
#endregion
-
- public void Dispose()
- {
- var closeTask = CloseCurrentItem();
- closeTask.Wait();
-
- _pluginService.PluginEnabled -= PluginServiceOnPluginEnabled;
- _pluginService.PluginDisabled -= PluginServiceOnPluginDisabled;
-
- _activeModulesUpdateTimer.Stop();
- _activeModulesUpdateTimer.Elapsed -= ActiveModulesUpdateTimerOnElapsed;
- }
}
}
\ No newline at end of file
diff --git a/src/Artemis.sln b/src/Artemis.sln
index 1af8e3f62..889050ad5 100644
--- a/src/Artemis.sln
+++ b/src/Artemis.sln
@@ -10,6 +10,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.UI", "Artemis.UI\Ar
{3D83760B-0A36-4C8F-978D-7949C3FC862B} = {3D83760B-0A36-4C8F-978D-7949C3FC862B}
{8DC7960F-6DDF-4007-A155-17E124F39374} = {8DC7960F-6DDF-4007-A155-17E124F39374}
{DCF7C321-95DC-4507-BB61-A7C5356E58EC} = {DCF7C321-95DC-4507-BB61-A7C5356E58EC}
+ {00318027-7FDB-4C86-AB86-9005A481E330} = {00318027-7FDB-4C86-AB86-9005A481E330}
{E592F239-FAA0-4840-9C85-46E5867D06D5} = {E592F239-FAA0-4840-9C85-46E5867D06D5}
{36C10640-A31F-4DEE-9F0E-9B9E3F12753D} = {36C10640-A31F-4DEE-9F0E-9B9E3F12753D}
{62214042-667E-4B29-B64E-1A68CE6FE209} = {62214042-667E-4B29-B64E-1A68CE6FE209}
@@ -76,6 +77,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.Plugins.LayerEffect
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.Plugins.Devices.Debug", "Plugins\Artemis.Plugins.Devices.Debug\Artemis.Plugins.Devices.Debug.csproj", "{3D83760B-0A36-4C8F-978D-7949C3FC862B}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Artemis.Plugins.Modules.Overlay", "Artemis.Plugins.Modules.Overlay\Artemis.Plugins.Modules.Overlay.csproj", "{00318027-7FDB-4C86-AB86-9005A481E330}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -260,6 +263,12 @@ Global
{3D83760B-0A36-4C8F-978D-7949C3FC862B}.Release|Any CPU.Build.0 = Release|Any CPU
{3D83760B-0A36-4C8F-978D-7949C3FC862B}.Release|x64.ActiveCfg = Release|Any CPU
{3D83760B-0A36-4C8F-978D-7949C3FC862B}.Release|x64.Build.0 = Release|Any CPU
+ {00318027-7FDB-4C86-AB86-9005A481E330}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {00318027-7FDB-4C86-AB86-9005A481E330}.Debug|x64.ActiveCfg = Debug|x64
+ {00318027-7FDB-4C86-AB86-9005A481E330}.Debug|x64.Build.0 = Debug|x64
+ {00318027-7FDB-4C86-AB86-9005A481E330}.Release|Any CPU.ActiveCfg = Release|x64
+ {00318027-7FDB-4C86-AB86-9005A481E330}.Release|x64.ActiveCfg = Release|x64
+ {00318027-7FDB-4C86-AB86-9005A481E330}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -287,6 +296,7 @@ Global
{2C1477DC-7A5C-4B65-85DB-1F16A18FB2EC} = {E830A02B-A7E5-4A6B-943F-76B0A542630C}
{62214042-667E-4B29-B64E-1A68CE6FE209} = {2C1477DC-7A5C-4B65-85DB-1F16A18FB2EC}
{3D83760B-0A36-4C8F-978D-7949C3FC862B} = {88792A7E-F037-4280-81D3-B131508EF1D8}
+ {00318027-7FDB-4C86-AB86-9005A481E330} = {B258A061-FA19-4835-8DC4-E9C3AE3664A0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C203080A-4473-4CC2-844B-F552EA43D66A}
diff --git a/src/Plugins/Artemis.Plugins.Devices.Debug/DebugDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.Debug/DebugDeviceProvider.cs
index 8fb860c76..bc0ea9b4a 100644
--- a/src/Plugins/Artemis.Plugins.Devices.Debug/DebugDeviceProvider.cs
+++ b/src/Plugins/Artemis.Plugins.Devices.Debug/DebugDeviceProvider.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.IO;
using Artemis.Core.Plugins;
using Artemis.Core.Plugins.DeviceProviders;
@@ -8,6 +9,7 @@ using Artemis.Plugins.Devices.Debug.Settings;
using Artemis.Plugins.Devices.Debug.ViewModels;
using RGB.NET.Core;
using RGB.NET.Devices.Debug;
+using Serilog;
namespace Artemis.Plugins.Devices.Debug
{
@@ -16,10 +18,12 @@ namespace Artemis.Plugins.Devices.Debug
{
private readonly IRgbService _rgbService;
private readonly PluginSettings _settings;
+ private readonly ILogger _logger;
- public DebugDeviceProvider(IRgbService rgbService, PluginSettings settings) : base(RGB.NET.Devices.Debug.DebugDeviceProvider.Instance)
+ public DebugDeviceProvider(IRgbService rgbService, PluginSettings settings, ILogger logger) : base(RGB.NET.Devices.Debug.DebugDeviceProvider.Instance)
{
_settings = settings;
+ _logger = logger;
_rgbService = rgbService;
}
@@ -35,7 +39,14 @@ namespace Artemis.Plugins.Devices.Debug
foreach (var deviceDefinition in definitions.Value)
RGB.NET.Devices.Debug.DebugDeviceProvider.Instance.AddFakeDeviceDefinition(deviceDefinition.Layout, deviceDefinition.ImageLayout);
- _rgbService.AddDeviceProvider(RgbDeviceProvider);
+ try
+ {
+ _rgbService.AddDeviceProvider(RgbDeviceProvider);
+ }
+ catch (Exception e)
+ {
+ _logger.Warning(e, "Debug device provided failed to initialize, check paths");
+ }
}
public override void DisablePlugin()
diff --git a/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs b/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs
index 60cb9b2dd..d8759b149 100644
--- a/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs
+++ b/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs
@@ -28,11 +28,11 @@ namespace Artemis.Plugins.Modules.General
{
}
- public override void ModuleActivated()
+ public override void ModuleActivated(bool isOverride)
{
}
- public override void ModuleDeactivated()
+ public override void ModuleDeactivated(bool isOverride)
{
}