mirror of
https://github.com/Stone-Red-Code/DesktopMagic.git
synced 2026-09-04 08:56:15 +02:00
Fully implement plugin manager and improve internal plugin handling
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
<ResourceDictionary Source="Resources\StringResources.en.xaml" />
|
<ResourceDictionary Source="Resources\StringResources.en.xaml" />
|
||||||
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="Grey" SecondaryColor="LightBlue" />
|
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="Grey" SecondaryColor="LightBlue" />
|
||||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/BusyIndicator;component/Theme/Default.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
<Thickness x:Key="DefaultMargin" Top="6" Left="6" Right="6" Bottom ="6"></Thickness>
|
<Thickness x:Key="DefaultMargin" Top="6" Left="6" Right="6" Bottom ="6"></Thickness>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
using Modio.NET.Models;
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Windows.Input;
|
|
||||||
|
|
||||||
namespace DesktopMagic.DataContexts;
|
|
||||||
internal class ModEntryDataContext(Mod mod, ICommand installCommand)
|
|
||||||
{
|
|
||||||
public string Name => mod.Name!;
|
|
||||||
|
|
||||||
public string Description => mod.DescriptionPlaintext!;
|
|
||||||
|
|
||||||
public string? Logo => mod.Logo?.Thumb320x180?.ToString();
|
|
||||||
|
|
||||||
public DateTime FormattedDateAdded => DateTimeOffset.FromUnixTimeSeconds(mod.DateAdded).LocalDateTime;
|
|
||||||
public DateTime FormattedDateUpdated => DateTimeOffset.FromUnixTimeSeconds(mod.DateUpdated).LocalDateTime;
|
|
||||||
|
|
||||||
public ICommand InstallCommand => installCommand;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using DesktopMagic.Plugins;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace DesktopMagic.DataContexts;
|
||||||
|
|
||||||
|
internal class PluginEntryDataContext(PluginMetadata pluginMetadata, ICommand command, bool installed = false)
|
||||||
|
{
|
||||||
|
public string Name => pluginMetadata.Name;
|
||||||
|
|
||||||
|
public string? Description => pluginMetadata.Description;
|
||||||
|
|
||||||
|
public string? Logo => pluginMetadata.IconUri?.ToString();
|
||||||
|
|
||||||
|
public DateTime? FormattedDateAdded => pluginMetadata.Added;
|
||||||
|
public DateTime? FormattedDateUpdated => pluginMetadata.Updated;
|
||||||
|
|
||||||
|
public uint Id => pluginMetadata.Id;
|
||||||
|
|
||||||
|
public ICommand Command => command;
|
||||||
|
|
||||||
|
public Visibility InstallButtonVisibility => installed ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
|
||||||
|
public Visibility RemoveButtonVisibility => installed ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
}
|
||||||
@@ -3,11 +3,28 @@ using System.ComponentModel;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace DesktopMagic.DataContexts;
|
namespace DesktopMagic.DataContexts;
|
||||||
|
|
||||||
internal class PluginManagerDataContext : INotifyPropertyChanged
|
internal class PluginManagerDataContext : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
public event PropertyChangedEventHandler? PropertyChanged;
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
public ObservableCollection<ModEntryDataContext> Mods { get; } = [];
|
public ObservableCollection<PluginEntryDataContext> AllPlugins { get; } = [];
|
||||||
|
public ObservableCollection<PluginEntryDataContext> InstalledPlugins { get; } = [];
|
||||||
|
|
||||||
|
private bool _isLoading;
|
||||||
|
|
||||||
|
public bool IsLoading
|
||||||
|
{
|
||||||
|
get => _isLoading;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_isLoading = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
OnPropertyChanged(nameof(IsNotLoading));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsNotLoading => !IsLoading;
|
||||||
|
|
||||||
protected void OnPropertyChanged([CallerMemberName] string? name = null)
|
protected void OnPropertyChanged([CallerMemberName] string? name = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AlwaysUpToDate" Version="1.0.0.4" />
|
<PackageReference Include="AlwaysUpToDate" Version="1.0.0.4" />
|
||||||
|
<PackageReference Include="BusyIndicators" Version="2.1.2" />
|
||||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.1" />
|
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.1" />
|
||||||
<PackageReference Include="Google.Apis.Calendar.v3" Version="1.64.0.3171" />
|
<PackageReference Include="Google.Apis.Calendar.v3" Version="1.64.0.3171" />
|
||||||
<PackageReference Include="MaterialDesignThemes" Version="4.9.0" />
|
<PackageReference Include="MaterialDesignThemes" Version="4.9.0" />
|
||||||
|
|||||||
@@ -8,5 +8,3 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "Windows only application")]
|
[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "Windows only application")]
|
||||||
[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "No need to")]
|
[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "No need to")]
|
||||||
[assembly: SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "<Pending>")]
|
[assembly: SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "<Pending>")]
|
||||||
[assembly: SuppressMessage("Minor Code Smell", "S3604:Member initializer values should not be redundant", Justification = "False postives")]
|
|
||||||
[assembly: SuppressMessage("Critical Code Smell", "S2696:Instance members should not write to \"static\" fields", Justification = "<Pending>", Scope = "member", Target = "~P:DesktopMagic.MainWindowDataContext.Settings")]
|
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:DesktopMagic"
|
xmlns:local="clr-namespace:DesktopMagic"
|
||||||
xmlns:dataContext="clr-namespace:DesktopMagic.DataContexts"
|
xmlns:dataContext="clr-namespace:DesktopMagic.DataContexts"
|
||||||
d:DataContext="{d:DesignInstance Type=dataContext:PluginManagerDataContext}"
|
d:DataContext="{d:DesignInstance Type=dataContext:MainWindowDataContext}"
|
||||||
Closing="Window_Closing"
|
Closing="Window_Closing"
|
||||||
Closed="Window_Closed"
|
Closed="Window_Closed"
|
||||||
ShowInTaskbar="True"
|
ShowInTaskbar="True"
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
</ItemsControl.ItemsPanel>
|
</ItemsControl.ItemsPanel>
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<CheckBox Click="PluginCheckBox_Click" Content="{Binding Key}" IsChecked="{Binding Value.Enabled}" Style="{StaticResource MaterialDesignDarkCheckBox}" />
|
<CheckBox Click="PluginCheckBox_Click" Content="{Binding Value.Name}" Tag="{Binding Key}" IsChecked="{Binding Value.Enabled}" Style="{StaticResource MaterialDesignDarkCheckBox}" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|
||||||
<DockPanel Grid.Column="1" Margin="2.5,0,0,0">
|
<DockPanel Grid.Column="1" Margin="2.5,0,0,0">
|
||||||
<ComboBox x:Name="optionsComboBox" DockPanel.Dock="Top" Height="24" SelectedIndex="0" SelectionChanged="OptionsComboBox_SelectionChanged" Background="#FFECECEC" Padding="4" VerticalAlignment="Center" />
|
<ComboBox x:Name="optionsComboBox" DisplayMemberPath="Name" DockPanel.Dock="Top" Height="24" SelectedIndex="0" SelectionChanged="OptionsComboBox_SelectionChanged" Background="#FFECECEC" Padding="4" VerticalAlignment="Center" />
|
||||||
<ScrollViewer Background="#FFBBBBBB">
|
<ScrollViewer Background="#FFBBBBBB">
|
||||||
<Grid>
|
<Grid>
|
||||||
<StackPanel x:Name="optionsPanel" Margin="3,3,3,0" HorizontalAlignment="Stretch" Visibility="Collapsed">
|
<StackPanel x:Name="optionsPanel" Margin="3,3,3,0" HorizontalAlignment="Stretch" Visibility="Collapsed">
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ using DesktopMagic.Helpers;
|
|||||||
using DesktopMagic.Plugins;
|
using DesktopMagic.Plugins;
|
||||||
using DesktopMagic.Settings;
|
using DesktopMagic.Settings;
|
||||||
|
|
||||||
|
using Stone_Red_Utilities.StringExtentions;
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@@ -26,12 +28,12 @@ namespace DesktopMagic
|
|||||||
|
|
||||||
private readonly MainWindowDataContext mainWindowDataContext = new();
|
private readonly MainWindowDataContext mainWindowDataContext = new();
|
||||||
|
|
||||||
private readonly Dictionary<string, Type> builtInPlugins = new()
|
private readonly Dictionary<PluginMetadata, Type> builtInPlugins = new()
|
||||||
{
|
{
|
||||||
{"Music Visualizer", typeof(MusicVisualizerPlugin)},
|
{new("Music Visualizer", 1), typeof(MusicVisualizerPlugin)},
|
||||||
{"Time", typeof(TimePlugin)},
|
{new("Time",2), typeof(TimePlugin)},
|
||||||
{"Date", typeof(DatePlugin)},
|
{new("Date",3), typeof(DatePlugin)},
|
||||||
{"Cpu Usage", typeof(CpuMonitorPlugin)}
|
{new("Cpu Usage", 4), typeof(CpuMonitorPlugin)}
|
||||||
};
|
};
|
||||||
|
|
||||||
private bool loaded = false;
|
private bool loaded = false;
|
||||||
@@ -76,7 +78,7 @@ namespace DesktopMagic
|
|||||||
|
|
||||||
#region Load
|
#region Load
|
||||||
|
|
||||||
private readonly List<string> pluginNames = [];
|
private readonly Dictionary<uint, InternalPluginData> plugins = [];
|
||||||
|
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -109,44 +111,41 @@ namespace DesktopMagic
|
|||||||
|
|
||||||
private void LoadPlugins()
|
private void LoadPlugins()
|
||||||
{
|
{
|
||||||
pluginNames.Clear();
|
plugins.Clear();
|
||||||
|
|
||||||
pluginNames.AddRange(builtInPlugins.Keys);
|
foreach (var buildInPlugin in builtInPlugins.Keys)
|
||||||
|
{
|
||||||
|
plugins.Add(buildInPlugin.Id, new(buildInPlugin, string.Empty));
|
||||||
|
}
|
||||||
|
|
||||||
string pluginsPath = App.ApplicationDataPath + "\\Plugins";
|
string pluginsPath = App.ApplicationDataPath + "\\Plugins";
|
||||||
|
|
||||||
foreach (string fileName in Directory.GetFiles(pluginsPath, "*.dll"))
|
|
||||||
{
|
|
||||||
string pluginName = fileName[(fileName.LastIndexOf('\\') + 1)..].Replace(fileName[fileName.LastIndexOf('.')..], "");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_ = Directory.CreateDirectory(Path.Combine(pluginsPath, pluginName));
|
|
||||||
File.Move(fileName, $"{pluginsPath}\\{pluginName}\\{pluginName}.dll");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
App.Logger.Log(ex.Message, "Main", LogSeverity.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (string directory in Directory.GetDirectories(pluginsPath))
|
foreach (string directory in Directory.GetDirectories(pluginsPath))
|
||||||
{
|
{
|
||||||
foreach (string fileName in Directory.GetFiles(directory).Where(s => s.EndsWith(".dll", StringComparison.InvariantCulture)))
|
string? pluginDllPath = Directory.GetFiles(directory, "main.dll").FirstOrDefault();
|
||||||
|
string? pluginMetadataPath = Directory.GetFiles(directory, "metadata.json").FirstOrDefault();
|
||||||
|
|
||||||
|
if (pluginDllPath is null)
|
||||||
{
|
{
|
||||||
string badChars = ",#-<>?!=()*,. ";
|
App.Logger.Log($"Plugin \"{directory}\" has no \"main.dll\"", "Main", LogSeverity.Error);
|
||||||
string pluginName = fileName[(fileName.LastIndexOf('\\') + 1)..].Replace(fileName[fileName.LastIndexOf('.')..], "");
|
continue;
|
||||||
string clearPluginName = pluginName;
|
|
||||||
|
|
||||||
if (pluginName == directory[(directory.LastIndexOf('\\') + 1)..])
|
|
||||||
{
|
|
||||||
foreach (char c in badChars)
|
|
||||||
{
|
|
||||||
clearPluginName = clearPluginName.Replace(c, '_');
|
|
||||||
}
|
|
||||||
|
|
||||||
pluginNames.Add(pluginName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pluginMetadataPath is null)
|
||||||
|
{
|
||||||
|
App.Logger.Log($"Plugin \"{directory}\" has no \"metadata.json\"", "Main", LogSeverity.Warn);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginMetadata? pluginMetadata = JsonSerializer.Deserialize<PluginMetadata>(File.ReadAllText(pluginMetadataPath));
|
||||||
|
|
||||||
|
if (pluginMetadata is null)
|
||||||
|
{
|
||||||
|
App.Logger.Log($"Plugin \"{directory}\" has no valid \"metadata.json\"", "Main", LogSeverity.Error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins.Add(pluginMetadata.Id, new(pluginMetadata, directory));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,31 +166,36 @@ namespace DesktopMagic
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadPlugin(checkBox.Content.ToString() ?? string.Empty);
|
LoadPlugin(uint.Parse(checkBox.Tag.ToString()!));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadPlugin(string pluginName)
|
private void LoadPlugin(uint pluginId)
|
||||||
{
|
{
|
||||||
if (!Settings.CurrentLayout.Plugins.TryGetValue(pluginName, out PluginSettings? pluginSettings))
|
if (!plugins.TryGetValue(pluginId, out InternalPluginData? internalPluginData))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Settings.CurrentLayout.Plugins.TryGetValue(pluginId, out PluginSettings? pluginSettings))
|
||||||
{
|
{
|
||||||
pluginSettings = new PluginSettings();
|
pluginSettings = new PluginSettings();
|
||||||
Settings.CurrentLayout.Plugins.Add(pluginName, pluginSettings);
|
Settings.CurrentLayout.Plugins.Add(pluginId, pluginSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginWindow window;
|
PluginWindow window;
|
||||||
|
|
||||||
if (builtInPlugins.TryGetValue(pluginName, out Type? pluginType))
|
if (builtInPlugins.TryGetValue(internalPluginData.Metadata, out Type? pluginType))
|
||||||
{
|
{
|
||||||
window = new PluginWindow((DesktopMagic.Api.Plugin)Activator.CreateInstance(pluginType)!, pluginName, pluginSettings)
|
window = new PluginWindow((Api.Plugin)Activator.CreateInstance(pluginType)!, internalPluginData.Metadata, pluginSettings)
|
||||||
{
|
{
|
||||||
Title = pluginName
|
Title = internalPluginData.Metadata.Name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
window = new PluginWindow(pluginName, pluginSettings)
|
window = new PluginWindow(internalPluginData.Metadata, pluginSettings, internalPluginData.DirectoryPath)
|
||||||
{
|
{
|
||||||
Title = pluginName
|
Title = internalPluginData.Metadata.Name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,12 +212,12 @@ namespace DesktopMagic
|
|||||||
{
|
{
|
||||||
Dispatcher.Invoke(() =>
|
Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
if (!optionsComboBox.Items.Contains(pluginName))
|
if (!optionsComboBox.Items.Contains(internalPluginData.Metadata))
|
||||||
{
|
{
|
||||||
_ = optionsComboBox.Items.Add(pluginName);
|
_ = optionsComboBox.Items.Add(internalPluginData.Metadata);
|
||||||
}
|
}
|
||||||
optionsComboBox.SelectedIndex = -1;
|
optionsComboBox.SelectedIndex = -1;
|
||||||
optionsComboBox.SelectedIndex = optionsComboBox.Items.IndexOf(pluginName);
|
optionsComboBox.SelectedIndex = optionsComboBox.Items.IndexOf(internalPluginData.Metadata);
|
||||||
window.PluginLoaded -= onPluginLoaded;
|
window.PluginLoaded -= onPluginLoaded;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -326,7 +330,7 @@ namespace DesktopMagic
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = Settings.CurrentLayout.Plugins.TryGetValue(optionsComboBox.SelectedItem.ToString()!, out Settings.PluginSettings? pluginSettings);
|
bool success = Settings.CurrentLayout.Plugins.TryGetValue(((PluginMetadata)optionsComboBox.SelectedItem).Id, out Settings.PluginSettings? pluginSettings);
|
||||||
if (!success || pluginSettings is null || pluginSettings.Settings.Count == 0)
|
if (!success || pluginSettings is null || pluginSettings.Settings.Count == 0)
|
||||||
{
|
{
|
||||||
_ = optionsPanel.Children.Add(new TextBlock() { Text = (string)FindResource("noOptions") });
|
_ = optionsPanel.Children.Add(new TextBlock() { Text = (string)FindResource("noOptions") });
|
||||||
@@ -561,19 +565,22 @@ namespace DesktopMagic
|
|||||||
bool showWindow = true;
|
bool showWindow = true;
|
||||||
|
|
||||||
// Load plugins
|
// Load plugins
|
||||||
foreach (string pluginName in pluginNames)
|
foreach (uint pluginId in plugins.Keys)
|
||||||
{
|
{
|
||||||
// Add plugin to layout if it doesn't exist
|
// Add plugin to layout if it doesn't exist
|
||||||
if (!Settings.CurrentLayout.Plugins.TryGetValue(pluginName, out PluginSettings? pluginSettings))
|
if (!Settings.CurrentLayout.Plugins.TryGetValue(pluginId, out PluginSettings? pluginSettings))
|
||||||
{
|
{
|
||||||
Settings.CurrentLayout.Plugins.Add(pluginName, new PluginSettings());
|
Settings.CurrentLayout.Plugins.Add(pluginId, new PluginSettings());
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InternalPluginData internalPluginData = plugins[pluginId];
|
||||||
|
pluginSettings.Name = internalPluginData.Metadata.Name;
|
||||||
|
|
||||||
if (pluginSettings.Enabled)
|
if (pluginSettings.Enabled)
|
||||||
{
|
{
|
||||||
LoadPlugin(pluginName);
|
LoadPlugin(pluginId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showWindow && pluginSettings.Enabled)
|
if (showWindow && pluginSettings.Enabled)
|
||||||
@@ -583,11 +590,11 @@ namespace DesktopMagic
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove plugins that are not loaded anymore
|
// Remove plugins that are not loaded anymore
|
||||||
foreach (string pluginName in Settings.CurrentLayout.Plugins.Keys)
|
foreach (uint pluginId in Settings.CurrentLayout.Plugins.Keys)
|
||||||
{
|
{
|
||||||
if (!pluginNames.Contains(pluginName))
|
if (!plugins.ContainsKey(pluginId))
|
||||||
{
|
{
|
||||||
Settings.CurrentLayout.Plugins.Remove(pluginName);
|
Settings.CurrentLayout.Plugins.Remove(pluginId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,6 +653,7 @@ namespace DesktopMagic
|
|||||||
PluginManager pluginManager = new PluginManager();
|
PluginManager pluginManager = new PluginManager();
|
||||||
pluginManager.ShowDialog();
|
pluginManager.ShowDialog();
|
||||||
LoadPlugins();
|
LoadPlugins();
|
||||||
|
LoadLayout(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetLanguageDictionary()
|
private void SetLanguageDictionary()
|
||||||
@@ -664,4 +672,10 @@ namespace DesktopMagic
|
|||||||
Resources.MergedDictionaries.Add(dict);
|
Resources.MergedDictionaries.Add(dict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class InternalPluginData(PluginMetadata pluginMetadata, string directoryPath)
|
||||||
|
{
|
||||||
|
public PluginMetadata Metadata { get; set; } = pluginMetadata;
|
||||||
|
public string DirectoryPath { get; set; } = directoryPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,36 +6,37 @@
|
|||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:local="clr-namespace:DesktopMagic.Plugins"
|
xmlns:local="clr-namespace:DesktopMagic.Plugins"
|
||||||
xmlns:dataContext="clr-namespace:DesktopMagic.DataContexts"
|
xmlns:dataContext="clr-namespace:DesktopMagic.DataContexts"
|
||||||
d:DataContext="{d:DesignInstance Type=dataContext:ModEntryDataContext}"
|
d:DataContext="{d:DesignInstance Type=dataContext:PluginEntryDataContext}"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
Background="{DynamicResource MaterialDesignPaper}"
|
Background="{DynamicResource MaterialDesignPaper}"
|
||||||
FontFamily="{DynamicResource MaterialDesignFont}">
|
FontFamily="{DynamicResource MaterialDesignFont}">
|
||||||
<Grid Background="White" Margin="10">
|
<Grid Background="White" Margin="10">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition/>
|
<RowDefinition />
|
||||||
<RowDefinition/>
|
<RowDefinition />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="auto"/>
|
<ColumnDefinition Width="auto" />
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Border HorizontalAlignment="Left" Width="100" Height="100" BorderThickness="1" BorderBrush="LightGray">
|
<Border HorizontalAlignment="Left" Width="100" Height="100" BorderThickness="1" BorderBrush="LightGray">
|
||||||
<Image Source="{Binding Logo}" Width="100" Height="100"/>
|
<Image Source="{Binding Logo}" Width="100" Height="100" />
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="1" HorizontalAlignment="Stretch">
|
<StackPanel Grid.Column="1" HorizontalAlignment="Stretch">
|
||||||
<Label Content="{Binding FormattedDateAdded}" HorizontalAlignment="Center" ContentStringFormat="Added: {0}"/>
|
<Label Content="{Binding FormattedDateAdded}" HorizontalAlignment="Center" ContentStringFormat="Added: {0}" />
|
||||||
<Label Content="{Binding FormattedDateUpdated}" HorizontalAlignment="Center" ContentStringFormat="Updated: {0}"/>
|
<Label Content="{Binding FormattedDateUpdated}" HorizontalAlignment="Center" ContentStringFormat="Updated: {0}" />
|
||||||
<Button Command="{Binding InstallCommand}" HorizontalAlignment="Stretch" Margin="10" Content="Install"/>
|
|
||||||
|
<Button Command="{Binding Command}" Visibility="{Binding InstallButtonVisibility}" HorizontalAlignment="Stretch" Margin="10" Content="Install" />
|
||||||
|
<Button Command="{Binding Command}" Visibility="{Binding RemoveButtonVisibility}" HorizontalAlignment="Stretch" Margin="10" Content="Remove" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Grid.Row="1" Grid.ColumnSpan="2">
|
<StackPanel Grid.Row="1" Grid.ColumnSpan="2">
|
||||||
<Label Content="{Binding Name}" FontSize="20"/>
|
<Label Content="{Binding Name}" FontSize="20" />
|
||||||
<Label Content="{Binding Description}"/>
|
<Label Content="{Binding Description}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@@ -15,7 +15,7 @@ internal class PluginData(PluginWindow window, PluginSettings pluginSettings) :
|
|||||||
|
|
||||||
public Point WindowPosition => new Point((int)window.Left, (int)window.Top);
|
public Point WindowPosition => new Point((int)window.Left, (int)window.Top);
|
||||||
|
|
||||||
public string PluginName => window.PluginName;
|
public string PluginName => window.PluginMetadata.Name;
|
||||||
|
|
||||||
public string PluginPath => window.PluginFolderPath;
|
public string PluginPath => window.PluginFolderPath;
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:busyIndicator="https://github.com/moh3ngolshani/BusyIndicator"
|
||||||
xmlns:local="clr-namespace:DesktopMagic.Plugins"
|
xmlns:local="clr-namespace:DesktopMagic.Plugins"
|
||||||
xmlns:dataContexts="clr-namespace:DesktopMagic.DataContexts"
|
xmlns:dataContexts="clr-namespace:DesktopMagic.DataContexts"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
@@ -13,45 +14,49 @@
|
|||||||
Width="800"
|
Width="800"
|
||||||
MinHeight="520"
|
MinHeight="520"
|
||||||
MinWidth="700"
|
MinWidth="700"
|
||||||
|
WindowStyle="ToolWindow"
|
||||||
Background="{DynamicResource MaterialDesignPaper}"
|
Background="{DynamicResource MaterialDesignPaper}"
|
||||||
FontFamily="{DynamicResource MaterialDesignFont}">
|
FontFamily="{DynamicResource MaterialDesignFont}">
|
||||||
<Grid Margin="5">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="auto"/>
|
|
||||||
<RowDefinition Height="auto"/>
|
|
||||||
<RowDefinition/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<Label Content="All plugins" FontSize="20"/>
|
<busyIndicator:BusyMask x:Name="BusyIndicator" IsBusy="{Binding IsLoading}" IndicatorType="Cogs" BusyContent="Please wait..." BusyContentMargin="0,20,0,0" IsBusyAtStartup="False">
|
||||||
|
<Grid Margin="5">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="auto" />
|
||||||
|
<RowDefinition Height="auto" />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<TextBox Grid.Row="1" materialDesign:HintAssist.Hint="Search..." materialDesign:TextFieldAssist.HasLeadingIcon="True" materialDesign:TextFieldAssist.LeadingIcon="Search"/>
|
<Label Content="All plugins" FontSize="20" />
|
||||||
|
|
||||||
<ItemsControl Grid.Row="2" ItemsSource="{Binding Mods}">
|
<TextBox Grid.Row="1" materialDesign:HintAssist.Hint="Search..." materialDesign:TextFieldAssist.HasLeadingIcon="True" materialDesign:TextFieldAssist.LeadingIcon="Search" />
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<Border BorderBrush="LightGray" BorderThickness="1">
|
|
||||||
<local:ModEntry/>
|
|
||||||
</Border>
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
|
|
||||||
<Label Grid.Column="1" Content="Installed plugins" FontSize="20"/>
|
<ItemsControl Grid.Row="2" ItemsSource="{Binding AllPlugins}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border BorderBrush="LightGray" BorderThickness="1">
|
||||||
|
<local:ModEntry />
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
|
||||||
<TextBox Grid.Row="1" Grid.Column="1" materialDesign:HintAssist.Hint="Search..." materialDesign:TextFieldAssist.HasLeadingIcon="True" materialDesign:TextFieldAssist.LeadingIcon="Search"/>
|
<Label Grid.Column="1" Content="Installed plugins" FontSize="20" />
|
||||||
|
|
||||||
<ItemsControl Grid.Row="2" Grid.Column="1" ItemsSource="{Binding Mods}">
|
<TextBox Grid.Row="1" Grid.Column="1" materialDesign:HintAssist.Hint="Search..." materialDesign:TextFieldAssist.HasLeadingIcon="True" materialDesign:TextFieldAssist.LeadingIcon="Search" />
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate>
|
<ItemsControl Grid.Row="2" Grid.Column="1" ItemsSource="{Binding InstalledPlugins}">
|
||||||
<Border BorderBrush="LightGray" BorderThickness="1">
|
<ItemsControl.ItemTemplate>
|
||||||
<local:ModEntry/>
|
<DataTemplate>
|
||||||
</Border>
|
<Border BorderBrush="LightGray" BorderThickness="1">
|
||||||
</DataTemplate>
|
<local:ModEntry />
|
||||||
</ItemsControl.ItemTemplate>
|
</Border>
|
||||||
</ItemsControl>
|
</DataTemplate>
|
||||||
</Grid>
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</Grid>
|
||||||
|
</busyIndicator:BusyMask>
|
||||||
</Window>
|
</Window>
|
||||||
@@ -6,17 +6,28 @@ using Modio.NET.Models;
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
|
using File = System.IO.File;
|
||||||
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
namespace DesktopMagic.Plugins;
|
namespace DesktopMagic.Plugins;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for PluginManager.xaml
|
/// Interaction logic for PluginManager.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class PluginManager : Window
|
public partial class PluginManager : Window
|
||||||
{
|
{
|
||||||
private readonly Client client = new Client(new Credentials("88e6ea774c3a502b06114e7fee0829ac"));
|
private readonly Client client = new Client(new Credentials("88e6ea774c3a502b06114e7fee0829ac"));
|
||||||
|
private readonly HttpClient httpClient = new();
|
||||||
|
|
||||||
private readonly PluginManagerDataContext pluginManagerDataContext = new();
|
private readonly PluginManagerDataContext pluginManagerDataContext = new();
|
||||||
private readonly string pluginsPath = Path.Combine(App.ApplicationDataPath, "Plugins");
|
private readonly string pluginsPath = Path.Combine(App.ApplicationDataPath, "Plugins");
|
||||||
@@ -28,19 +39,114 @@ public partial class PluginManager : Window
|
|||||||
DataContext = pluginManagerDataContext;
|
DataContext = pluginManagerDataContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Remove(string pluginPath, uint? id)
|
||||||
|
{
|
||||||
|
pluginManagerDataContext.IsLoading = true;
|
||||||
|
|
||||||
|
PluginEntryDataContext? pluginEntryDataContext = pluginManagerDataContext.InstalledPlugins.FirstOrDefault(p => p.Id == id);
|
||||||
|
|
||||||
|
if (pluginEntryDataContext is not null)
|
||||||
|
{
|
||||||
|
_ = pluginManagerDataContext.InstalledPlugins.Remove(pluginEntryDataContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Directory.Exists(pluginPath))
|
||||||
|
{
|
||||||
|
Directory.Delete(pluginPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginManagerDataContext.IsLoading = false;
|
||||||
|
}
|
||||||
|
|
||||||
protected override async void OnInitialized(EventArgs e)
|
protected override async void OnInitialized(EventArgs e)
|
||||||
{
|
{
|
||||||
base.OnInitialized(e);
|
base.OnInitialized(e);
|
||||||
|
|
||||||
IReadOnlyList<Mod> mods = await client.Games[5665].Mods.Search().ToListAsync();
|
HashSet<uint> pluginIds = [];
|
||||||
foreach (Mod mod in mods)
|
|
||||||
|
foreach (string pluginPath in Directory.GetDirectories(pluginsPath))
|
||||||
{
|
{
|
||||||
pluginManagerDataContext.Mods.Add(new ModEntryDataContext(mod, new CommandHandler(() => Install(mod))));
|
string pluginMetadataPath = Path.Combine(pluginPath, "metadata.json");
|
||||||
|
if (!File.Exists(pluginMetadataPath))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginMetadata? pluginMetadata = JsonSerializer.Deserialize<PluginMetadata>(File.ReadAllText(pluginMetadataPath));
|
||||||
|
|
||||||
|
if (pluginMetadata is not null)
|
||||||
|
{
|
||||||
|
pluginManagerDataContext.InstalledPlugins.Add(new PluginEntryDataContext(pluginMetadata, new CommandHandler(() => Remove(pluginPath, pluginMetadata.Id)), true));
|
||||||
|
_ = pluginIds.Add(pluginMetadata.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IAsyncEnumerable<Mod> mods = client.Games[5665].Mods.Search().ToEnumerableAsync();
|
||||||
|
await foreach (Mod mod in mods)
|
||||||
|
{
|
||||||
|
if (pluginIds.Contains(mod.Id))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginManagerDataContext.AllPlugins.Add(new PluginEntryDataContext(new(mod), new CommandHandler(async () => await Install(mod))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Install(Mod mod)
|
protected override void OnClosing(CancelEventArgs e)
|
||||||
{
|
{
|
||||||
|
e.Cancel = pluginManagerDataContext.IsLoading;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Install(Mod mod)
|
||||||
|
{
|
||||||
|
pluginManagerDataContext.IsLoading = true;
|
||||||
|
|
||||||
Debug.WriteLine(mod.Modfile?.Download?.BinaryUrl + " | " + pluginsPath);
|
Debug.WriteLine(mod.Modfile?.Download?.BinaryUrl + " | " + pluginsPath);
|
||||||
|
|
||||||
|
if (mod.Modfile?.Download?.BinaryUrl is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string pluginGuid = Guid.NewGuid().ToString();
|
||||||
|
string pluginPath = Path.Combine(pluginsPath, pluginGuid);
|
||||||
|
string zipFilePath = Path.Combine(pluginsPath, pluginGuid + ".zip");
|
||||||
|
|
||||||
|
using (Stream fileStream = await httpClient.GetStreamAsync(mod.Modfile.Download.BinaryUrl))
|
||||||
|
{
|
||||||
|
using FileStream outputFileStream = new FileStream(zipFilePath, FileMode.Create);
|
||||||
|
|
||||||
|
await fileStream.CopyToAsync(outputFileStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (ZipArchive zipArchive = ZipFile.OpenRead(zipFilePath))
|
||||||
|
{
|
||||||
|
zipArchive.ExtractToDirectory(pluginPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string pluginMetadataPath = Path.Combine(pluginPath, "metadata.json");
|
||||||
|
File.WriteAllText(pluginMetadataPath, JsonSerializer.Serialize(new PluginMetadata(mod)));
|
||||||
|
|
||||||
|
File.Delete(zipFilePath);
|
||||||
|
|
||||||
|
if (!File.Exists(Path.Combine(pluginPath, "main.dll")))
|
||||||
|
{
|
||||||
|
Remove(pluginPath, mod.Id);
|
||||||
|
pluginManagerDataContext.IsLoading = false;
|
||||||
|
_ = MessageBox.Show("The plugin you are trying to install does not contain a \"main.dll\" file. Please contact the plugin author.", "Plugin Manager", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginEntryDataContext? pluginEntryDataContext = pluginManagerDataContext.AllPlugins.FirstOrDefault(p => p.Id == mod.Id);
|
||||||
|
|
||||||
|
if (pluginEntryDataContext is not null)
|
||||||
|
{
|
||||||
|
_ = pluginManagerDataContext.AllPlugins.Remove(pluginEntryDataContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginManagerDataContext.InstalledPlugins.Add(new PluginEntryDataContext(new PluginMetadata(mod), new CommandHandler(() => Remove(pluginPath, mod.Id)), true));
|
||||||
|
|
||||||
|
pluginManagerDataContext.IsLoading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using Modio.NET.Models;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace DesktopMagic.Plugins;
|
||||||
|
|
||||||
|
public class PluginMetadata
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public uint Id { get; set; }
|
||||||
|
|
||||||
|
public string? Author { get; set; }
|
||||||
|
|
||||||
|
public Uri? IconUri { get; set; }
|
||||||
|
|
||||||
|
public DateTime? Added { get; set; }
|
||||||
|
|
||||||
|
public DateTime? Updated { get; set; }
|
||||||
|
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
public string? Version { get; set; }
|
||||||
|
|
||||||
|
public PluginMetadata(Mod mod)
|
||||||
|
{
|
||||||
|
Name = mod.Name ?? mod.Id.ToString();
|
||||||
|
Id = mod.Id;
|
||||||
|
Author = mod.SubmittedBy?.Username;
|
||||||
|
IconUri = mod.Logo?.Thumb320x180;
|
||||||
|
Added = DateTimeOffset.FromUnixTimeSeconds(mod.DateAdded).DateTime;
|
||||||
|
Updated = DateTimeOffset.FromUnixTimeSeconds(mod.DateUpdated).DateTime;
|
||||||
|
Description = mod.DescriptionPlaintext;
|
||||||
|
Version = mod.Modfile?.Version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PluginMetadata(string name, uint id)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonConstructor]
|
||||||
|
public PluginMetadata()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (obj is not PluginMetadata other)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Id == other.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Id.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,10 +34,10 @@ public partial class PluginWindow : Window
|
|||||||
private Plugin? pluginClassInstance;
|
private Plugin? pluginClassInstance;
|
||||||
|
|
||||||
public bool IsRunning { get; private set; } = true;
|
public bool IsRunning { get; private set; } = true;
|
||||||
public string PluginName { get; private set; }
|
public PluginMetadata PluginMetadata { get; private set; }
|
||||||
public string? PluginFolderPath { get; private set; }
|
public string? PluginFolderPath { get; private set; }
|
||||||
|
|
||||||
public PluginWindow(string pluginName, PluginSettings settings)
|
public PluginWindow(PluginMetadata pluginMetadata, PluginSettings settings, string pluginFolderPath)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
@@ -62,16 +62,18 @@ public partial class PluginWindow : Window
|
|||||||
t.Elapsed += UpdateTimer_Elapsed;
|
t.Elapsed += UpdateTimer_Elapsed;
|
||||||
t.Start();
|
t.Start();
|
||||||
|
|
||||||
PluginName = pluginName;
|
PluginMetadata = pluginMetadata;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
|
|
||||||
Left = settings.Position.X;
|
Left = settings.Position.X;
|
||||||
Top = settings.Position.Y;
|
Top = settings.Position.Y;
|
||||||
Width = settings.Size.X;
|
Width = settings.Size.X;
|
||||||
Height = settings.Size.Y;
|
Height = settings.Size.Y;
|
||||||
|
|
||||||
|
PluginFolderPath = pluginFolderPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluginWindow(Plugin pluginClassInstance, string pluginName, Settings.PluginSettings settings) : this(pluginName, settings)
|
public PluginWindow(Plugin pluginClassInstance, PluginMetadata pluginMetadata, PluginSettings settings) : this(pluginMetadata, settings, string.Empty)
|
||||||
{
|
{
|
||||||
this.pluginClassInstance = pluginClassInstance;
|
this.pluginClassInstance = pluginClassInstance;
|
||||||
}
|
}
|
||||||
@@ -119,7 +121,7 @@ public partial class PluginWindow : Window
|
|||||||
|
|
||||||
private void Window_ContentRendered(object? sender, EventArgs e)
|
private void Window_ContentRendered(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
App.Logger.Log($"\"{PluginName}\" - Starting plugin thread", "Plugin");
|
App.Logger.Log($"\"{PluginMetadata}\" - Starting plugin thread", "Plugin");
|
||||||
pluginThread = new Thread(LoadPlugin);
|
pluginThread = new Thread(LoadPlugin);
|
||||||
pluginThread.Start();
|
pluginThread.Start();
|
||||||
}
|
}
|
||||||
@@ -165,20 +167,15 @@ public partial class PluginWindow : Window
|
|||||||
|
|
||||||
private void LoadPlugin()
|
private void LoadPlugin()
|
||||||
{
|
{
|
||||||
App.Logger.Log($"\"{PluginName}\" - Loading plugin", "Plugin");
|
App.Logger.Log($"\"{PluginMetadata}\" - Loading plugin", "Plugin");
|
||||||
|
|
||||||
if (pluginClassInstance is null)
|
if (pluginClassInstance is null && !File.Exists($"{PluginFolderPath}\\main.dll"))
|
||||||
{
|
{
|
||||||
PluginFolderPath = $"{App.ApplicationDataPath}\\Plugins\\{PluginName}";
|
App.Logger.Log($"\"{PluginMetadata}\" - File \"main.dll\" does not exist", "Plugin", LogSeverity.Error);
|
||||||
|
_ = MessageBox.Show("File \"main.dll\" does not exist!", $"Error \"{PluginMetadata}\"", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
|
||||||
if (!File.Exists($"{PluginFolderPath}\\{PluginName}.dll"))
|
Exit();
|
||||||
{
|
return;
|
||||||
App.Logger.Log($"\"{PluginName}\" - File does not exist", "Plugin", LogSeverity.Error);
|
|
||||||
_ = MessageBox.Show("File does not exist!", $"Error \"{PluginName}\"", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
|
|
||||||
Exit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -187,8 +184,8 @@ public partial class PluginWindow : Window
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
App.Logger.Log($"\"{PluginName}\" - {ex}", "Plugin", LogSeverity.Error);
|
App.Logger.Log($"\"{PluginMetadata}\" - {ex}", "Plugin", LogSeverity.Error);
|
||||||
_ = MessageBox.Show("File execution error:\n" + ex, $"Error \"{PluginName}\"", MessageBoxButton.OK, MessageBoxImage.Error);
|
_ = MessageBox.Show("File execution error:\n" + ex, $"Error \"{PluginMetadata}\"", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
Exit();
|
Exit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -200,14 +197,14 @@ public partial class PluginWindow : Window
|
|||||||
object? instance = pluginClassInstance;
|
object? instance = pluginClassInstance;
|
||||||
if (instance is null)
|
if (instance is null)
|
||||||
{
|
{
|
||||||
byte[] assemblyBytes = File.ReadAllBytes($"{PluginFolderPath}\\{PluginName}.dll");
|
byte[] assemblyBytes = File.ReadAllBytes($"{PluginFolderPath}\\main.dll");
|
||||||
Assembly dll = Assembly.Load(assemblyBytes);
|
Assembly dll = Assembly.Load(assemblyBytes);
|
||||||
Type? instanceType = Array.Find(dll.GetTypes(), type => type.GetTypeInfo().BaseType == typeof(Plugin));
|
Type? instanceType = Array.Find(dll.GetTypes(), type => type.GetTypeInfo().BaseType == typeof(Plugin));
|
||||||
|
|
||||||
if (instanceType is null)
|
if (instanceType is null)
|
||||||
{
|
{
|
||||||
App.Logger.Log($"\"{PluginName}\" - The \"Plugin\" class could not be found! It has to inherit from \"{typeof(Plugin).FullName}\"", "Plugin", LogSeverity.Error);
|
App.Logger.Log($"\"{PluginMetadata}\" - The \"Plugin\" class could not be found! It has to inherit from \"{typeof(Plugin).FullName}\"", "Plugin", LogSeverity.Error);
|
||||||
_ = MessageBox.Show($"The \"Plugin\" class could not be found! It has to inherit from \"{typeof(Plugin).FullName}\"", $"Error \"{PluginName}\"", MessageBoxButton.OK, MessageBoxImage.Error);
|
_ = MessageBox.Show($"The \"Plugin\" class could not be found! It has to inherit from \"{typeof(Plugin).FullName}\"", $"Error \"{PluginMetadata}\"", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
|
||||||
Exit();
|
Exit();
|
||||||
return;
|
return;
|
||||||
@@ -222,8 +219,8 @@ public partial class PluginWindow : Window
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
App.Logger.Log($"\"{PluginName}\" - The \"Plugin\" class could not be found! It has to inherit from \"{typeof(Plugin).FullName}\"", "Plugin", LogSeverity.Error);
|
App.Logger.Log($"\"{PluginMetadata}\" - The \"Plugin\" class could not be found! It has to inherit from \"{typeof(Plugin).FullName}\"", "Plugin", LogSeverity.Error);
|
||||||
_ = MessageBox.Show($"The \"Plugin\" class has to inherit from \"{typeof(Plugin).FullName}\"", $"Error \"{PluginName}\"", MessageBoxButton.OK, MessageBoxImage.Error);
|
_ = MessageBox.Show($"The \"Plugin\" class has to inherit from \"{typeof(Plugin).FullName}\"", $"Error \"{PluginMetadata}\"", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
Exit();
|
Exit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -283,7 +280,7 @@ public partial class PluginWindow : Window
|
|||||||
|
|
||||||
private void LoadOptions(object instance)
|
private void LoadOptions(object instance)
|
||||||
{
|
{
|
||||||
App.Logger.Log($"\"{PluginName}\" - Loading plugin options", "Plugin");
|
App.Logger.Log($"\"{PluginMetadata}\" - Loading plugin options", "Plugin");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -321,8 +318,8 @@ public partial class PluginWindow : Window
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
App.Logger.Log($"\"{PluginName}\" - {ex}", "Plugin", LogSeverity.Error);
|
App.Logger.Log($"\"{PluginMetadata}\" - {ex}", "Plugin", LogSeverity.Error);
|
||||||
_ = MessageBox.Show("File execution error:\n" + ex, $"Error \"{PluginName}\"", MessageBoxButton.OK, MessageBoxImage.Error);
|
_ = MessageBox.Show("File execution error:\n" + ex, $"Error \"{PluginMetadata}\"", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
Exit();
|
Exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -366,8 +363,8 @@ public partial class PluginWindow : Window
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
App.Logger.Log($"\"{PluginName}\" - {ex}", "Plugin", LogSeverity.Error);
|
App.Logger.Log($"\"{PluginMetadata}\" - {ex}", "Plugin", LogSeverity.Error);
|
||||||
_ = MessageBox.Show("File execution error:\n" + ex, $"Error \"{PluginName}\"", MessageBoxButton.OK, MessageBoxImage.Error);
|
_ = MessageBox.Show("File execution error:\n" + ex, $"Error \"{PluginMetadata}\"", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
Exit();
|
Exit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -380,7 +377,7 @@ public partial class PluginWindow : Window
|
|||||||
|
|
||||||
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||||
{
|
{
|
||||||
App.Logger.Log($"\"{PluginName}\" - Stopping plugin", "Plugin");
|
App.Logger.Log($"\"{PluginMetadata}\" - Stopping plugin", "Plugin");
|
||||||
pluginClassInstance?.Stop();
|
pluginClassInstance?.Stop();
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,7 @@ public class SettingElement
|
|||||||
|
|
||||||
[JsonConstructor]
|
[JsonConstructor]
|
||||||
private SettingElement()
|
private SettingElement()
|
||||||
|
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ internal class Layout(string name) : INotifyPropertyChanged
|
|||||||
|
|
||||||
private string name = name;
|
private string name = name;
|
||||||
private Theme theme = new Theme();
|
private Theme theme = new Theme();
|
||||||
private Dictionary<string, PluginSettings> plugins = [];
|
private Dictionary<uint, PluginSettings> plugins = [];
|
||||||
|
|
||||||
public Theme Theme
|
public Theme Theme
|
||||||
{
|
{
|
||||||
@@ -25,7 +25,7 @@ internal class Layout(string name) : INotifyPropertyChanged
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, PluginSettings> Plugins
|
public Dictionary<uint, PluginSettings> Plugins
|
||||||
{
|
{
|
||||||
get => plugins;
|
get => plugins;
|
||||||
set
|
set
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ public class PluginSettings : INotifyPropertyChanged
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public Theme Theme => theme is null ? MainWindowDataContext.GetSettings().CurrentLayout.Theme : theme;
|
public Theme Theme => theme is null ? MainWindowDataContext.GetSettings().CurrentLayout.Theme : theme;
|
||||||
|
|
||||||
|
// Only for internal use to show the name of the plugin in the main window
|
||||||
|
[JsonIgnore]
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
public List<SettingElement> Settings
|
public List<SettingElement> Settings
|
||||||
{
|
{
|
||||||
get => settings;
|
get => settings;
|
||||||
|
|||||||
Reference in New Issue
Block a user