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

Modules - Added activation requirements tab

Profile editor - Only override active profile with profile editor tab open
This commit is contained in:
Robert 2020-08-26 19:38:44 +02:00
parent 90383f2e41
commit 8d756128e4
12 changed files with 252 additions and 53 deletions

View File

@ -15,5 +15,10 @@
{
return ActivationMet;
}
public string GetUserFriendlyDescription()
{
return "No description available";
}
}
}

View File

@ -10,5 +10,11 @@
/// </summary>
/// <returns></returns>
bool Evaluate();
/// <summary>
/// Returns a user-friendly description of the activation requirement, should include parameters if applicable
/// </summary>
/// <returns>A user-friendly description of the activation requirement</returns>
string GetUserFriendlyDescription();
}
}

View File

@ -43,5 +43,14 @@ namespace Artemis.Core.Plugins.Modules.ActivationRequirements
? processes.Any(p => string.Equals(Path.GetDirectoryName(p.GetProcessFilename()), Location, StringComparison.CurrentCultureIgnoreCase))
: processes.Any();
}
public string GetUserFriendlyDescription()
{
var description = $"Requirement met when \"{ProcessName}.exe\" is running";
if (Location != null)
description += $" from \"{Location}\"";
return description;
}
}
}

View File

@ -5,7 +5,9 @@ using Artemis.Core.Models.Profile.LayerProperties.Attributes;
using Artemis.Core.Models.Surface;
using Artemis.Core.Plugins;
using Artemis.Core.Plugins.Modules;
using Artemis.Core.Plugins.Modules.ActivationRequirements;
using Artemis.UI.Screens.Module;
using Artemis.UI.Screens.Module.Tabs;
using Artemis.UI.Screens.ProfileEditor;
using Artemis.UI.Screens.ProfileEditor.DisplayConditions;
using Artemis.UI.Screens.ProfileEditor.DisplayConditions.Abstract;
@ -30,7 +32,10 @@ namespace Artemis.UI.Ninject.Factories
public interface IModuleVmFactory : IVmFactory
{
ModuleRootViewModel Create(Module module);
ModuleRootViewModel CreateModuleRootViewModel(Module module);
ProfileEditorViewModel CreateProfileEditorViewModel(ProfileModule module);
ActivationRequirementsViewModel CreateActivationRequirementsViewModel(Module module);
ActivationRequirementViewModel CreateActivationRequirementViewModel(IModuleActivationRequirement activationRequirement);
}
public interface ISettingsVmFactory : IVmFactory
@ -44,11 +49,6 @@ namespace Artemis.UI.Ninject.Factories
DeviceDebugViewModel Create(ArtemisDevice device);
}
public interface IProfileEditorVmFactory : IVmFactory
{
ProfileEditorViewModel Create(ProfileModule module);
}
public interface IFolderVmFactory : IVmFactory
{
FolderViewModel Create(ProfileElement folder);

View File

@ -1,9 +1,6 @@
using System.Collections.Generic;
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;
@ -13,17 +10,15 @@ namespace Artemis.UI.Screens.Module
{
public class ModuleRootViewModel : Conductor<Screen>.Collection.OneActive
{
private readonly IModuleService _moduleService;
private readonly IProfileEditorVmFactory _profileEditorVmFactory;
private readonly IKernel _kernel;
private readonly IModuleVmFactory _moduleVmFactory;
public ModuleRootViewModel(Core.Plugins.Modules.Module module, IModuleService moduleService, IProfileEditorVmFactory profileEditorVmFactory, IKernel kernel)
public ModuleRootViewModel(Core.Plugins.Modules.Module module, IModuleVmFactory moduleVmFactory, IKernel kernel)
{
DisplayName = module?.DisplayName;
Module = module;
_moduleService = moduleService;
_profileEditorVmFactory = profileEditorVmFactory;
_moduleVmFactory = moduleVmFactory;
_kernel = kernel;
}
@ -31,31 +26,18 @@ namespace Artemis.UI.Screens.Module
protected override void OnActivate()
{
Task.Run(async () =>
{
await _moduleService.SetActiveModuleOverride(Module);
await AddTabsAsync();
});
AddTabs();
base.OnActivate();
}
protected override void OnDeactivate()
{
Task.Run(async () =>
{
await _moduleService.SetActiveModuleOverride(null);
});
base.OnDeactivate();
}
private async Task AddTabsAsync()
private void AddTabs()
{
// Create the profile editor and module VMs
if (Module is ProfileModule profileModule)
{
var profileEditor = _profileEditorVmFactory.Create(profileModule);
Items.Add(profileEditor);
}
Items.Add(_moduleVmFactory.CreateProfileEditorViewModel(profileModule));
if (Module.ActivationRequirements.Any())
Items.Add(_moduleVmFactory.CreateActivationRequirementsViewModel(Module));
if (Module.ModuleTabs != null)
{

View File

@ -0,0 +1,44 @@
<UserControl x:Class="Artemis.UI.Screens.Module.Tabs.ActivationRequirementView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.Tabs"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:ActivationRequirementViewModel}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}"
Text="{Binding RequirementName}" />
<TextBlock Style="{StaticResource MaterialDesignTextBlock}"
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
TextWrapping="Wrap"
Text="{Binding RequirementDescription}" />
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleButton Style="{StaticResource MaterialDesignActionToggleButton}"
Focusable="False"
IsHitTestVisible="False"
IsChecked="{Binding RequirementMet}">
<ToggleButton.Content>
<Border Background="#E74C4C" Width="32" Height="32">
<materialDesign:PackIcon Kind="Close" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Border>
</ToggleButton.Content>
<materialDesign:ToggleButtonAssist.OnContent>
<materialDesign:PackIcon Kind="Check" />
</materialDesign:ToggleButtonAssist.OnContent>
</ToggleButton>
</StackPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,64 @@
using System.Timers;
using Artemis.Core.Plugins.Modules.ActivationRequirements;
using Humanizer;
using Stylet;
namespace Artemis.UI.Screens.Module.Tabs
{
public class ActivationRequirementViewModel : Screen
{
private readonly IModuleActivationRequirement _activationRequirement;
private readonly Timer _updateTimer;
private string _requirementDescription;
private bool _requirementMet;
public ActivationRequirementViewModel(IModuleActivationRequirement activationRequirement)
{
_activationRequirement = activationRequirement;
_updateTimer = new Timer(500);
RequirementName = activationRequirement.GetType().Name.Humanize();
RequirementDescription = activationRequirement.GetUserFriendlyDescription();
_updateTimer.Elapsed += UpdateTimerOnElapsed;
}
public string RequirementName { get; }
public string RequirementDescription
{
get => _requirementDescription;
set => SetAndNotify(ref _requirementDescription, value);
}
public bool RequirementMet
{
get => _requirementMet;
set => SetAndNotify(ref _requirementMet, value);
}
protected override void OnActivate()
{
Update();
_updateTimer.Start();
base.OnActivate();
}
protected override void OnDeactivate()
{
_updateTimer.Stop();
base.OnDeactivate();
}
private void UpdateTimerOnElapsed(object sender, ElapsedEventArgs e)
{
Update();
}
private void Update()
{
RequirementDescription = _activationRequirement.GetUserFriendlyDescription();
RequirementMet = _activationRequirement.Evaluate();
}
}
}

View File

@ -0,0 +1,53 @@
<UserControl x:Class="Artemis.UI.Screens.Module.Tabs.ActivationRequirementsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.Tabs"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:ActivationRequirementsViewModel}">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<StackPanel Margin="15" MaxWidth="800">
<!-- General settings -->
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">Activation requirements</TextBlock>
<TextBlock Margin="0 0 0 15" TextWrapping="Wrap" Style="{StaticResource MaterialDesignTextBlock}">
This module has built-in activation requirements and won't activate until <Run Text="{Binding ActivationType}" FontWeight="Medium" Foreground="{StaticResource SecondaryAccentBrush}" />. <LineBreak />
These requirements allow the module creator to decide when the module is activated and you cannot override them.
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}"
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"
TextWrapping="Wrap">
Note: While you have the profile editor open the module is always activated and any other modules are deactivated.
</TextBlock>
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Separator Margin="0 -10">
<Separator.Style>
<Style TargetType="Separator" BasedOn="{StaticResource MaterialDesignSeparator}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Separator.Style>
</Separator>
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" Margin="20" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</materialDesign:Card>
</StackPanel>
</ScrollViewer>
</UserControl>

View File

@ -0,0 +1,36 @@
using System.Linq;
using Artemis.Core.Plugins.Modules;
using Artemis.UI.Ninject.Factories;
using Stylet;
namespace Artemis.UI.Screens.Module.Tabs
{
public class ActivationRequirementsViewModel : Conductor<ActivationRequirementViewModel>.Collection.AllActive
{
private readonly IModuleVmFactory _moduleVmFactory;
public ActivationRequirementsViewModel(Core.Plugins.Modules.Module module, IModuleVmFactory moduleVmFactory)
{
_moduleVmFactory = moduleVmFactory;
DisplayName = "Activation requirements";
Module = module;
ActivationType = Module.ActivationRequirementMode == ActivationRequirementType.All
? "all requirements are met"
: "any requirement is met";
}
public Core.Plugins.Modules.Module Module { get; }
public string ActivationType { get; set; }
protected override void OnActivate()
{
if (!Items.Any())
Items.AddRange(Module.ActivationRequirements.Select(_moduleVmFactory.CreateActivationRequirementViewModel));
}
}
}

View File

@ -7,6 +7,7 @@ using Artemis.Core.Models.Profile;
using Artemis.Core.Plugins.Modules;
using Artemis.Core.Plugins.Settings;
using Artemis.Core.Services;
using Artemis.Core.Services.Interfaces;
using Artemis.Core.Services.Storage.Interfaces;
using Artemis.UI.Screens.ProfileEditor.Dialogs;
using Artemis.UI.Screens.ProfileEditor.DisplayConditions;
@ -24,6 +25,7 @@ namespace Artemis.UI.Screens.ProfileEditor
private readonly IProfileEditorService _profileEditorService;
private readonly IProfileService _profileService;
private readonly ISettingsService _settingsService;
private readonly IModuleService _moduleService;
private readonly ISnackbarMessageQueue _snackbarMessageQueue;
private BindableCollection<ProfileDescriptor> _profiles;
private PluginSetting<GridLength> _sidePanelsWidth;
@ -42,11 +44,13 @@ namespace Artemis.UI.Screens.ProfileEditor
IProfileService profileService,
IDialogService dialogService,
ISettingsService settingsService,
IModuleService moduleService,
ISnackbarMessageQueue snackbarMessageQueue)
{
_profileEditorService = profileEditorService;
_profileService = profileService;
_settingsService = settingsService;
_moduleService = moduleService;
_snackbarMessageQueue = snackbarMessageQueue;
DisplayName = "Profile editor";
@ -233,19 +237,21 @@ namespace Artemis.UI.Screens.ProfileEditor
LoadWorkspaceSettings();
Module.IsProfileUpdatingDisabled = true;
Module.ActiveProfileChanged += ModuleOnActiveProfileChanged;
LoadProfiles();
Execute.PostToUIThread(LoadProfiles);
Task.Run(async () => { await _moduleService.SetActiveModuleOverride(Module); });
base.OnActivate();
}
protected override void OnClose()
protected override void OnDeactivate()
{
SaveWorkspaceSettings();
Module.IsProfileUpdatingDisabled = false;
Module.ActiveProfileChanged -= ModuleOnActiveProfileChanged;
_profileEditorService.ChangeSelectedProfile(null);
base.OnClose();
Task.Run(async () => { await _moduleService.SetActiveModuleOverride(null); });
base.OnDeactivate();
}
private void RemoveProfile(ProfileDescriptor profileDescriptor)
@ -309,19 +315,6 @@ namespace Artemis.UI.Screens.ProfileEditor
// Get all profiles from the database
Profiles.Clear();
Profiles.AddRange(_profileService.GetProfileDescriptors(Module).OrderBy(d => d.Name));
// Populate the selected profile
var lastActiveProfile = Profiles.FirstOrDefault(p => p.IsLastActiveProfile) ?? Profiles.FirstOrDefault();
if (lastActiveProfile != null)
{
SelectedProfile = lastActiveProfile;
return;
}
// Create a default profile if there is none
var defaultProfile = _profileService.CreateProfileDescriptor(Module, "Default");
Profiles.Add(defaultProfile);
SelectedProfile = defaultProfile;
}
}
}

View File

@ -211,7 +211,7 @@ namespace Artemis.UI.Screens.Sidebar
private void ActivateModule(INavigationItem sidebarItem)
{
SelectedItem = SidebarModules.ContainsKey(sidebarItem) ? _moduleVmFactory.Create(SidebarModules[sidebarItem]) : null;
SelectedItem = SidebarModules.ContainsKey(sidebarItem) ? _moduleVmFactory.CreateModuleRootViewModel(SidebarModules[sidebarItem]) : null;
}
#region Event handlers

View File

@ -1,4 +1,6 @@
using Artemis.Core.Plugins.Modules;
using System;
using System.IO;
using Artemis.Core.Plugins.Modules;
using Artemis.Core.Plugins.Modules.ActivationRequirements;
namespace Artemis.Plugins.Modules.Overlay
@ -14,6 +16,11 @@ namespace Artemis.Plugins.Modules.Overlay
DefaultPriorityCategory = ModulePriorityCategory.Overlay;
ActivationRequirements.Add(new ProcessActivationRequirement("taskmgr"));
ActivationRequirements.Add(new ProcessActivationRequirement("calc"));
ActivationRequirements.Add(new ProcessActivationRequirement("mspaint")
{
Location = Path.Combine(Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.System)).FullName, "System32")
});
}
// This is the end of your plugin life cycle.