mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Plugin info - Implemented property changed
Plugins - Improved enable failure detection Plugins UI - Show an indicator on plugins that failed to enable Plugins UI - Show a progress indicator on plugins that are enabling UI - Added reusable Snackbar (not the Dutch kind with kroketten)
This commit is contained in:
parent
28bcfcc95a
commit
a47eedf1c2
@ -52,13 +52,30 @@ namespace Artemis.Core.Plugins.Abstract
|
|||||||
if (enable && !Enabled)
|
if (enable && !Enabled)
|
||||||
{
|
{
|
||||||
Enabled = true;
|
Enabled = true;
|
||||||
|
PluginInfo.Enabled = true;
|
||||||
|
|
||||||
|
// If enable failed, put it back in a disabled state
|
||||||
|
try
|
||||||
|
{
|
||||||
EnablePlugin();
|
EnablePlugin();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Enabled = false;
|
||||||
|
PluginInfo.Enabled = false;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
OnPluginEnabled();
|
OnPluginEnabled();
|
||||||
}
|
}
|
||||||
else if (!enable && Enabled)
|
else if (!enable && Enabled)
|
||||||
{
|
{
|
||||||
Enabled = false;
|
Enabled = false;
|
||||||
|
PluginInfo.Enabled = false;
|
||||||
|
|
||||||
|
// Even if disable failed, still leave it in a disabled state to avoid more issues
|
||||||
DisablePlugin();
|
DisablePlugin();
|
||||||
|
|
||||||
OnPluginDisabled();
|
OnPluginDisabled();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,24 @@ using Artemis.Core.Plugins.Abstract;
|
|||||||
using Artemis.Storage.Entities.Plugins;
|
using Artemis.Storage.Entities.Plugins;
|
||||||
using McMaster.NETCore.Plugins;
|
using McMaster.NETCore.Plugins;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
namespace Artemis.Core.Plugins.Models
|
namespace Artemis.Core.Plugins.Models
|
||||||
{
|
{
|
||||||
public class PluginInfo
|
[JsonObject(MemberSerialization.OptIn)]
|
||||||
|
public class PluginInfo : PropertyChangedBase
|
||||||
{
|
{
|
||||||
|
private Guid _guid;
|
||||||
|
private string _name;
|
||||||
|
private string _description;
|
||||||
|
private string _icon;
|
||||||
|
private Version _version;
|
||||||
|
private string _main;
|
||||||
|
private DirectoryInfo _directory;
|
||||||
|
private Plugin _instance;
|
||||||
|
private bool _enabled;
|
||||||
|
private bool _lastEnableSuccessful;
|
||||||
|
|
||||||
internal PluginInfo()
|
internal PluginInfo()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -18,77 +31,125 @@ namespace Artemis.Core.Plugins.Models
|
|||||||
/// The plugins GUID
|
/// The plugins GUID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty(Required = Required.Always)]
|
[JsonProperty(Required = Required.Always)]
|
||||||
public Guid Guid { get; internal set; }
|
public Guid Guid
|
||||||
|
{
|
||||||
|
get => _guid;
|
||||||
|
internal set => SetAndNotify(ref _guid, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of the plugin
|
/// The name of the plugin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty(Required = Required.Always)]
|
[JsonProperty(Required = Required.Always)]
|
||||||
public string Name { get; internal set; }
|
public string Name
|
||||||
|
{
|
||||||
|
get => _name;
|
||||||
|
internal set => SetAndNotify(ref _name, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A short description of the plugin
|
/// A short description of the plugin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Description { get; set; }
|
[JsonProperty]
|
||||||
|
public string Description
|
||||||
|
{
|
||||||
|
get => _description;
|
||||||
|
set => SetAndNotify(ref _description, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The plugins display icon that's shown in the settings see <see href="https://materialdesignicons.com" /> for
|
/// The plugins display icon that's shown in the settings see <see href="https://materialdesignicons.com" /> for
|
||||||
/// available
|
/// available
|
||||||
/// icons
|
/// icons
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Icon { get; set; }
|
[JsonProperty]
|
||||||
|
public string Icon
|
||||||
|
{
|
||||||
|
get => _icon;
|
||||||
|
set => SetAndNotify(ref _icon, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The version of the plugin
|
/// The version of the plugin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty(Required = Required.Always)]
|
[JsonProperty(Required = Required.Always)]
|
||||||
public Version Version { get; internal set; }
|
public Version Version
|
||||||
|
{
|
||||||
|
get => _version;
|
||||||
|
internal set => SetAndNotify(ref _version, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The main entry DLL, should contain a class implementing Plugin
|
/// The main entry DLL, should contain a class implementing Plugin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty(Required = Required.Always)]
|
[JsonProperty(Required = Required.Always)]
|
||||||
public string Main { get; internal set; }
|
public string Main
|
||||||
|
{
|
||||||
|
get => _main;
|
||||||
|
internal set => SetAndNotify(ref _main, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The plugins root directory
|
/// The plugins root directory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
public DirectoryInfo Directory
|
||||||
public DirectoryInfo Directory { get; internal set; }
|
{
|
||||||
|
get => _directory;
|
||||||
|
internal set => SetAndNotify(ref _directory, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A reference to the type implementing Plugin, available after successful load
|
/// A reference to the type implementing Plugin, available after successful load
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
public Plugin Instance
|
||||||
public Plugin Instance { get; internal set; }
|
{
|
||||||
|
get => _instance;
|
||||||
|
internal set => SetAndNotify(ref _instance, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates whether the user enabled the plugin or not
|
/// Indicates whether the user enabled the plugin or not
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
public bool Enabled
|
||||||
public bool Enabled { get; internal set; }
|
{
|
||||||
|
get => _enabled;
|
||||||
|
internal set => SetAndNotify(ref _enabled, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether the last time the plugin loaded, it loaded correctly
|
||||||
|
/// </summary>
|
||||||
|
public bool LastEnableSuccessful
|
||||||
|
{
|
||||||
|
get => _lastEnableSuccessful;
|
||||||
|
internal set => SetAndNotify(ref _lastEnableSuccessful, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The PluginLoader backing this plugin
|
/// The PluginLoader backing this plugin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
|
||||||
internal PluginLoader PluginLoader { get; set; }
|
internal PluginLoader PluginLoader { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The assembly the plugin code lives in
|
/// The assembly the plugin code lives in
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
|
||||||
internal Assembly Assembly { get; set; }
|
internal Assembly Assembly { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The entity representing the plugin
|
/// The entity representing the plugin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
|
||||||
internal PluginEntity PluginEntity { get; set; }
|
internal PluginEntity PluginEntity { get; set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{nameof(Guid)}: {Guid}, {nameof(Name)}: {Name}, {nameof(Version)}: {Version}";
|
return $"{Name} v{Version} - {Guid}";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ApplyToEntity()
|
||||||
|
{
|
||||||
|
PluginEntity.Id = Guid;
|
||||||
|
PluginEntity.IsEnabled = Enabled;
|
||||||
|
PluginEntity.LastEnableSuccessful = LastEnableSuccessful;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,8 +137,6 @@ namespace Artemis.Core.Services
|
|||||||
var pluginInfo = JsonConvert.DeserializeObject<PluginInfo>(File.ReadAllText(metadataFile));
|
var pluginInfo = JsonConvert.DeserializeObject<PluginInfo>(File.ReadAllText(metadataFile));
|
||||||
pluginInfo.Directory = subDirectory;
|
pluginInfo.Directory = subDirectory;
|
||||||
|
|
||||||
_logger.Debug("Loading plugin {pluginInfo}", pluginInfo);
|
|
||||||
OnPluginLoading(new PluginEventArgs(pluginInfo));
|
|
||||||
LoadPlugin(pluginInfo);
|
LoadPlugin(pluginInfo);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -150,38 +148,22 @@ namespace Artemis.Core.Services
|
|||||||
// Activate plugins after they are all loaded
|
// Activate plugins after they are all loaded
|
||||||
foreach (var pluginInfo in _plugins.Where(p => p.Enabled))
|
foreach (var pluginInfo in _plugins.Where(p => p.Enabled))
|
||||||
{
|
{
|
||||||
if (!pluginInfo.PluginEntity.LastEnableSuccessful)
|
if (!pluginInfo.LastEnableSuccessful)
|
||||||
{
|
{
|
||||||
pluginInfo.Enabled = false;
|
pluginInfo.Enabled = false;
|
||||||
_logger.Warning("Plugin failed to load last time, disabling it now to avoid instability. Plugin info: {pluginInfo}", pluginInfo);
|
_logger.Warning("Plugin failed to load last time, disabling it now to avoid instability. Plugin info: {pluginInfo}", pluginInfo);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark this as false until the plugin enabled successfully and save it in case the plugin drags us down into a crash
|
|
||||||
pluginInfo.PluginEntity.LastEnableSuccessful = false;
|
|
||||||
_pluginRepository.SavePlugin(pluginInfo.PluginEntity);
|
|
||||||
|
|
||||||
var threwException = false;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.Debug("Enabling plugin {pluginInfo}", pluginInfo);
|
EnablePlugin(pluginInfo.Instance);
|
||||||
pluginInfo.Instance.SetEnabled(true);
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
_logger.Warning(new ArtemisPluginException(pluginInfo, "Failed to enable plugin", e), "Plugin exception");
|
// ignored, logged in EnablePlugin
|
||||||
pluginInfo.Enabled = false;
|
|
||||||
threwException = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We got this far so the plugin enabled and we didn't crash horribly, yay
|
|
||||||
if (!threwException)
|
|
||||||
{
|
|
||||||
pluginInfo.PluginEntity.LastEnableSuccessful = true;
|
|
||||||
_pluginRepository.SavePlugin(pluginInfo.PluginEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
OnPluginEnabled(new PluginEventArgs(pluginInfo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadingPlugins = false;
|
LoadingPlugins = false;
|
||||||
@ -213,16 +195,20 @@ namespace Artemis.Core.Services
|
|||||||
{
|
{
|
||||||
lock (_plugins)
|
lock (_plugins)
|
||||||
{
|
{
|
||||||
|
_logger.Debug("Loading plugin {pluginInfo}", pluginInfo);
|
||||||
|
OnPluginLoading(new PluginEventArgs(pluginInfo));
|
||||||
|
|
||||||
// Unload the plugin first if it is already loaded
|
// Unload the plugin first if it is already loaded
|
||||||
if (_plugins.Contains(pluginInfo))
|
if (_plugins.Contains(pluginInfo))
|
||||||
UnloadPlugin(pluginInfo);
|
UnloadPlugin(pluginInfo);
|
||||||
|
|
||||||
var pluginEntity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid);
|
var pluginEntity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid);
|
||||||
if (pluginEntity == null)
|
if (pluginEntity == null)
|
||||||
pluginEntity = new PluginEntity {PluginGuid = pluginInfo.Guid, IsEnabled = true, LastEnableSuccessful = true};
|
pluginEntity = new PluginEntity {Id = pluginInfo.Guid, IsEnabled = true, LastEnableSuccessful = true};
|
||||||
|
|
||||||
pluginInfo.PluginEntity = pluginEntity;
|
pluginInfo.PluginEntity = pluginEntity;
|
||||||
pluginInfo.Enabled = pluginEntity.IsEnabled;
|
pluginInfo.Enabled = pluginEntity.IsEnabled;
|
||||||
|
pluginInfo.LastEnableSuccessful = pluginEntity.LastEnableSuccessful;
|
||||||
|
|
||||||
var mainFile = Path.Combine(pluginInfo.Directory.FullName, pluginInfo.Main);
|
var mainFile = Path.Combine(pluginInfo.Directory.FullName, pluginInfo.Main);
|
||||||
if (!File.Exists(mainFile))
|
if (!File.Exists(mainFile))
|
||||||
@ -310,28 +296,37 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
public void EnablePlugin(Plugin plugin)
|
public void EnablePlugin(Plugin plugin)
|
||||||
{
|
{
|
||||||
plugin.PluginInfo.Enabled = true;
|
lock (_plugins)
|
||||||
plugin.PluginInfo.PluginEntity.IsEnabled = true;
|
{
|
||||||
plugin.PluginInfo.PluginEntity.LastEnableSuccessful = false;
|
_logger.Debug("Enabling plugin {pluginInfo}", plugin.PluginInfo);
|
||||||
|
|
||||||
|
plugin.PluginInfo.LastEnableSuccessful = false;
|
||||||
|
plugin.PluginInfo.ApplyToEntity();
|
||||||
|
|
||||||
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
|
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
|
||||||
|
|
||||||
var threwException = false;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
plugin.SetEnabled(true);
|
plugin.SetEnabled(true);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.Warning(new ArtemisPluginException(plugin.PluginInfo, "Failed to enable plugin", e), "Plugin exception");
|
_logger.Warning(new ArtemisPluginException(plugin.PluginInfo, "Exception during SetEnabled(true)", e), "Failed to enable plugin");
|
||||||
plugin.PluginInfo.Enabled = false;
|
throw;
|
||||||
threwException = true;
|
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
// We got this far so the plugin enabled and we didn't crash horribly, yay
|
|
||||||
if (!threwException)
|
|
||||||
{
|
{
|
||||||
plugin.PluginInfo.PluginEntity.LastEnableSuccessful = true;
|
// We got this far so the plugin enabled and we didn't crash horribly, yay
|
||||||
|
if (plugin.PluginInfo.Enabled)
|
||||||
|
{
|
||||||
|
plugin.PluginInfo.LastEnableSuccessful = true;
|
||||||
|
plugin.PluginInfo.ApplyToEntity();
|
||||||
|
|
||||||
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
|
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
|
||||||
|
|
||||||
|
_logger.Debug("Successfully enabled plugin {pluginInfo}", plugin.PluginInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OnPluginEnabled(new PluginEventArgs(plugin.PluginInfo));
|
OnPluginEnabled(new PluginEventArgs(plugin.PluginInfo));
|
||||||
@ -339,18 +334,29 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
public void DisablePlugin(Plugin plugin)
|
public void DisablePlugin(Plugin plugin)
|
||||||
{
|
{
|
||||||
plugin.PluginInfo.Enabled = false;
|
lock (_plugins)
|
||||||
plugin.PluginInfo.PluginEntity.IsEnabled = false;
|
{
|
||||||
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
|
_logger.Debug("Disabling plugin {pluginInfo}", plugin.PluginInfo);
|
||||||
|
|
||||||
// Device providers cannot be disabled at runtime, restart the application
|
// Device providers cannot be disabled at runtime, restart the application
|
||||||
if (plugin is DeviceProvider)
|
if (plugin is DeviceProvider)
|
||||||
{
|
{
|
||||||
|
// Don't call SetEnabled(false) but simply update enabled state and save it
|
||||||
|
plugin.PluginInfo.Enabled = false;
|
||||||
|
plugin.PluginInfo.ApplyToEntity();
|
||||||
|
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
|
||||||
|
|
||||||
|
_logger.Debug("Shutting down for device provider disable {pluginInfo}", plugin.PluginInfo);
|
||||||
CurrentProcessUtilities.Shutdown(2, true);
|
CurrentProcessUtilities.Shutdown(2, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin.SetEnabled(false);
|
plugin.SetEnabled(false);
|
||||||
|
plugin.PluginInfo.ApplyToEntity();
|
||||||
|
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
|
||||||
|
|
||||||
|
_logger.Debug("Successfully disabled plugin {pluginInfo}", plugin.PluginInfo);
|
||||||
|
}
|
||||||
|
|
||||||
OnPluginDisabled(new PluginEventArgs(plugin.PluginInfo));
|
OnPluginDisabled(new PluginEventArgs(plugin.PluginInfo));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,6 @@ namespace Artemis.Storage.Entities.Plugins
|
|||||||
public class PluginEntity
|
public class PluginEntity
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public Guid PluginGuid { get; set; }
|
|
||||||
|
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; }
|
||||||
public bool LastEnableSuccessful { get; set; }
|
public bool LastEnableSuccessful { get; set; }
|
||||||
|
|||||||
@ -3,7 +3,7 @@ using LiteDB;
|
|||||||
|
|
||||||
namespace Artemis.Storage.Migrations
|
namespace Artemis.Storage.Migrations
|
||||||
{
|
{
|
||||||
public class AttributeBasedPropertiesMigration : IStorageMigration
|
public class M1AttributeBasedPropertiesMigration : IStorageMigration
|
||||||
{
|
{
|
||||||
public int UserVersion => 1;
|
public int UserVersion => 1;
|
||||||
|
|
||||||
@ -4,7 +4,7 @@ using LiteDB;
|
|||||||
|
|
||||||
namespace Artemis.Storage.Migrations
|
namespace Artemis.Storage.Migrations
|
||||||
{
|
{
|
||||||
public class ProfileEntitiesEnabledMigration : IStorageMigration
|
public class M2ProfileEntitiesEnabledMigration : IStorageMigration
|
||||||
{
|
{
|
||||||
public int UserVersion => 2;
|
public int UserVersion => 2;
|
||||||
|
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
using Artemis.Storage.Migrations.Interfaces;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrations
|
||||||
|
{
|
||||||
|
public class M3PluginEntitiesIndexChangesMigration : IStorageMigration
|
||||||
|
{
|
||||||
|
public int UserVersion => 3;
|
||||||
|
|
||||||
|
public void Apply(LiteRepository repository)
|
||||||
|
{
|
||||||
|
if (repository.Database.CollectionExists("PluginEntity"))
|
||||||
|
repository.Database.DropCollection("PluginEntity");
|
||||||
|
if (repository.Database.CollectionExists("PluginSettingEntity"))
|
||||||
|
repository.Database.DropCollection("PluginSettingEntity");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,9 +13,7 @@ namespace Artemis.Storage.Repositories
|
|||||||
{
|
{
|
||||||
_repository = repository;
|
_repository = repository;
|
||||||
|
|
||||||
_repository.Database.GetCollection<PluginEntity>().EnsureIndex(s => s.PluginGuid);
|
_repository.Database.GetCollection<PluginSettingEntity>().EnsureIndex(s => new {s.Name, s.PluginGuid}, true);
|
||||||
_repository.Database.GetCollection<PluginSettingEntity>().EnsureIndex(s => s.Name);
|
|
||||||
_repository.Database.GetCollection<PluginSettingEntity>().EnsureIndex(s => s.PluginGuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddPlugin(PluginEntity pluginEntity)
|
public void AddPlugin(PluginEntity pluginEntity)
|
||||||
@ -25,12 +23,13 @@ namespace Artemis.Storage.Repositories
|
|||||||
|
|
||||||
public PluginEntity GetPluginByGuid(Guid pluginGuid)
|
public PluginEntity GetPluginByGuid(Guid pluginGuid)
|
||||||
{
|
{
|
||||||
return _repository.FirstOrDefault<PluginEntity>(p => p.PluginGuid == pluginGuid);
|
return _repository.FirstOrDefault<PluginEntity>(p => p.Id == pluginGuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SavePlugin(PluginEntity pluginEntity)
|
public void SavePlugin(PluginEntity pluginEntity)
|
||||||
{
|
{
|
||||||
_repository.Upsert(pluginEntity);
|
_repository.Upsert(pluginEntity);
|
||||||
|
_repository.Database.Checkpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSetting(PluginSettingEntity pluginSettingEntity)
|
public void AddSetting(PluginSettingEntity pluginSettingEntity)
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using Artemis.UI.Shared.Ninject.Factories;
|
using Artemis.UI.Shared.Ninject.Factories;
|
||||||
using Artemis.UI.Shared.Services.Interfaces;
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
|
using MaterialDesignThemes.Wpf;
|
||||||
using Ninject.Extensions.Conventions;
|
using Ninject.Extensions.Conventions;
|
||||||
using Ninject.Modules;
|
using Ninject.Modules;
|
||||||
|
|
||||||
@ -32,6 +33,8 @@ namespace Artemis.UI.Shared.Ninject
|
|||||||
.BindAllInterfaces()
|
.BindAllInterfaces()
|
||||||
.Configure(c => c.InSingletonScope());
|
.Configure(c => c.InSingletonScope());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Kernel.Bind<ISnackbarMessageQueue>().ToConstant(new SnackbarMessageQueue()).InSingletonScope();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,6 +70,10 @@
|
|||||||
<Setter Property="IsTabStop" Value="False" />
|
<Setter Property="IsTabStop" Value="False" />
|
||||||
<Setter Property="Focusable" Value="False" />
|
<Setter Property="Focusable" Value="False" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style TargetType="GridSplitter" BasedOn="{StaticResource MaterialDesignGridSplitter}">
|
||||||
|
<Setter Property="IsTabStop" Value="False" />
|
||||||
|
<Setter Property="Focusable" Value="False" />
|
||||||
|
</Style>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</Application>
|
||||||
@ -13,6 +13,7 @@ using Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem;
|
|||||||
using Artemis.UI.Screens.Module.ProfileEditor.Visualization;
|
using Artemis.UI.Screens.Module.ProfileEditor.Visualization;
|
||||||
using Artemis.UI.Screens.Settings.Debug;
|
using Artemis.UI.Screens.Settings.Debug;
|
||||||
using Artemis.UI.Screens.Settings.Tabs.Devices;
|
using Artemis.UI.Screens.Settings.Tabs.Devices;
|
||||||
|
using Artemis.UI.Screens.Settings.Tabs.Plugins;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
|
|
||||||
namespace Artemis.UI.Ninject.Factories
|
namespace Artemis.UI.Ninject.Factories
|
||||||
@ -26,6 +27,11 @@ namespace Artemis.UI.Ninject.Factories
|
|||||||
ModuleRootViewModel Create(Module module);
|
ModuleRootViewModel Create(Module module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IPluginSettingsVmFactory : IVmFactory
|
||||||
|
{
|
||||||
|
PluginSettingsViewModel Create(Plugin plugin);
|
||||||
|
}
|
||||||
|
|
||||||
public interface IDeviceSettingsVmFactory : IVmFactory
|
public interface IDeviceSettingsVmFactory : IVmFactory
|
||||||
{
|
{
|
||||||
DeviceSettingsViewModel Create(ArtemisDevice device);
|
DeviceSettingsViewModel Create(ArtemisDevice device);
|
||||||
|
|||||||
@ -66,8 +66,9 @@
|
|||||||
<RowDefinition Height="28" />
|
<RowDefinition Height="28" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition />
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="1.5*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<!-- Left side -->
|
<!-- Left side -->
|
||||||
@ -157,8 +158,11 @@
|
|||||||
</materialDesign:DialogHost>
|
</materialDesign:DialogHost>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Resize -->
|
||||||
|
<GridSplitter Grid.Row="0" Grid.RowSpan="2" Grid.Column="1" Width="15" HorizontalAlignment="Stretch" Cursor="SizeWE" Margin="-15 0" Background="Transparent" />
|
||||||
|
|
||||||
<!-- Right side -->
|
<!-- Right side -->
|
||||||
<Grid Grid.Row="0" Grid.Column="1">
|
<Grid Grid.Row="0" Grid.Column="2">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="56" />
|
<RowDefinition Height="56" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
@ -214,21 +218,16 @@
|
|||||||
|
|
||||||
<!-- Bottom row, a bit hacky but has a ZIndex of 2 to cut off the time caret that overlaps the entire timeline -->
|
<!-- Bottom row, a bit hacky but has a ZIndex of 2 to cut off the time caret that overlaps the entire timeline -->
|
||||||
<Grid Grid.Row="1"
|
<Grid Grid.Row="1"
|
||||||
Grid.ColumnSpan="2"
|
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Panel.ZIndex="2"
|
Panel.ZIndex="2"
|
||||||
Background="{DynamicResource MaterialDesignCardBackground}">
|
Background="{DynamicResource MaterialDesignCardBackground}">
|
||||||
<!-- Selected layer controls -->
|
<!-- Selected layer controls -->
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid Grid.Column="0">
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<StackPanel Grid.Column="0"
|
<StackPanel Grid.Column="0"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
Margin="6"
|
Margin="6"
|
||||||
@ -251,7 +250,7 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Button Grid.Column="1"
|
<Button Grid.Column="1"
|
||||||
Style="{StaticResource MaterialDesignFlatMidBgButton}"
|
Style="{StaticResource MaterialDesignFlatMidBgButton}"
|
||||||
Margin="0 -2"
|
Margin="0 -2 5 -2"
|
||||||
Padding="10 0"
|
Padding="10 0"
|
||||||
Height="20"
|
Height="20"
|
||||||
Width="110"
|
Width="110"
|
||||||
@ -260,13 +259,13 @@
|
|||||||
Visibility="{Binding PropertyTreeVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
|
Visibility="{Binding PropertyTreeVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
|
||||||
Command="{x:Static materialDesign:Transitioner.MoveLastCommand}"
|
Command="{x:Static materialDesign:Transitioner.MoveLastCommand}"
|
||||||
CommandTarget="{Binding ElementName=TransitionCommandAnchor}">
|
CommandTarget="{Binding ElementName=TransitionCommandAnchor}">
|
||||||
<TextBlock FontSize="10">
|
<TextBlock FontSize="11">
|
||||||
ADD EFFECT
|
ADD EFFECT
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</Button>
|
</Button>
|
||||||
<Button Grid.Column="1"
|
<Button Grid.Column="1"
|
||||||
Style="{StaticResource MaterialDesignFlatMidBgButton}"
|
Style="{StaticResource MaterialDesignFlatMidBgButton}"
|
||||||
Margin="0 -2"
|
Margin="0 -2 5 -2"
|
||||||
Padding="10 0"
|
Padding="10 0"
|
||||||
Height="20"
|
Height="20"
|
||||||
Width="110"
|
Width="110"
|
||||||
@ -275,12 +274,69 @@
|
|||||||
Visibility="{Binding PropertyTreeVisible, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}"
|
Visibility="{Binding PropertyTreeVisible, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}"
|
||||||
Command="{x:Static materialDesign:Transitioner.MoveFirstCommand}"
|
Command="{x:Static materialDesign:Transitioner.MoveFirstCommand}"
|
||||||
CommandTarget="{Binding ElementName=TransitionCommandAnchor}">
|
CommandTarget="{Binding ElementName=TransitionCommandAnchor}">
|
||||||
<TextBlock FontSize="10">
|
<TextBlock FontSize="11">
|
||||||
SHOW PROPERTIES
|
SHOW PROPERTIES
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<Grid Grid.Row="1"
|
||||||
|
Grid.Column="2"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Panel.ZIndex="2"
|
||||||
|
Background="{DynamicResource MaterialDesignCardBackground}">
|
||||||
|
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<ListBox Style="{StaticResource MaterialDesignToolToggleListBox}" SelectedIndex="0" Height="20" Margin="5 0 0 0">
|
||||||
|
<ListBoxItem Padding="10 0">
|
||||||
|
<ListBoxItem.ToolTip>
|
||||||
|
<ToolTip Placement="Top" VerticalOffset="-5">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock>Select the <Run FontWeight="Bold">enter</Run> timeline</TextBlock>
|
||||||
|
<TextBlock>Played when the folder/layer starts displaying (condition is met)</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</ToolTip>
|
||||||
|
</ListBoxItem.ToolTip>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="RayStart" Width="20" Height="20" Margin="0 -4" />
|
||||||
|
<TextBlock Margin="5 0 0 0" FontSize="11">ENTER</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</ListBoxItem>
|
||||||
|
<ListBoxItem Padding="10 0">
|
||||||
|
<ListBoxItem.ToolTip>
|
||||||
|
<ToolTip Placement="Top" VerticalOffset="-5">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock>Select the <Run FontWeight="Bold">main</Run> timeline</TextBlock>
|
||||||
|
<TextBlock>Played after the enter timeline finishes, either on repeat or once</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</ToolTip>
|
||||||
|
</ListBoxItem.ToolTip>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="RayStartEnd" Width="20" Height="20" Margin="0 -4" />
|
||||||
|
<TextBlock Margin="5 0 0 0" FontSize="11">MAIN</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</ListBoxItem>
|
||||||
|
<ListBoxItem Padding="10 0">
|
||||||
|
<ListBoxItem.ToolTip>
|
||||||
|
<ToolTip Placement="Top" VerticalOffset="-5">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock>Select the <Run FontWeight="Bold">exit</Run> timeline</TextBlock>
|
||||||
|
<TextBlock>Played when the folder/layer stops displaying (conditon no longer met)</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</ToolTip>
|
||||||
|
|
||||||
|
</ListBoxItem.ToolTip>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="RayEnd" Width="20" Height="20" Margin="0 -4" />
|
||||||
|
<TextBlock Margin="5 0 0 0" FontSize="11">EXIT</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</ListBoxItem>
|
||||||
|
</ListBox>
|
||||||
|
|
||||||
<!-- Zoom control -->
|
<!-- Zoom control -->
|
||||||
<Slider Grid.Column="1"
|
<Slider Grid.Column="1"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
@ -290,6 +346,7 @@
|
|||||||
Maximum="350"
|
Maximum="350"
|
||||||
Value="{Binding ProfileEditorService.PixelsPerSecond}"
|
Value="{Binding ProfileEditorService.PixelsPerSecond}"
|
||||||
Width="319" />
|
Width="319" />
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -47,7 +47,8 @@
|
|||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
</mde:MaterialWindow.Resources>
|
</mde:MaterialWindow.Resources>
|
||||||
<materialDesign:DialogHost Identifier="RootDialog" DialogTheme="Inherit">
|
<materialDesign:DialogHost Identifier="RootDialog" DialogTheme="Inherit" SnackbarMessageQueue="{Binding MainMessageQueue}">
|
||||||
|
<Grid>
|
||||||
<materialDesign:DrawerHost IsLeftDrawerOpen="{Binding IsSidebarVisible}">
|
<materialDesign:DrawerHost IsLeftDrawerOpen="{Binding IsSidebarVisible}">
|
||||||
<materialDesign:DrawerHost.LeftDrawerContent>
|
<materialDesign:DrawerHost.LeftDrawerContent>
|
||||||
<ContentControl s:View.Model="{Binding SidebarViewModel}" Width="220" ClipToBounds="False" />
|
<ContentControl s:View.Model="{Binding SidebarViewModel}" Width="220" ClipToBounds="False" />
|
||||||
@ -69,5 +70,7 @@
|
|||||||
<ContentControl s:View.Model="{Binding ActiveItem}" Style="{StaticResource InitializingFade}" />
|
<ContentControl s:View.Model="{Binding ActiveItem}" Style="{StaticResource InitializingFade}" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</materialDesign:DrawerHost>
|
</materialDesign:DrawerHost>
|
||||||
|
<materialDesign:Snackbar x:Name="MainSnackbar" MessageQueue="{Binding MainMessageQueue}" />
|
||||||
|
</Grid>
|
||||||
</materialDesign:DialogHost>
|
</materialDesign:DialogHost>
|
||||||
</mde:MaterialWindow>
|
</mde:MaterialWindow>
|
||||||
@ -28,9 +28,10 @@ namespace Artemis.UI.Screens
|
|||||||
private bool _lostFocus;
|
private bool _lostFocus;
|
||||||
|
|
||||||
public RootViewModel(IEventAggregator eventAggregator, SidebarViewModel sidebarViewModel, ISettingsService settingsService, ICoreService coreService,
|
public RootViewModel(IEventAggregator eventAggregator, SidebarViewModel sidebarViewModel, ISettingsService settingsService, ICoreService coreService,
|
||||||
IDebugService debugService)
|
IDebugService debugService, ISnackbarMessageQueue snackbarMessageQueue)
|
||||||
{
|
{
|
||||||
SidebarViewModel = sidebarViewModel;
|
SidebarViewModel = sidebarViewModel;
|
||||||
|
MainMessageQueue = snackbarMessageQueue;
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
_coreService = coreService;
|
_coreService = coreService;
|
||||||
_debugService = debugService;
|
_debugService = debugService;
|
||||||
@ -49,9 +50,9 @@ namespace Artemis.UI.Screens
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SidebarViewModel SidebarViewModel { get; }
|
public SidebarViewModel SidebarViewModel { get; }
|
||||||
|
public ISnackbarMessageQueue MainMessageQueue { get; set; }
|
||||||
public bool IsSidebarVisible { get; set; }
|
public bool IsSidebarVisible { get; set; }
|
||||||
public bool ActiveItemReady { get; set; }
|
public bool ActiveItemReady { get; set; }
|
||||||
|
|
||||||
public string WindowTitle { get; set; }
|
public string WindowTitle { get; set; }
|
||||||
|
|
||||||
public void WindowDeactivated()
|
public void WindowDeactivated()
|
||||||
|
|||||||
@ -27,20 +27,20 @@ namespace Artemis.UI.Screens.Settings
|
|||||||
private readonly IDialogService _dialogService;
|
private readonly IDialogService _dialogService;
|
||||||
private readonly IPluginService _pluginService;
|
private readonly IPluginService _pluginService;
|
||||||
private readonly ISettingsService _settingsService;
|
private readonly ISettingsService _settingsService;
|
||||||
|
private readonly IPluginSettingsVmFactory _pluginSettingsVmFactory;
|
||||||
private readonly ISurfaceService _surfaceService;
|
private readonly ISurfaceService _surfaceService;
|
||||||
private readonly IWindowManager _windowManager;
|
|
||||||
|
|
||||||
public SettingsViewModel(ISurfaceService surfaceService, IPluginService pluginService, IDialogService dialogService, IWindowManager windowManager,
|
public SettingsViewModel(ISurfaceService surfaceService, IPluginService pluginService, IDialogService dialogService, IDebugService debugService,
|
||||||
IDebugService debugService, ISettingsService settingsService, IDeviceSettingsVmFactory deviceSettingsVmFactory)
|
ISettingsService settingsService, IPluginSettingsVmFactory pluginSettingsVmFactory, IDeviceSettingsVmFactory deviceSettingsVmFactory)
|
||||||
{
|
{
|
||||||
DisplayName = "Settings";
|
DisplayName = "Settings";
|
||||||
|
|
||||||
_surfaceService = surfaceService;
|
_surfaceService = surfaceService;
|
||||||
_pluginService = pluginService;
|
_pluginService = pluginService;
|
||||||
_dialogService = dialogService;
|
_dialogService = dialogService;
|
||||||
_windowManager = windowManager;
|
|
||||||
_debugService = debugService;
|
_debugService = debugService;
|
||||||
_settingsService = settingsService;
|
_settingsService = settingsService;
|
||||||
|
_pluginSettingsVmFactory = pluginSettingsVmFactory;
|
||||||
_deviceSettingsVmFactory = deviceSettingsVmFactory;
|
_deviceSettingsVmFactory = deviceSettingsVmFactory;
|
||||||
|
|
||||||
DeviceSettingsViewModels = new BindableCollection<DeviceSettingsViewModel>();
|
DeviceSettingsViewModels = new BindableCollection<DeviceSettingsViewModel>();
|
||||||
@ -189,7 +189,7 @@ namespace Artemis.UI.Screens.Settings
|
|||||||
DeviceSettingsViewModels.AddRange(_surfaceService.ActiveSurface.Devices.Select(d => _deviceSettingsVmFactory.Create(d)));
|
DeviceSettingsViewModels.AddRange(_surfaceService.ActiveSurface.Devices.Select(d => _deviceSettingsVmFactory.Create(d)));
|
||||||
|
|
||||||
Plugins.Clear();
|
Plugins.Clear();
|
||||||
Plugins.AddRange(_pluginService.GetAllPluginInfo().Select(p => new PluginSettingsViewModel(p.Instance, _windowManager, _dialogService, _pluginService)));
|
Plugins.AddRange(_pluginService.GetAllPluginInfo().Select(p => _pluginSettingsVmFactory.Create(p.Instance)));
|
||||||
|
|
||||||
base.OnInitialActivate();
|
base.OnInitialActivate();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,7 @@
|
|||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="80" />
|
<ColumnDefinition Width="80" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
@ -43,9 +44,16 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<materialDesign:PackIcon Kind="{Binding Icon}" Width="48" Height="48" Grid.Row="0" Grid.RowSpan="2" HorizontalAlignment="Center" />
|
<materialDesign:PackIcon Kind="{Binding Icon}" Width="48" Height="48" Grid.Row="0" Grid.RowSpan="2" HorizontalAlignment="Center" />
|
||||||
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Text="{Binding PluginInfo.Name}" Grid.Column="1" Grid.Row="0" />
|
|
||||||
|
<TextBlock Grid.Column="1" Grid.Row="0" Style="{StaticResource MaterialDesignTextBlock}" Text="{Binding PluginInfo.Name}" />
|
||||||
|
<materialDesign:Card Grid.Column="2" Grid.Row="0" Background="#FF4343" Height="22" Padding="4" Margin="0 -18 0 0"
|
||||||
|
Visibility="{Binding PluginInfo.LastEnableSuccessful, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
|
||||||
|
LOAD FAILED
|
||||||
|
</materialDesign:Card>
|
||||||
|
|
||||||
<TextBlock Grid.Column="1"
|
<TextBlock Grid.Column="1"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
Text="{Binding PluginInfo.Description}"
|
Text="{Binding PluginInfo.Description}"
|
||||||
Style="{StaticResource MaterialDesignTextBlock}"
|
Style="{StaticResource MaterialDesignTextBlock}"
|
||||||
@ -56,15 +64,17 @@
|
|||||||
<Button Style="{StaticResource MaterialDesignOutlinedButton}" ToolTip="MaterialDesignOutlinedButton" Margin="4" s:View.ActionTarget="{Binding}" Command="{s:Action OpenSettings}">
|
<Button Style="{StaticResource MaterialDesignOutlinedButton}" ToolTip="MaterialDesignOutlinedButton" Margin="4" s:View.ActionTarget="{Binding}" Command="{s:Action OpenSettings}">
|
||||||
SETTINGS
|
SETTINGS
|
||||||
</Button>
|
</Button>
|
||||||
<!-- <Button Style="{StaticResource MaterialDesignOutlinedButton}" ToolTip="MaterialDesignOutlinedButton" Margin="4"> -->
|
|
||||||
<!-- SETTINGS -->
|
|
||||||
<!-- </Button> -->
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="8">
|
<StackPanel Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="8"
|
||||||
|
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
|
||||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" IsChecked="{Binding IsEnabled}">
|
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" IsChecked="{Binding IsEnabled}">
|
||||||
Plugin enabled
|
Plugin enabled
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="8"
|
||||||
|
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||||
|
<ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}" Value="0" IsIndeterminate="True" />
|
||||||
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</materialDesign:Card>
|
</materialDesign:Card>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,4 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core.Plugins.Abstract;
|
using Artemis.Core.Plugins.Abstract;
|
||||||
using Artemis.Core.Plugins.Models;
|
using Artemis.Core.Plugins.Models;
|
||||||
@ -13,9 +15,11 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
{
|
{
|
||||||
private readonly IDialogService _dialogService;
|
private readonly IDialogService _dialogService;
|
||||||
private readonly IPluginService _pluginService;
|
private readonly IPluginService _pluginService;
|
||||||
|
private readonly ISnackbarMessageQueue _snackbarMessageQueue;
|
||||||
private readonly IWindowManager _windowManager;
|
private readonly IWindowManager _windowManager;
|
||||||
|
|
||||||
public PluginSettingsViewModel(Plugin plugin, IWindowManager windowManager, IDialogService dialogService, IPluginService pluginService)
|
public PluginSettingsViewModel(Plugin plugin, IWindowManager windowManager, IDialogService dialogService, IPluginService pluginService,
|
||||||
|
ISnackbarMessageQueue snackbarMessageQueue)
|
||||||
{
|
{
|
||||||
Plugin = plugin;
|
Plugin = plugin;
|
||||||
PluginInfo = plugin.PluginInfo;
|
PluginInfo = plugin.PluginInfo;
|
||||||
@ -23,6 +27,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
_windowManager = windowManager;
|
_windowManager = windowManager;
|
||||||
_dialogService = dialogService;
|
_dialogService = dialogService;
|
||||||
_pluginService = pluginService;
|
_pluginService = pluginService;
|
||||||
|
_snackbarMessageQueue = snackbarMessageQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Plugin Plugin { get; set; }
|
public Plugin Plugin { get; set; }
|
||||||
@ -40,6 +45,8 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
|
|
||||||
public bool CanOpenSettings => IsEnabled && Plugin.HasConfigurationViewModel;
|
public bool CanOpenSettings => IsEnabled && Plugin.HasConfigurationViewModel;
|
||||||
|
|
||||||
|
public bool Enabling { get; set; }
|
||||||
|
|
||||||
public async Task OpenSettings()
|
public async Task OpenSettings()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -55,6 +62,18 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task ShowLogsFolder()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
await _dialogService.ShowExceptionDialog("Welp, we couldn\'t open the logs folder for you", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private PackIconKind GetIconKind()
|
private PackIconKind GetIconKind()
|
||||||
{
|
{
|
||||||
if (PluginInfo.Icon != null)
|
if (PluginInfo.Icon != null)
|
||||||
@ -105,7 +124,23 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (enable)
|
if (enable)
|
||||||
|
{
|
||||||
|
Enabling = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
_pluginService.EnablePlugin(Plugin);
|
_pluginService.EnablePlugin(Plugin);
|
||||||
|
_snackbarMessageQueue.Enqueue($"Enabled plugin {PluginInfo.Name}");
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_snackbarMessageQueue.Enqueue($"Failed to enable plugin {PluginInfo.Name}", "VIEW LOGS", async () => await ShowLogsFolder());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Enabling = false;
|
||||||
|
NotifyOfPropertyChange(() => IsEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_pluginService.DisablePlugin(Plugin);
|
_pluginService.DisablePlugin(Plugin);
|
||||||
|
|
||||||
|
|||||||
@ -244,4 +244,5 @@
|
|||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=leds/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=leds/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=snackbar/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
Loading…
x
Reference in New Issue
Block a user