diff --git a/Configuration/ConfigManager.cs b/Configuration/ConfigManager.cs index 6d8c0bff..d5145ba6 100644 --- a/Configuration/ConfigManager.cs +++ b/Configuration/ConfigManager.cs @@ -10,21 +10,25 @@ namespace TweetDuck.Configuration{ sealed class ConfigManager{ public UserConfig User { get; } public SystemConfig System { get; } + public PluginConfig Plugins { get; } public event EventHandler ProgramRestartRequested; private readonly FileConfigInstance<UserConfig> infoUser; private readonly FileConfigInstance<SystemConfig> infoSystem; + private readonly PluginConfigInstance infoPlugins; private readonly IConfigInstance<BaseConfig>[] infoList; public ConfigManager(){ User = new UserConfig(this); System = new SystemConfig(this); + Plugins = new PluginConfig(this); infoList = new IConfigInstance<BaseConfig>[]{ infoUser = new FileConfigInstance<UserConfig>(Program.UserConfigFilePath, User, "program options"), - infoSystem = new FileConfigInstance<SystemConfig>(Program.SystemConfigFilePath, System, "system options") + infoSystem = new FileConfigInstance<SystemConfig>(Program.SystemConfigFilePath, System, "system options"), + infoPlugins = new PluginConfigInstance(Program.PluginConfigFilePath, Plugins) }; // TODO refactor further @@ -51,16 +55,19 @@ public ConfigManager(){ public void LoadAll(){ infoUser.Load(); infoSystem.Load(); + infoPlugins.Load(); } public void SaveAll(){ infoUser.Save(); infoSystem.Save(); + infoPlugins.Save(); } public void ReloadAll(){ infoUser.Reload(); infoSystem.Reload(); + infoPlugins.Reload(); } private void TriggerProgramRestartRequested(){ diff --git a/Configuration/Instance/PluginConfigInstance.cs b/Configuration/Instance/PluginConfigInstance.cs new file mode 100644 index 00000000..20fe9aea --- /dev/null +++ b/Configuration/Instance/PluginConfigInstance.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace TweetDuck.Configuration.Instance{ + class PluginConfigInstance : IConfigInstance<PluginConfig>{ + public PluginConfig Instance { get; } + + private readonly string filename; + + public PluginConfigInstance(string filename, PluginConfig instance){ + this.filename = filename; + this.Instance = instance; + } + + public void Load(){ + try{ + using(StreamReader reader = new StreamReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), Encoding.UTF8)){ + string line = reader.ReadLine(); + + if (line == "#Disabled"){ + HashSet<string> newDisabled = new HashSet<string>(); + + while((line = reader.ReadLine()) != null){ + newDisabled.Add(line); + } + + Instance.ReloadSilently(newDisabled); + } + } + }catch(FileNotFoundException){ + }catch(DirectoryNotFoundException){ + }catch(Exception e){ + Program.Reporter.HandleException("Plugin Configuration Error", "Could not read the plugin configuration file. If you continue, the list of disabled plugins will be reset to default.", true, e); + } + } + + public void Save(){ + try{ + using(StreamWriter writer = new StreamWriter(new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None), Encoding.UTF8)){ + writer.WriteLine("#Disabled"); + + foreach(string identifier in Instance.DisabledPlugins){ + writer.WriteLine(identifier); + } + } + }catch(Exception e){ + Program.Reporter.HandleException("Plugin Configuration Error", "Could not save the plugin configuration file.", true, e); + } + } + + public void Reload(){ + Load(); + } + + public void Reset(){ + try{ + File.Delete(filename); + Instance.ReloadSilently(Instance.ConstructWithDefaults<PluginConfig>().DisabledPlugins); + }catch(Exception e){ + Program.Reporter.HandleException("Plugin Configuration Error", "Could not delete the plugin configuration file.", true, e); + return; + } + + Reload(); + } + } +} diff --git a/Configuration/PluginConfig.cs b/Configuration/PluginConfig.cs new file mode 100644 index 00000000..f1940ac1 --- /dev/null +++ b/Configuration/PluginConfig.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using TweetDuck.Plugins; +using TweetDuck.Plugins.Events; + +namespace TweetDuck.Configuration{ + sealed class PluginConfig : ConfigManager.BaseConfig, IPluginConfig{ + private static readonly string[] DefaultDisabled = { + "official/clear-columns", + "official/reply-account" + }; + + // CONFIGURATION + + public IEnumerable<string> DisabledPlugins => disabled; + + public event EventHandler<PluginChangedStateEventArgs> PluginChangedState; + + public void SetEnabled(Plugin plugin, bool enabled){ + if ((enabled && disabled.Remove(plugin.Identifier)) || (!enabled && disabled.Add(plugin.Identifier))){ + PluginChangedState?.Invoke(this, new PluginChangedStateEventArgs(plugin, enabled)); + Save(); + } + } + + public bool IsEnabled(Plugin plugin){ + return !disabled.Contains(plugin.Identifier); + } + + public void ReloadSilently(IEnumerable<string> newDisabled){ + disabled.Clear(); + disabled.UnionWith(newDisabled); + } + + private readonly HashSet<string> disabled = new HashSet<string>(DefaultDisabled); + + // END OF CONFIG + + public PluginConfig(ConfigManager configManager) : base(configManager){} + + protected override ConfigManager.BaseConfig ConstructWithDefaults(ConfigManager configManager){ + return new PluginConfig(configManager); + } + } +} diff --git a/Core/FormBrowser.cs b/Core/FormBrowser.cs index bc5d1c9b..3aef36b7 100644 --- a/Core/FormBrowser.cs +++ b/Core/FormBrowser.cs @@ -62,7 +62,7 @@ public FormBrowser(){ Text = Program.BrandName; - this.plugins = new PluginManager(Program.PluginPath, Program.PluginConfigFilePath); + this.plugins = new PluginManager(Program.Config.Plugins, Program.PluginPath); this.plugins.Reloaded += plugins_Reloaded; this.plugins.Executed += plugins_Executed; this.plugins.Reload(); diff --git a/Core/Other/Settings/Dialogs/DialogSettingsManage.cs b/Core/Other/Settings/Dialogs/DialogSettingsManage.cs index 07a33de0..5b23a468 100644 --- a/Core/Other/Settings/Dialogs/DialogSettingsManage.cs +++ b/Core/Other/Settings/Dialogs/DialogSettingsManage.cs @@ -135,8 +135,9 @@ private void btnContinue_Click(object sender, EventArgs e){ Program.Config.ProgramRestartRequested -= Config_ProgramRestartRequested; if (SelectedItems.HasFlag(ProfileManager.Items.PluginData)){ + Program.Config.Plugins.Reset(); + try{ - File.Delete(Program.PluginConfigFilePath); Directory.Delete(Program.PluginDataPath, true); }catch(Exception ex){ Program.Reporter.HandleException("Profile Reset", "Could not delete plugin data.", true, ex); diff --git a/Plugins/Controls/PluginControl.cs b/Plugins/Controls/PluginControl.cs index f3bfc04e..5cbb7568 100644 --- a/Plugins/Controls/PluginControl.cs +++ b/Plugins/Controls/PluginControl.cs @@ -89,7 +89,7 @@ private void btnConfigure_Click(object sender, EventArgs e){ } private void btnToggleState_Click(object sender, EventArgs e){ - pluginManager.Config.ToggleEnabled(plugin); + pluginManager.Config.SetEnabled(plugin, !pluginManager.Config.IsEnabled(plugin)); UpdatePluginState(); } diff --git a/Plugins/IPluginConfig.cs b/Plugins/IPluginConfig.cs new file mode 100644 index 00000000..afe22f4f --- /dev/null +++ b/Plugins/IPluginConfig.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using TweetDuck.Plugins.Events; + +namespace TweetDuck.Plugins{ + interface IPluginConfig{ + IEnumerable<string> DisabledPlugins { get; } + + event EventHandler<PluginChangedStateEventArgs> PluginChangedState; + + void SetEnabled(Plugin plugin, bool enabled); + bool IsEnabled(Plugin plugin); + } +} diff --git a/Plugins/PluginConfig.cs b/Plugins/PluginConfig.cs deleted file mode 100644 index 65981cde..00000000 --- a/Plugins/PluginConfig.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using TweetDuck.Plugins.Events; - -namespace TweetDuck.Plugins{ - sealed class PluginConfig{ - public event EventHandler<PluginChangedStateEventArgs> PluginChangedState; - - public IEnumerable<string> DisabledPlugins => disabled; - public bool AnyDisabled => disabled.Count > 0; - - private static readonly string[] DefaultDisabled = { - "official/clear-columns", - "official/reply-account" - }; - - private readonly HashSet<string> disabled = new HashSet<string>(); - - public void SetEnabled(Plugin plugin, bool enabled){ - if ((enabled && disabled.Remove(plugin.Identifier)) || (!enabled && disabled.Add(plugin.Identifier))){ - PluginChangedState?.Invoke(this, new PluginChangedStateEventArgs(plugin, enabled)); - } - } - - public void ToggleEnabled(Plugin plugin){ - SetEnabled(plugin, !IsEnabled(plugin)); - } - - public bool IsEnabled(Plugin plugin){ - return !disabled.Contains(plugin.Identifier); - } - - public void Save(string file){ - try{ - using(StreamWriter writer = new StreamWriter(new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None), Encoding.UTF8)){ - writer.WriteLine("#Disabled"); - - foreach(string identifier in disabled){ - writer.WriteLine(identifier); - } - } - }catch(Exception e){ - Program.Reporter.HandleException("Plugin Configuration Error", "Could not save the plugin configuration file.", true, e); - } - } - - public void Load(string file){ - try{ - using(StreamReader reader = new StreamReader(new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read), Encoding.UTF8)){ - string line = reader.ReadLine(); - - if (line == "#Disabled"){ - disabled.Clear(); - - while((line = reader.ReadLine()) != null){ - disabled.Add(line); - } - } - } - }catch(FileNotFoundException){ - disabled.Clear(); - disabled.UnionWith(DefaultDisabled); - Save(file); - }catch(DirectoryNotFoundException){ - }catch(Exception e){ - Program.Reporter.HandleException("Plugin Configuration Error", "Could not read the plugin configuration file. If you continue, the list of disabled plugins will be reset to default.", true, e); - } - } - } -} diff --git a/Plugins/PluginManager.cs b/Plugins/PluginManager.cs index 290e97e8..39a71613 100644 --- a/Plugins/PluginManager.cs +++ b/Plugins/PluginManager.cs @@ -21,13 +21,12 @@ sealed class PluginManager{ public IEnumerable<Plugin> Plugins => plugins; public IEnumerable<InjectedHTML> NotificationInjections => bridge.NotificationInjections; - public PluginConfig Config { get; } + public IPluginConfig Config { get; } public event EventHandler<PluginErrorEventArgs> Reloaded; public event EventHandler<PluginErrorEventArgs> Executed; - + private readonly string rootPath; - private readonly string configPath; private readonly PluginBridge bridge; private readonly HashSet<Plugin> plugins = new HashSet<Plugin>(); @@ -36,15 +35,12 @@ sealed class PluginManager{ private IWebBrowser mainBrowser; - public PluginManager(string rootPath, string configPath){ + public PluginManager(IPluginConfig config, string rootPath){ + this.Config = config; + this.Config.PluginChangedState += Config_PluginChangedState; + this.rootPath = rootPath; - this.configPath = configPath; - - this.Config = new PluginConfig(); this.bridge = new PluginBridge(this); - - Config.Load(configPath); - Config.PluginChangedState += Config_PluginChangedState; } public void Register(IWebBrowser browser, PluginEnvironment environment, Control sync, bool asMainBrowser = false){ @@ -65,7 +61,6 @@ public void Register(IWebBrowser browser, PluginEnvironment environment, Control private void Config_PluginChangedState(object sender, PluginChangedStateEventArgs e){ mainBrowser?.ExecuteScriptAsync("TDPF_setPluginState", e.Plugin, e.IsEnabled); - Config.Save(configPath); } public bool IsPluginInstalled(string identifier){ @@ -120,8 +115,6 @@ public Plugin GetPluginFromToken(int token){ } public void Reload(){ - Config.Load(configPath); - plugins.Clear(); tokens.Clear(); diff --git a/Plugins/PluginScriptGenerator.cs b/Plugins/PluginScriptGenerator.cs index a85c9d5f..83292cea 100644 --- a/Plugins/PluginScriptGenerator.cs +++ b/Plugins/PluginScriptGenerator.cs @@ -1,9 +1,10 @@ -using TweetDuck.Plugins.Enums; +using System.Linq; +using TweetDuck.Plugins.Enums; namespace TweetDuck.Plugins{ static class PluginScriptGenerator{ - public static string GenerateConfig(PluginConfig config){ - return config.AnyDisabled ? "window.TD_PLUGINS.disabled = [\""+string.Join("\",\"", config.DisabledPlugins)+"\"];" : string.Empty; + public static string GenerateConfig(IPluginConfig config){ + return "window.TD_PLUGINS.disabled = ["+string.Join(",", config.DisabledPlugins.Select(id => $"\"{id}\""))+"]"; } public static string GeneratePlugin(string pluginIdentifier, string pluginContents, int pluginToken, PluginEnvironment environment){ diff --git a/TweetDuck.csproj b/TweetDuck.csproj index 2991c762..35223003 100644 --- a/TweetDuck.csproj +++ b/TweetDuck.csproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="packages\CefSharp.WinForms.67.0.0-pre01\build\CefSharp.WinForms.props" Condition="Exists('packages\CefSharp.WinForms.67.0.0-pre01\build\CefSharp.WinForms.props')" /> <Import Project="packages\CefSharp.Common.67.0.0-pre01\build\CefSharp.Common.props" Condition="Exists('packages\CefSharp.Common.67.0.0-pre01\build\CefSharp.Common.props')" /> @@ -57,6 +57,7 @@ <Compile Include="Configuration\Instance\FileConfigInstance.cs" /> <Compile Include="Configuration\ConfigManager.cs" /> <Compile Include="Configuration\Instance\IConfigInstance.cs" /> + <Compile Include="Configuration\Instance\PluginConfigInstance.cs" /> <Compile Include="Configuration\LockManager.cs" /> <Compile Include="Configuration\SystemConfig.cs" /> <Compile Include="Configuration\UserConfig.cs" /> @@ -259,10 +260,11 @@ <SubType>Component</SubType> </Compile> <Compile Include="Plugins\Enums\PluginFolder.cs" /> + <Compile Include="Plugins\IPluginConfig.cs" /> <Compile Include="Plugins\Plugin.cs" /> <Compile Include="Plugins\Events\PluginChangedStateEventArgs.cs" /> <Compile Include="Plugins\PluginBridge.cs" /> - <Compile Include="Plugins\PluginConfig.cs" /> + <Compile Include="Configuration\PluginConfig.cs" /> <Compile Include="Plugins\Enums\PluginEnvironment.cs" /> <Compile Include="Plugins\Enums\PluginGroup.cs" /> <Compile Include="Plugins\Events\PluginErrorEventArgs.cs" />